using System.Collections.Generic;
using System.Globalization;
using StellaOps.Feedser.Models;

namespace StellaOps.Feedser.Models.Tests;

internal static class CanonicalExampleFactory
{
    public static IEnumerable<(string Name, Advisory Advisory)> GetExamples()
    {
        yield return ("nvd-basic", CreateNvdExample());
        yield return ("psirt-overlay", CreatePsirtOverlay());
        yield return ("ghsa-semver", CreateGhsaSemVer());
        yield return ("kev-flag", CreateKevFlag());
    }

    private static Advisory CreateNvdExample()
    {
        var provenance = Provenance("nvd", "map", "cve-2024-1234", "2024-08-01T12:00:00Z");
        return new Advisory(
            advisoryKey: "CVE-2024-1234",
            title: "Integer overflow in ExampleCMS",
            summary: "An integer overflow in ExampleCMS allows remote attackers to escalate privileges.",
            language: "en",
            published: ParseDate("2024-07-15T00:00:00Z"),
            modified: ParseDate("2024-07-16T10:35:00Z"),
            severity: "high",
            exploitKnown: false,
            aliases: new[] { "CVE-2024-1234" },
            references: new[]
            {
                new AdvisoryReference(
                    "https://nvd.nist.gov/vuln/detail/CVE-2024-1234",
                    kind: "advisory",
                    sourceTag: "nvd",
                    summary: "NVD entry",
                    provenance: provenance),
                new AdvisoryReference(
                    "https://example.org/security/CVE-2024-1234",
                    kind: "advisory",
                    sourceTag: "vendor",
                    summary: "Vendor bulletin",
                    provenance: Provenance("example", "fetch", "bulletin", "2024-07-14T15:00:00Z")),
            },
            affectedPackages: new[]
            {
                new AffectedPackage(
                    type: AffectedPackageTypes.Cpe,
                    identifier: "cpe:/a:examplecms:examplecms:1.0",
                    platform: null,
                    versionRanges: new[]
                    {
                        new AffectedVersionRange("version", "1.0", "1.0.5", null, null, provenance),
                    },
                    statuses: new[]
                    {
                        new AffectedPackageStatus("affected", provenance),
                    },
                    provenance: new[] { provenance }),
            },
            cvssMetrics: new[]
            {
                new CvssMetric("3.1", "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H", 9.8, "critical", provenance),
            },
            provenance: new[] { provenance });
    }

    private static Advisory CreatePsirtOverlay()
    {
        var rhsaProv = Provenance("redhat", "map", "rhsa-2024:0252", "2024-05-11T09:00:00Z");
        var cveProv = Provenance("redhat", "enrich", "cve-2024-5678", "2024-05-11T09:05:00Z");
        return new Advisory(
            advisoryKey: "RHSA-2024:0252",
            title: "Important: kernel security update",
            summary: "Updates the Red Hat Enterprise Linux kernel to address CVE-2024-5678.",
            language: "en",
            published: ParseDate("2024-05-10T19:28:00Z"),
            modified: ParseDate("2024-05-11T08:15:00Z"),
            severity: "critical",
            exploitKnown: false,
            aliases: new[] { "RHSA-2024:0252", "CVE-2024-5678" },
            references: new[]
            {
                new AdvisoryReference(
                    "https://access.redhat.com/errata/RHSA-2024:0252",
                    kind: "advisory",
                    sourceTag: "redhat",
                    summary: "Red Hat security advisory",
                    provenance: rhsaProv),
            },
            affectedPackages: new[]
            {
                new AffectedPackage(
                    type: AffectedPackageTypes.Rpm,
                    identifier: "kernel-0:4.18.0-553.el8.x86_64",
                    platform: "rhel-8",
                    versionRanges: new[]
                    {
                        new AffectedVersionRange("nevra", "0:4.18.0-553.el8", null, null, null, rhsaProv),
                    },
                    statuses: new[]
                    {
                        new AffectedPackageStatus("fixed", rhsaProv),
                    },
                    provenance: new[] { rhsaProv, cveProv }),
            },
            cvssMetrics: new[]
            {
                new CvssMetric("3.1", "CVSS:3.1/AV:L/AC:L/PR:H/UI:N/S:U/C:H/I:H/A:H", 6.7, "medium", rhsaProv),
            },
            provenance: new[] { rhsaProv, cveProv });
    }

