namespace YMhut.Box.Core.App;

public sealed record InstallManifestRelease(
    string Version,
    string Build,
    string Channel,
    string PackageVersion);

public sealed record InstallManifest(
    InstallManifestRelease? Release,
    IReadOnlyList<string> RequiredFiles,
    IReadOnlyList<string> Files)
{
    public const string RelativePath = "config/install-manifest.ini";

    public static InstallManifest Parse(string text)
    {
        var release = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase);
        var requiredFiles = new List<string>();
        var files = new List<string>();
        var section = string.Empty;

        using var reader = new StringReader(text);
        while (reader.ReadLine() is { } line)
        {
            var value = line.Trim();
            if (string.IsNullOrWhiteSpace(value) || value.StartsWith(';') || value.StartsWith('#'))
            {
                continue;
            }

            if (value.StartsWith('[') && value.EndsWith(']'))
            {
                section = value[1..^1].Trim();
                continue;
            }

            if (section.Equals("Release", StringComparison.OrdinalIgnoreCase))
            {
                var separator = value.IndexOf('=');
                if (separator <= 0)
                {
                    continue;
                }

                release[value[..separator].Trim()] = value[(separator + 1)..].Trim();
                continue;
            }

            if (section.Equals("RequiredFiles", StringComparison.OrdinalIgnoreCase))
            {
                requiredFiles.Add(NormalizeManifestPath(value));
                continue;
            }

            if (section.Equals("Files", StringComparison.OrdinalIgnoreCase))
            {
                files.Add(NormalizeManifestPath(value));
            }
        }

        InstallManifestRelease? releaseInfo = null;
        if (release.Count > 0)
        {
            releaseInfo = new InstallManifestRelease(
                GetReleaseValue(release, "Version"),
                GetReleaseValue(release, "Build"),
                GetReleaseValue(release, "Channel"),
                GetReleaseValue(release, "PackageVersion"));
        }

        return new InstallManifest(releaseInfo, requiredFiles, files);
    }

    public static async Task<InstallManifest> ReadAsync(string installRoot, CancellationToken cancellationToken = default)
    {
        var path = Path.Combine(installRoot, RelativePath.Replace('/', Path.DirectorySeparatorChar));
        var text = await File.ReadAllTextAsync(path, cancellationToken).ConfigureAwait(false);
        return Parse(text);
    }

    public bool ContainsFile(string relativePath)
    {
        var normalized = NormalizeManifestPath(relativePath);
        return Files.Contains(normalized, StringComparer.OrdinalIgnoreCase) ||
            RequiredFiles.Contains(normalized, StringComparer.OrdinalIgnoreCase);
    }

    private static string GetReleaseValue(IReadOnlyDictionary<string, string> release, string key)
        => release.TryGetValue(key, out var value) ? value : string.Empty;

    private static string NormalizeManifestPath(string path)
        => path.Trim().Replace('\\', '/').TrimStart('/');
}
