using System.Collections.Immutable;
using System.Linq;
using System.Text.Json;
using StellaOps.Feedser.Models;
using Xunit;

namespace StellaOps.Feedser.Source.Ghsa.Tests.Ghsa;

public sealed class GhsaCreditParityRegressionTests
{
    private static readonly JsonSerializerOptions SerializerOptions = new(JsonSerializerDefaults.Web);

    [Fact]
    public void CreditParity_FixturesRemainInSyncAcrossSources()
    {
        var ghsa = LoadFixture("credit-parity.ghsa.json");
        var osv = LoadFixture("credit-parity.osv.json");
        var nvd = LoadFixture("credit-parity.nvd.json");

        var ghsaCredits = NormalizeCredits(ghsa);
        var osvCredits = NormalizeCredits(osv);
        var nvdCredits = NormalizeCredits(nvd);

        Assert.NotEmpty(ghsaCredits);
        Assert.Equal(ghsaCredits, osvCredits);
        Assert.Equal(ghsaCredits, nvdCredits);
    }

    private static Advisory LoadFixture(string fileName)
    {
        var path = Path.Combine(AppContext.BaseDirectory, "Fixtures", fileName);
        return JsonSerializer.Deserialize<Advisory>(File.ReadAllText(path), SerializerOptions)
            ?? throw new InvalidOperationException($"Failed to deserialize fixture '{fileName}'.");
    }

    private static HashSet<string> NormalizeCredits(Advisory advisory)
    {
        var set = new HashSet<string>(StringComparer.Ordinal);
        foreach (var credit in advisory.Credits)
        {
            var contactList = credit.Contacts.IsDefaultOrEmpty
                ? Array.Empty<string>()
                : credit.Contacts.ToArray();
            var contacts = string.Join("|", contactList.OrderBy(static contact => contact, StringComparer.Ordinal));
            var key = string.Join("||", credit.Role ?? string.Empty, credit.DisplayName ?? string.Empty, contacts);
            set.Add(key);
        }

        return set;
    }
}
