using System;
using System.Collections.Generic;
using System.Linq;
using StellaOps.Feedser.Models;
using StellaOps.Feedser.Source.Ics.Cisa;
using StellaOps.Feedser.Source.Ics.Cisa.Internal;
using Xunit;

namespace StellaOps.Feedser.Source.Ics.Cisa.Tests.IcsCisa;

public class IcsCisaConnectorMappingTests
{
    private static readonly DateTimeOffset RecordedAt = new(2025, 10, 14, 12, 0, 0, TimeSpan.Zero);

    [Fact]
    public void BuildReferences_MergesFeedAndDetailAttachments()
    {
        var dto = new IcsCisaAdvisoryDto
        {
            AdvisoryId = "ICSA-25-123-01",
            Title = "Sample Advisory",
            Link = "https://www.cisa.gov/news-events/ics-advisories/icsa-25-123-01",
            Summary = "Summary",
            DescriptionHtml = "<p>Summary</p>",
            Published = RecordedAt,
            Updated = RecordedAt,
            IsMedical = false,
            References = new[]
            {
                "https://example.org/advisory",
                "https://www.cisa.gov/news-events/ics-advisories/icsa-25-123-01"
            },
            Attachments = new List<IcsCisaAttachmentDto>
            {
                new() { Title = "PDF Attachment", Url = "https://files.cisa.gov/docs/icsa-25-123-01.pdf" },
            }
        };

        var references = IcsCisaConnector.BuildReferences(dto, RecordedAt);

        Assert.Equal(3, references.Count);
        Assert.Contains(references, reference => reference.Kind == "attachment" && reference.Url == "https://files.cisa.gov/docs/icsa-25-123-01.pdf");
        Assert.Contains(references, reference => reference.Url == "https://example.org/advisory");
        Assert.Contains(references, reference => reference.Url == "https://www.cisa.gov/news-events/ics-advisories/icsa-25-123-01");
    }


    [Fact]
    public void BuildMitigationReferences_ProducesReferences()
    {
        var dto = new IcsCisaAdvisoryDto
        {
            AdvisoryId = "ICSA-25-999-01",
            Title = "Mitigation Test",
            Link = "https://www.cisa.gov/news-events/ics-advisories/icsa-25-999-01",
            Mitigations = new[] { "Apply firmware 9.9.1", "Limit network access" },
            Published = RecordedAt,
            Updated = RecordedAt,
            IsMedical = false,
        };

        var references = IcsCisaConnector.BuildMitigationReferences(dto, RecordedAt);

        Assert.Equal(2, references.Count);
        var first = references.First();
        Assert.Equal("mitigation", first.Kind);
        Assert.Equal("icscisa-mitigation", first.SourceTag);
        Assert.EndsWith("#mitigation-1", first.Url, StringComparison.Ordinal);
        Assert.Contains("Apply firmware", first.Summary);
    }

    [Fact]
    public void BuildAffectedPackages_EmitsProductRangesWithSemVer()
    {
        var dto = new IcsCisaAdvisoryDto
        {
            AdvisoryId = "ICSA-25-456-02",
            Title = "Vendor Advisory",
            Link = "https://www.cisa.gov/news-events/ics-advisories/icsa-25-456-02",
            DescriptionHtml = "",
            Summary = null,
            Published = RecordedAt,
            Vendors = new[] { "Example Corp" },
            Products = new[] { "ControlSuite 4.2" }
        };

        var packages = IcsCisaConnector.BuildAffectedPackages(dto, RecordedAt);

        var productPackage = Assert.Single(packages);
        Assert.Equal(AffectedPackageTypes.IcsVendor, productPackage.Type);
        Assert.Equal("ControlSuite", productPackage.Identifier);
        var range = Assert.Single(productPackage.VersionRanges);
        Assert.Equal("product", range.RangeKind);
        Assert.Equal("4.2", range.RangeExpression);
        Assert.NotNull(range.Primitives);
        Assert.Equal("Example Corp", range.Primitives!.VendorExtensions!["ics.vendors"]);
        Assert.Equal("ControlSuite", range.Primitives.VendorExtensions!["ics.product"]);
        Assert.NotNull(range.Primitives.SemVer);
        Assert.Equal("4.2.0", range.Primitives.SemVer!.ExactValue);
    }
}
