using System;
using System.Collections.Generic;
using System.Globalization;
using System.Text.RegularExpressions;

namespace StellaOps.Feedser.Source.Distro.Debian.Internal;

internal static class DebianListParser
{
    private static readonly Regex HeaderRegex = new("^\\[(?<date>[^\\]]+)\\]\\s+(?<id>DSA-\\d{4,}-\\d+)\\s+(?<title>.+)$", RegexOptions.Compiled);
    private static readonly Regex CveRegex = new("CVE-\\d{4}-\\d{3,7}", RegexOptions.IgnoreCase | RegexOptions.Compiled);

    public static IReadOnlyList<DebianListEntry> Parse(string? content)
    {
        if (string.IsNullOrWhiteSpace(content))
        {
            return Array.Empty<DebianListEntry>();
        }

        var entries = new List<DebianListEntry>();
        var currentCves = new HashSet<string>(StringComparer.OrdinalIgnoreCase);
        DateTimeOffset currentDate = default;
        string? currentId = null;
        string? currentTitle = null;
        string? currentPackage = null;

        foreach (var rawLine in content.Split('\n'))
        {
            var line = rawLine.TrimEnd('\r');
            if (string.IsNullOrWhiteSpace(line))
            {
                continue;
            }

            if (line[0] == '[')
            {
                if (currentId is not null && currentTitle is not null && currentPackage is not null)
                {
                    entries.Add(new DebianListEntry(
                        currentId,
                        currentDate,
                        currentTitle,
                        currentPackage,
                        currentCves.Count == 0 ? Array.Empty<string>() : new List<string>(currentCves)));
                }

                currentCves.Clear();
                currentId = null;
                currentTitle = null;
                currentPackage = null;

                var match = HeaderRegex.Match(line);
                if (!match.Success)
                {
                    continue;
                }

                if (!DateTimeOffset.TryParseExact(
                        match.Groups["date"].Value,
                        new[] { "dd MMM yyyy", "d MMM yyyy" },
                        CultureInfo.InvariantCulture,
                        DateTimeStyles.AssumeUniversal | DateTimeStyles.AdjustToUniversal,
                        out currentDate))
                {
                    continue;
                }

                currentId = match.Groups["id"].Value.Trim();
                currentTitle = match.Groups["title"].Value.Trim();

                var separatorIndex = currentTitle.IndexOf(" - ", StringComparison.Ordinal);
                currentPackage = separatorIndex > 0
                    ? currentTitle[..separatorIndex].Trim()
                    : currentTitle.Split(' ', StringSplitOptions.RemoveEmptyEntries | StringSplitOptions.TrimEntries).FirstOrDefault();
                if (string.IsNullOrWhiteSpace(currentPackage))
                {
                    currentPackage = currentId;
                }

                continue;
            }

            if (line[0] == '{')
            {
                foreach (Match match in CveRegex.Matches(line))
                {
                    if (match.Success && !string.IsNullOrWhiteSpace(match.Value))
                    {
                        currentCves.Add(match.Value.ToUpperInvariant());
                    }
                }
            }
        }

        if (currentId is not null && currentTitle is not null && currentPackage is not null)
        {
            entries.Add(new DebianListEntry(
                currentId,
                currentDate,
                currentTitle,
                currentPackage,
                currentCves.Count == 0 ? Array.Empty<string>() : new List<string>(currentCves)));
        }

        return entries;
    }
}
