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

namespace StellaOps.Feedser.Source.CertFr.Internal;

internal static class CertFrParser
{
    private static readonly Regex AnchorRegex = new("<a[^>]+href=\"(?<url>https?://[^\"]+)\"", RegexOptions.IgnoreCase | RegexOptions.Compiled);
    private static readonly Regex ScriptRegex = new("<script[\\s\\S]*?</script>", RegexOptions.IgnoreCase | RegexOptions.Compiled);
    private static readonly Regex StyleRegex = new("<style[\\s\\S]*?</style>", RegexOptions.IgnoreCase | RegexOptions.Compiled);
    private static readonly Regex TagRegex = new("<[^>]+>", RegexOptions.Compiled);
    private static readonly Regex WhitespaceRegex = new("\\s+", RegexOptions.Compiled);

    public static CertFrDto Parse(string html, CertFrDocumentMetadata metadata)
    {
        ArgumentException.ThrowIfNullOrEmpty(html);
        ArgumentNullException.ThrowIfNull(metadata);

        var sanitized = SanitizeHtml(html);
        var summary = BuildSummary(metadata.Summary, sanitized);
        var references = ExtractReferences(html);

        return new CertFrDto(
            metadata.AdvisoryId,
            metadata.Title,
            metadata.DetailUri.ToString(),
            metadata.Published,
            summary,
            sanitized,
            references);
    }

    private static string SanitizeHtml(string html)
    {
        var withoutScripts = ScriptRegex.Replace(html, string.Empty);
        var withoutStyles = StyleRegex.Replace(withoutScripts, string.Empty);
        var withoutTags = TagRegex.Replace(withoutStyles, " ");
        var decoded = System.Net.WebUtility.HtmlDecode(withoutTags) ?? string.Empty;
        return WhitespaceRegex.Replace(decoded, " ").Trim();
    }

    private static string? BuildSummary(string? metadataSummary, string content)
    {
        if (!string.IsNullOrWhiteSpace(metadataSummary))
        {
            return metadataSummary.Trim();
        }

        if (string.IsNullOrWhiteSpace(content))
        {
            return null;
        }

        var sentences = content.Split(new[] { '.','!','?' }, StringSplitOptions.RemoveEmptyEntries | StringSplitOptions.TrimEntries);
        if (sentences.Length > 0)
        {
            return sentences[0].Trim();
        }

        return content.Length > 280 ? content[..280].Trim() : content;
    }

    private static IReadOnlyList<string> ExtractReferences(string html)
    {
        var references = new HashSet<string>(StringComparer.OrdinalIgnoreCase);
        foreach (Match match in AnchorRegex.Matches(html))
        {
            if (match.Success)
            {
                references.Add(match.Groups["url"].Value.Trim());
            }
        }

        return references.Count == 0
            ? Array.Empty<string>()
            : references.OrderBy(url => url, StringComparer.OrdinalIgnoreCase).ToArray();
    }
}
