using System;
using Xunit;
using StellaOps.Feedser.Models;
using StellaOps.Feedser.Source.Distro.Debian;
using StellaOps.Feedser.Source.Distro.Debian.Internal;
using StellaOps.Feedser.Storage.Mongo.Documents;

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

public sealed class DebianMapperTests
{
    [Fact]
    public void Map_BuildsRangePrimitives_ForResolvedPackage()
    {
        var dto = new DebianAdvisoryDto(
            AdvisoryId: "DSA-2024-123",
            SourcePackage: "openssl",
            Title: "Openssl security update",
            Description: "Fixes multiple issues.",
            CveIds: new[] { "CVE-2024-1000", "CVE-2024-1001" },
            Packages: new[]
            {
                new DebianPackageStateDto(
                    Package: "openssl",
                    Release: "bullseye",
                    Status: "resolved",
                    IntroducedVersion: "1:1.1.1n-0+deb11u2",
                    FixedVersion: "1:1.1.1n-0+deb11u5",
                    LastAffectedVersion: null,
                    Published: new DateTimeOffset(2024, 9, 1, 0, 0, 0, TimeSpan.Zero)),
                new DebianPackageStateDto(
                    Package: "openssl",
                    Release: "bookworm",
                    Status: "open",
                    IntroducedVersion: null,
                    FixedVersion: null,
                    LastAffectedVersion: null,
                    Published: null)
            },
            References: new[]
            {
                new DebianReferenceDto(
                    Url: "https://security-tracker.debian.org/tracker/DSA-2024-123",
                    Kind: "advisory",
                    Title: "Debian Security Advisory 2024-123"),
            });

        var document = new DocumentRecord(
            Id: Guid.NewGuid(),
            SourceName: DebianConnectorPlugin.SourceName,
            Uri: "https://security-tracker.debian.org/tracker/DSA-2024-123",
            FetchedAt: new DateTimeOffset(2024, 9, 1, 1, 0, 0, TimeSpan.Zero),
            Sha256: "sha",
            Status: "Fetched",
            ContentType: "application/json",
            Headers: null,
            Metadata: null,
            Etag: null,
            LastModified: null,
            GridFsId: null);

        Advisory advisory = DebianMapper.Map(dto, document, new DateTimeOffset(2024, 9, 1, 2, 0, 0, TimeSpan.Zero));

        Assert.Equal("DSA-2024-123", advisory.AdvisoryKey);
        Assert.Contains("CVE-2024-1000", advisory.Aliases);
        Assert.Contains("CVE-2024-1001", advisory.Aliases);

        var resolvedPackage = Assert.Single(advisory.AffectedPackages, p => p.Platform == "bullseye");
        var range = Assert.Single(resolvedPackage.VersionRanges);
        Assert.Equal("evr", range.RangeKind);
        Assert.Equal("1:1.1.1n-0+deb11u2", range.IntroducedVersion);
        Assert.Equal("1:1.1.1n-0+deb11u5", range.FixedVersion);
        Assert.NotNull(range.Primitives);
        var evr = range.Primitives!.Evr;
        Assert.NotNull(evr);
        Assert.NotNull(evr!.Introduced);
        Assert.Equal(1, evr.Introduced!.Epoch);
        Assert.Equal("1.1.1n", evr.Introduced.UpstreamVersion);
        Assert.Equal("0+deb11u2", evr.Introduced.Revision);
        Assert.NotNull(evr.Fixed);
        Assert.Equal(1, evr.Fixed!.Epoch);
        Assert.Equal("1.1.1n", evr.Fixed.UpstreamVersion);
        Assert.Equal("0+deb11u5", evr.Fixed.Revision);

        var normalizedRule = Assert.Single(resolvedPackage.NormalizedVersions);
        Assert.Equal(NormalizedVersionSchemes.Evr, normalizedRule.Scheme);
        Assert.Equal(NormalizedVersionRuleTypes.Range, normalizedRule.Type);
        Assert.Equal("1:1.1.1n-0+deb11u2", normalizedRule.Min);
        Assert.True(normalizedRule.MinInclusive);
        Assert.Equal("1:1.1.1n-0+deb11u5", normalizedRule.Max);
        Assert.False(normalizedRule.MaxInclusive);
        Assert.Equal("debian:bullseye", normalizedRule.Notes);

        var openPackage = Assert.Single(advisory.AffectedPackages, p => p.Platform == "bookworm");
        Assert.Empty(openPackage.VersionRanges);
        Assert.Empty(openPackage.NormalizedVersions);
    }
}
