namespace YMhut.Box.Core.App;

public static class InstallLayoutPaths
{
    public const string InstallRootEnvironmentVariable = "YMHUT_BOX_INSTALL_ROOT";
    public const string ArchivedLayoutEnvironmentVariable = "YMHUT_BOX_ARCHIVED_LAYOUT";

    public static string ResolveInstallRoot(string? baseDirectory = null)
    {
        return ResolveInstallRootContext(baseDirectory).InstallRoot;
    }

    public static InstallRootContext ResolveInstallRootContext(string? baseDirectory = null)
    {
        var selected = SelectInstallRoot(baseDirectory);
        var installRoot = selected.Path;
        var assetsRoot = Path.Combine(installRoot, "Assets");
        if (!Directory.Exists(assetsRoot))
        {
            assetsRoot = CandidateRoots(baseDirectory)
                .Select(candidate => Path.Combine(candidate, "Assets"))
                .FirstOrDefault(Directory.Exists)
                ?? Path.Combine(installRoot, "Assets");
        }

        var manifestPath = Path.Combine(installRoot, InstallManifest.RelativePath.Replace('/', Path.DirectorySeparatorChar));
        var manifestIdentity = InstallRootContext.BuildManifestIdentity(installRoot);
        return new InstallRootContext(
            installRoot,
            assetsRoot,
            manifestPath,
            manifestIdentity,
            IsPackagedInstallPath(installRoot),
            selected.Source);
    }

    public static string ResolveInstalledExecutablePath(string? baseDirectory = null)
    {
        var processPath = Environment.ProcessPath;
        if (!string.IsNullOrWhiteSpace(processPath) &&
            string.Equals(Path.GetFileName(processPath), "YMhutBox.exe", StringComparison.OrdinalIgnoreCase) &&
            File.Exists(processPath))
        {
            return processPath;
        }

        foreach (var root in CandidateRoots(baseDirectory))
        {
            var executable = Path.Combine(root, "YMhutBox.exe");
            if (File.Exists(executable))
            {
                return executable;
            }
        }

        return Environment.ProcessPath ?? Path.Combine(Path.GetFullPath(baseDirectory ?? AppContext.BaseDirectory), "YMhutBox.exe");
    }

    public static string ResolveAssetsRoot(string? baseDirectory = null)
    {
        return ResolveInstallRootContext(baseDirectory).AssetsRoot;
    }

    public static string? ResolveArchivedLayoutRoot()
        => NormalizeCandidate(Environment.GetEnvironmentVariable(ArchivedLayoutEnvironmentVariable));

    public static IEnumerable<string> CandidateRoots(string? baseDirectory = null)
    {
        var seen = new HashSet<string>(StringComparer.OrdinalIgnoreCase);
        foreach (var (candidate, _) in RawCandidates(baseDirectory))
        {
            var fullPath = NormalizeCandidate(candidate);
            if (fullPath is not null && seen.Add(fullPath))
            {
                yield return fullPath;
            }
        }
    }

    private static (string Path, string Source) SelectInstallRoot(string? baseDirectory)
    {
        var candidates = RawCandidates(baseDirectory)
            .Select(candidate => (Path: NormalizeCandidate(candidate.Path), candidate.Source))
            .Where(candidate => candidate.Path is not null)
            .Select(candidate => (Path: candidate.Path!, candidate.Source))
            .ToArray();

        foreach (var candidate in candidates)
        {
            if (LooksLikeInstallRoot(candidate.Path))
            {
                return candidate;
            }
        }

        var explicitRoot = NormalizeCandidate(Environment.GetEnvironmentVariable(InstallRootEnvironmentVariable));
        if (explicitRoot is not null && Directory.Exists(explicitRoot))
        {
            return (explicitRoot, "install-root-env");
        }

        var firstExisting = candidates.FirstOrDefault(candidate => Directory.Exists(candidate.Path));
        if (!string.IsNullOrWhiteSpace(firstExisting.Path))
        {
            return firstExisting;
        }

        return (Path.GetFullPath(baseDirectory ?? AppContext.BaseDirectory), "fallback");
    }

    private static IEnumerable<(string? Path, string Source)> RawCandidates(string? baseDirectory)
    {
        var processPath = Environment.ProcessPath;
        if (!string.IsNullOrWhiteSpace(processPath) &&
            string.Equals(Path.GetFileName(processPath), "YMhutBox.exe", StringComparison.OrdinalIgnoreCase))
        {
            yield return (Path.GetDirectoryName(processPath), "process");
        }

        yield return (Environment.GetEnvironmentVariable(InstallRootEnvironmentVariable), "install-root-env");
        yield return (baseDirectory, "base-directory");
        yield return (AppContext.BaseDirectory, "app-context");
    }

    private static string? NormalizeCandidate(string? candidate)
    {
        if (string.IsNullOrWhiteSpace(candidate))
        {
            return null;
        }

        try
        {
            return Path.GetFullPath(candidate.Trim())
                .TrimEnd(Path.DirectorySeparatorChar, Path.AltDirectorySeparatorChar);
        }
        catch
        {
            return null;
        }
    }

    private static bool LooksLikeInstallRoot(string root)
    {
        if (!Directory.Exists(root))
        {
            return false;
        }

        return File.Exists(Path.Combine(root, "YMhutBox.exe")) ||
            File.Exists(Path.Combine(root, "YMhutBox.dll")) ||
            File.Exists(Path.Combine(root, InstallManifest.RelativePath.Replace('/', Path.DirectorySeparatorChar)));
    }

    private static bool IsPackagedInstallPath(string root)
    {
        var normalized = root.Replace(Path.AltDirectorySeparatorChar, Path.DirectorySeparatorChar);
        return normalized.Contains($"{Path.DirectorySeparatorChar}WindowsApps{Path.DirectorySeparatorChar}", StringComparison.OrdinalIgnoreCase);
    }
}
