using System;
using System.Collections.Generic;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using StellaOps.Feedser.Exporter.Json;
using StellaOps.Feedser.Models;

namespace StellaOps.Feedser.Exporter.Json.Tests;

public sealed class JsonExporterParitySmokeTests : IDisposable
{
    private readonly string _root;

    public JsonExporterParitySmokeTests()
    {
        _root = Directory.CreateTempSubdirectory("feedser-json-parity-tests").FullName;
    }

    [Fact]
    public async Task ExportProducesVulnListCompatiblePaths()
    {
        var options = new JsonExportOptions { OutputRoot = _root };
        var builder = new JsonExportSnapshotBuilder(options, new VulnListJsonExportPathResolver());
        var exportedAt = DateTimeOffset.Parse("2024-09-01T12:00:00Z", CultureInfo.InvariantCulture);

        var advisories = CreateSampleAdvisories();
        var result = await builder.WriteAsync(advisories, exportedAt, exportName: "parity-test", CancellationToken.None);

        var expected = new[]
        {
            "amazon/2/ALAS2-2024-1234.json",
            "debian/DLA-2024-1234.json",
            "ghsa/go/github.com%2Facme%2Fsample/GHSA-AAAA-BBBB-CCCC.json",
            "nvd/2023/CVE-2023-27524.json",
            "oracle/linux/ELSA-2024-12345.json",
            "redhat/oval/RHSA-2024_0252.json",
            "ubuntu/USN-6620-1.json",
            "wolfi/WOLFI-2024-0001.json",
        };

        Assert.Equal(expected, result.FilePaths.ToArray());

        foreach (var path in expected)
        {
            var fullPath = ResolvePath(result.ExportDirectory, path);
            Assert.True(File.Exists(fullPath), $"Expected export file '{path}' to be present");
        }
    }

    private static IReadOnlyList<Advisory> CreateSampleAdvisories()
    {
        var published = DateTimeOffset.Parse("2024-01-01T00:00:00Z", CultureInfo.InvariantCulture);
        var modified = DateTimeOffset.Parse("2024-02-01T00:00:00Z", CultureInfo.InvariantCulture);

        return new[]
        {
            CreateAdvisory(
                "CVE-2023-27524",
                "Apache Superset Improper Authentication",
                new[] { "CVE-2023-27524" },
                null,
                "nvd",
                published,
                modified),
            CreateAdvisory(
                "GHSA-aaaa-bbbb-cccc",
                "Sample GHSA",
                new[] { "CVE-2024-2000" },
                new[]
                {
                    new AffectedPackage(
                        AffectedPackageTypes.SemVer,
                        "pkg:go/github.com/acme/sample@1.0.0",
                        provenance: new[] { new AdvisoryProvenance("ghsa", "map", "", published) })
                },
                "ghsa",
                published,
                modified),
            CreateAdvisory(
                "USN-6620-1",
                "Ubuntu Security Notice",
                null,
                null,
                "ubuntu",
                published,
                modified),
            CreateAdvisory(
                "DLA-2024-1234",
                "Debian LTS Advisory",
                null,
                null,
                "debian",
                published,
                modified),
            CreateAdvisory(
                "RHSA-2024:0252",
                "Red Hat Security Advisory",
                null,
                null,
                "redhat",
                published,
                modified),
            CreateAdvisory(
                "ALAS2-2024-1234",
                "Amazon Linux Advisory",
                null,
                null,
                "amazon",
                published,
                modified),
            CreateAdvisory(
                "ELSA-2024-12345",
                "Oracle Linux Advisory",
                null,
                null,
                "oracle",
                published,
                modified),
            CreateAdvisory(
                "WOLFI-2024-0001",
                "Wolfi Advisory",
                null,
                null,
                "wolfi",
                published,
                modified),
        };
    }

    private static Advisory CreateAdvisory(
        string advisoryKey,
        string title,
        IEnumerable<string>? aliases,
        IEnumerable<AffectedPackage>? packages,
        string? provenanceSource,
        DateTimeOffset? published,
        DateTimeOffset? modified)
    {
        var provenance = provenanceSource is null
            ? Array.Empty<AdvisoryProvenance>()
            : new[] { new AdvisoryProvenance(provenanceSource, "normalize", "", modified ?? DateTimeOffset.UtcNow) };

        return new Advisory(
            advisoryKey,
            title,
            summary: null,
            language: "en",
            published,
            modified,
            severity: "medium",
            exploitKnown: false,
            aliases: aliases ?? Array.Empty<string>(),
            references: Array.Empty<AdvisoryReference>(),
            affectedPackages: packages ?? Array.Empty<AffectedPackage>(),
            cvssMetrics: Array.Empty<CvssMetric>(),
            provenance: provenance);
    }

    private static string ResolvePath(string root, string relative)
    {
        var segments = relative.Split('/', StringSplitOptions.RemoveEmptyEntries);
        return Path.Combine(new[] { root }.Concat(segments).ToArray());
    }

    public void Dispose()
    {
        try
        {
            if (Directory.Exists(_root))
            {
                Directory.Delete(_root, recursive: true);
            }
        }
        catch
        {
            // best effort cleanup
        }
    }
}
