using System;
using System.Collections.Generic;
using System.IO;
using MongoDB.Bson;
using StellaOps.Feedser.Models;
using StellaOps.Feedser.Source.Common;
using StellaOps.Feedser.Source.Distro.Suse;
using StellaOps.Feedser.Source.Distro.Suse.Internal;
using StellaOps.Feedser.Storage.Mongo.Documents;
using Xunit;

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

public sealed class SuseMapperTests
{
    [Fact]
    public void Map_BuildsNevraRangePrimitives()
    {
        var json = File.ReadAllText(Path.Combine(AppContext.BaseDirectory, "Source", "Distro", "Suse", "Fixtures", "suse-su-2025_0001-1.json"));
        var dto = SuseCsafParser.Parse(json);

        var document = new DocumentRecord(
            Guid.NewGuid(),
            SuseConnectorPlugin.SourceName,
            "https://ftp.suse.com/pub/projects/security/csaf/suse-su-2025_0001-1.json",
            DateTimeOffset.UtcNow,
            "sha256",
            DocumentStatuses.PendingParse,
            "application/json",
            Headers: null,
            Metadata: new Dictionary<string, string>(StringComparer.Ordinal)
            {
                ["suse.id"] = dto.AdvisoryId
            },
            Etag: "adv-1",
            LastModified: DateTimeOffset.UtcNow,
            GridFsId: ObjectId.Empty);

        var mapped = SuseMapper.Map(dto, document, DateTimeOffset.UtcNow);

        Assert.Equal(dto.AdvisoryId, mapped.AdvisoryKey);
        var package = Assert.Single(mapped.AffectedPackages);
        Assert.Equal(AffectedPackageTypes.Rpm, package.Type);
        var range = Assert.Single(package.VersionRanges);
        Assert.Equal("nevra", range.RangeKind);
        Assert.NotNull(range.Primitives);
        Assert.NotNull(range.Primitives!.Nevra);
        Assert.NotNull(range.Primitives.Nevra!.Fixed);
        Assert.Equal("openssl", range.Primitives.Nevra.Fixed!.Name);
        Assert.Equal("SUSE Linux Enterprise Server 15 SP5", package.Platform);

        var normalizedRule = Assert.Single(package.NormalizedVersions);
        Assert.Equal(NormalizedVersionSchemes.Nevra, normalizedRule.Scheme);
        Assert.Equal($"suse:{package.Platform}", normalizedRule.Notes);
        var primitives = range.Primitives.Nevra;
        if (primitives!.Introduced is not null)
        {
            Assert.Equal(primitives.Introduced.ToCanonicalString(), normalizedRule.Min);
        }
        if (primitives.Fixed is not null)
        {
            Assert.Equal(primitives.Fixed.ToCanonicalString(), normalizedRule.Max);
        }
        if (primitives.LastAffected is not null && normalizedRule.Type is NormalizedVersionRuleTypes.Range or NormalizedVersionRuleTypes.LessThanOrEqual)
        {
            Assert.Equal(primitives.LastAffected.ToCanonicalString(), normalizedRule.Max);
        }
    }
}