    private static Advisory CreateGhsaSemVer()
    {
        var provenance = Provenance("ghsa", "map", "ghsa-aaaa-bbbb-cccc", "2024-03-05T10:00:00Z");
        return new Advisory(
            advisoryKey: "GHSA-aaaa-bbbb-cccc",
            title: "Prototype pollution in widget.js",
            summary: "A crafted payload can pollute Object.prototype leading to RCE.",
            language: "en",
            published: ParseDate("2024-03-04T00:00:00Z"),
            modified: ParseDate("2024-03-04T12:00:00Z"),
            severity: "high",
            exploitKnown: false,
            aliases: new[] { "GHSA-aaaa-bbbb-cccc", "CVE-2024-2222" },
            references: new[]
            {
                new AdvisoryReference(
                    "https://github.com/example/widget/security/advisories/GHSA-aaaa-bbbb-cccc",
                    kind: "advisory",
                    sourceTag: "ghsa",
                    summary: "GitHub Security Advisory",
                    provenance: provenance),
                new AdvisoryReference(
                    "https://github.com/example/widget/commit/abcd1234",
                    kind: "patch",
                    sourceTag: "ghsa",
                    summary: "Patch commit",
                    provenance: provenance),
            },
            affectedPackages: new[]
            {
                new AffectedPackage(
                    type: AffectedPackageTypes.SemVer,
                    identifier: "pkg:npm/example-widget",
                    platform: null,
                    versionRanges: new[]
                    {
                        new AffectedVersionRange("semver", null, "2.5.1", null, ">=0.0.0 <2.5.1", provenance),
                        new AffectedVersionRange("semver", "3.0.0", "3.2.4", null, null, provenance),
                    },
                    statuses: Array.Empty<AffectedPackageStatus>(),
                    provenance: new[] { provenance }),
            },
            cvssMetrics: new[]
            {
                new CvssMetric("3.1", "CVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:U/C:H/I:H/A:H", 8.8, "high", provenance),
            },
            provenance: new[] { provenance });
    }

    private static Advisory CreateKevFlag()
    {
        var provenance = Provenance("cisa-kev", "annotate", "kev", "2024-02-10T09:30:00Z");
        return new Advisory(
            advisoryKey: "CVE-2023-9999",
            title: "Remote code execution in LegacyServer",
            summary: "Unauthenticated RCE due to unsafe deserialization.",
            language: "en",
            published: ParseDate("2023-11-20T00:00:00Z"),
            modified: ParseDate("2024-02-09T16:22:00Z"),
            severity: "critical",
            exploitKnown: true,
            aliases: new[] { "CVE-2023-9999" },
            references: new[]
            {
                new AdvisoryReference(
                    "https://www.cisa.gov/known-exploited-vulnerabilities-catalog",
                    kind: "kev",
                    sourceTag: "cisa",
                    summary: "CISA KEV entry",
                    provenance: provenance),
            },
            affectedPackages: Array.Empty<AffectedPackage>(),
            cvssMetrics: Array.Empty<CvssMetric>(),
            provenance: new[] { provenance });
    }

    private static AdvisoryProvenance Provenance(string source, string kind, string value, string recordedAt)
        => new(source, kind, value, ParseDate(recordedAt));

    private static DateTimeOffset ParseDate(string value)
        => DateTimeOffset.Parse(value, CultureInfo.InvariantCulture, DateTimeStyles.AssumeUniversal).ToUniversalTime();
}
