using System.Text.Json;
using MongoDB.Bson;
using StellaOps.Feedser.Models;
using StellaOps.Feedser.Source.Osv.Internal;
using StellaOps.Feedser.Storage.Mongo.Documents;
using StellaOps.Feedser.Storage.Mongo.Dtos;

namespace StellaOps.Feedser.Source.Osv.Tests;

public sealed class OsvConflictFixtureTests
{
    [Fact]
    public void ConflictFixture_MatchesSnapshot()
    {
        using var databaseSpecificDoc = JsonDocument.Parse("""{"severity":"medium"}""");

        var dto = new OsvVulnerabilityDto
        {
            Id = "OSV-2025-4242",
            Summary = "Container escape for conflict-package",
            Details = "OSV captures the latest container escape details including patched version metadata.",
            Aliases = new[] { "CVE-2025-4242", "GHSA-qqqq-wwww-eeee" },
            Published = new DateTimeOffset(2025, 2, 28, 0, 0, 0, TimeSpan.Zero),
            Modified = new DateTimeOffset(2025, 3, 6, 12, 0, 0, TimeSpan.Zero),
            Severity = new[]
            {
                new OsvSeverityDto
                {
                    Type = "CVSS_V3",
                    Score = "CVSS:3.1/AV:N/AC:H/PR:L/UI:R/S:U/C:L/I:L/A:L"
                }
            },
            References = new[]
            {
                new OsvReferenceDto
                {
                    Type = "ADVISORY",
                    Url = "https://osv.dev/vulnerability/OSV-2025-4242"
                },
                new OsvReferenceDto
                {
                    Type = "FIX",
                    Url = "https://github.com/conflict/package/commit/abcdef1234567890"
                }
            },
            Credits = new[]
            {
                new OsvCreditDto
                {
                    Name = "osv-reporter",
                    Type = "reporter",
                    Contact = new[] { "mailto:osv-reporter@example.com" }
                }
            },
            Affected = new[]
            {
                new OsvAffectedPackageDto
                {
                    Package = new OsvPackageDto
                    {
                        Ecosystem = "npm",
                        Name = "conflict/package"
                    },
                    Ranges = new[]
                    {
                        new OsvRangeDto
                        {
                            Type = "SEMVER",
                            Events = new[]
                            {
                                new OsvEventDto { Introduced = "1.0.0" },
                                new OsvEventDto { LastAffected = "1.4.2" },
                                new OsvEventDto { Fixed = "1.5.0" }
                            }
                        }
                    }
                }
            },
            DatabaseSpecific = databaseSpecificDoc.RootElement.Clone()
        };

        var document = new DocumentRecord(
            Id: Guid.Parse("8dd2b0fe-a5f5-4b3b-9f5c-0f3aad6fb6ce"),
            SourceName: OsvConnectorPlugin.SourceName,
            Uri: "https://api.osv.dev/v1/vulns/OSV-2025-4242",
            FetchedAt: new DateTimeOffset(2025, 3, 6, 11, 30, 0, TimeSpan.Zero),
            Sha256: "sha256-osv-conflict-fixture",
            Status: "completed",
            ContentType: "application/json",
            Headers: null,
            Metadata: null,
            Etag: "\"etag-osv-conflict\"",
            LastModified: new DateTimeOffset(2025, 3, 6, 12, 0, 0, TimeSpan.Zero),
            GridFsId: null);

        var dtoRecord = new DtoRecord(
            Id: Guid.Parse("6f7d5ce7-cb47-40a5-8b41-8ad022b5fd5c"),
            DocumentId: document.Id,
            SourceName: OsvConnectorPlugin.SourceName,
            SchemaVersion: "osv.v1",
            Payload: new BsonDocument("id", dto.Id),
            ValidatedAt: new DateTimeOffset(2025, 3, 6, 12, 5, 0, TimeSpan.Zero));

        var advisory = OsvMapper.Map(dto, document, dtoRecord, "npm");
        var snapshot = SnapshotSerializer.ToSnapshot(advisory).Replace("\r\n", "\n").TrimEnd();

        var expectedPath = Path.Combine(AppContext.BaseDirectory, "Fixtures", "conflict-osv.canonical.json");
        var expected = File.ReadAllText(expectedPath).Replace("\r\n", "\n").TrimEnd();

        if (!string.Equals(expected, snapshot, StringComparison.Ordinal))
        {
            var actualPath = Path.Combine(AppContext.BaseDirectory, "Fixtures", "conflict-osv.canonical.actual.json");
            File.WriteAllText(actualPath, snapshot);
        }

        Assert.Equal(expected, snapshot);
    }
}
