using System;
using System.Linq;
using StellaOps.Feedser.Models;
using StellaOps.Feedser.Source.Kev;
using StellaOps.Feedser.Source.Kev.Internal;
using Xunit;

namespace StellaOps.Feedser.Source.Kev.Tests;

public sealed class KevMapperTests
{
    [Fact]
    public void Map_BuildsVendorRangePrimitivesWithDueDate()
    {
        var catalog = new KevCatalogDto
        {
            CatalogVersion = "2025.10.09",
            DateReleased = new DateTimeOffset(2025, 10, 9, 16, 52, 28, TimeSpan.Zero),
            Vulnerabilities = new[]
            {
                new KevVulnerabilityDto
                {
                    CveId = "CVE-2021-43798",
                    VendorProject = "Grafana Labs",
                    Product = "Grafana",
                    VulnerabilityName = "Grafana Path Traversal Vulnerability",
                    DateAdded = "2025-10-09",
                    ShortDescription = "Grafana contains a path traversal vulnerability that could allow access to local files.",
                    RequiredAction = "Apply mitigations per vendor instructions or discontinue use.",
                    DueDate = "2025-10-30",
                    KnownRansomwareCampaignUse = "Unknown",
                    Notes = "https://grafana.com/security/advisory; https://nvd.nist.gov/vuln/detail/CVE-2021-43798",
                    Cwes = new[] { "CWE-22" }
                }
            }
        };

        var feedUri = new Uri("https://www.cisa.gov/sites/default/files/feeds/known_exploited_vulnerabilities.json");
        var fetchedAt = new DateTimeOffset(2025, 10, 9, 17, 0, 0, TimeSpan.Zero);
        var validatedAt = fetchedAt.AddMinutes(1);

        var advisories = KevMapper.Map(catalog, KevConnectorPlugin.SourceName, feedUri, fetchedAt, validatedAt);

        var advisory = Assert.Single(advisories);
        Assert.True(advisory.ExploitKnown);
        Assert.Contains("cve-2021-43798", advisory.Aliases, StringComparer.OrdinalIgnoreCase);

        var affected = Assert.Single(advisory.AffectedPackages);
        Assert.Equal(AffectedPackageTypes.Vendor, affected.Type);
        Assert.Equal("Grafana Labs::Grafana", affected.Identifier);

        Assert.Collection(
            affected.NormalizedVersions,
            rule =>
            {
                Assert.Equal("kev.catalog", rule.Scheme);
                Assert.Equal(NormalizedVersionRuleTypes.Exact, rule.Type);
                Assert.Equal("2025.10.09", rule.Value);
                Assert.Equal("Grafana Labs::Grafana", rule.Notes);
            },
            rule =>
            {
                Assert.Equal("kev.date-added", rule.Scheme);
                Assert.Equal(NormalizedVersionRuleTypes.Exact, rule.Type);
                Assert.Equal("2025-10-09", rule.Value);
            },
            rule =>
            {
                Assert.Equal("kev.due-date", rule.Scheme);
                Assert.Equal(NormalizedVersionRuleTypes.LessThanOrEqual, rule.Type);
                Assert.Equal("2025-10-30", rule.Max);
                Assert.True(rule.MaxInclusive);
            });

        var range = Assert.Single(affected.VersionRanges);
        Assert.Equal(AffectedPackageTypes.Vendor, range.RangeKind);
        var primitives = range.Primitives;
        Assert.NotNull(primitives);

        Assert.True(primitives!.HasVendorExtensions);
        var extensions = primitives!.VendorExtensions!;
        Assert.Equal("Grafana Labs", extensions["kev.vendorProject"]);
        Assert.Equal("Grafana", extensions["kev.product"]);
        Assert.Equal("2025-10-30", extensions["kev.dueDate"]);
        Assert.Equal("Unknown", extensions["kev.knownRansomwareCampaignUse"]);
        Assert.Equal("CWE-22", extensions["kev.cwe"]);

        var references = advisory.References.Select(reference => reference.Url).ToArray();
        Assert.Contains("https://grafana.com/security/advisory", references);
        Assert.Contains("https://nvd.nist.gov/vuln/detail/CVE-2021-43798", references);
        Assert.Contains("https://www.cisa.gov/known-exploited-vulnerabilities-catalog?search=CVE-2021-43798", references);
    }
}
