using System;
using System.IO;
using System.Linq;
using System.Text.Json;
using FluentAssertions;
using StellaOps.Feedser.Source.Cccs.Internal;
using StellaOps.Feedser.Source.Common.Html;
using Xunit;
using Xunit.Abstractions;

namespace StellaOps.Feedser.Source.Cccs.Tests.Internal;

public sealed class CccsHtmlParserTests
{
    private readonly ITestOutputHelper _output;
    private static readonly HtmlContentSanitizer Sanitizer = new();
    private static readonly CccsHtmlParser Parser = new(Sanitizer);

    public CccsHtmlParserTests(ITestOutputHelper output)
    {
        _output = output ?? throw new ArgumentNullException(nameof(output));
    }

    public static IEnumerable<object[]> ParserCases()
    {
        yield return new object[]
        {
            "cccs-raw-advisory.json",
            "TEST-001",
            "en",
            new[] { "Vendor Widget 1.0", "Vendor Widget 2.0" },
            new[]
            {
                "https://example.com/details",
                "https://www.cyber.gc.ca/en/contact-cyber-centre?lang=en"
            },
            new[] { "CVE-2020-1234", "CVE-2021-9999" }
        };

        yield return new object[]
        {
            "cccs-raw-advisory-fr.json",
            "TEST-002-FR",
            "fr",
            new[] { "Produit Exemple 3.1", "Produit Exemple 3.2", "Variante 3.2.1" },
            new[]
            {
                "https://exemple.ca/details",
                "https://www.cyber.gc.ca/fr/contact-centre-cyber"
            },
            new[] { "CVE-2024-1111" }
        };
    }

    [Theory]
    [MemberData(nameof(ParserCases))]
    public void Parse_ExtractsExpectedFields(
        string fixtureName,
        string expectedSerial,
        string expectedLanguage,
        string[] expectedProducts,
        string[] expectedReferenceUrls,
        string[] expectedCves)
    {
        var raw = LoadFixture<CccsRawAdvisoryDocument>(fixtureName);

        var dto = Parser.Parse(raw);

        _output.WriteLine("Products: {0}", string.Join("|", dto.Products));
        _output.WriteLine("References: {0}", string.Join("|", dto.References.Select(r => $"{r.Url} ({r.Label})")));
        _output.WriteLine("CVEs: {0}", string.Join("|", dto.CveIds));

        dto.SerialNumber.Should().Be(expectedSerial);
        dto.Language.Should().Be(expectedLanguage);
        dto.Products.Should().BeEquivalentTo(expectedProducts);
        foreach (var url in expectedReferenceUrls)
        {
            dto.References.Should().Contain(reference => reference.Url == url);
        }

        dto.CveIds.Should().BeEquivalentTo(expectedCves);
        dto.ContentHtml.Should().Contain("<ul>").And.Contain("<li>");
        dto.ContentHtml.Should().Contain("<h2", because: "heading structure must survive sanitisation for UI rendering");
    }

    internal static T LoadFixture<T>(string fileName)
    {
        var path = Path.Combine(AppContext.BaseDirectory, "Fixtures", fileName);
        var json = File.ReadAllText(path);
        return JsonSerializer.Deserialize<T>(json, new JsonSerializerOptions(JsonSerializerDefaults.Web))!;
    }
}
