using System.Collections.Generic;
using System.Collections.Immutable;
using System.Linq;
using System.Text.Json.Serialization;

namespace StellaOps.Feedser.Models;

/// <summary>
/// Canonical weakness (e.g., CWE entry) associated with an advisory.
/// </summary>
public sealed record AdvisoryWeakness
{
    public static AdvisoryWeakness Empty { get; } = new("cwe", "CWE-000", null, null, Array.Empty<AdvisoryProvenance>());

    [JsonConstructor]
    public AdvisoryWeakness(string taxonomy, string identifier, string? name, string? uri, ImmutableArray<AdvisoryProvenance> provenance)
        : this(taxonomy, identifier, name, uri, provenance.IsDefault ? null : provenance.AsEnumerable())
    {
    }

    public AdvisoryWeakness(string taxonomy, string identifier, string? name, string? uri, IEnumerable<AdvisoryProvenance>? provenance)
    {
        Taxonomy = NormalizeTaxonomy(taxonomy);
        Identifier = NormalizeIdentifier(identifier);
        Name = Validation.TrimToNull(name);
        Uri = Validation.TrimToNull(uri);
        Provenance = (provenance ?? Array.Empty<AdvisoryProvenance>())
            .Where(static value => value is not null)
            .OrderBy(static value => value.Source, StringComparer.Ordinal)
            .ThenBy(static value => value.Kind, StringComparer.Ordinal)
            .ThenBy(static value => value.RecordedAt)
            .ToImmutableArray();
    }

    public string Taxonomy { get; }

    public string Identifier { get; }

    public string? Name { get; }

    public string? Uri { get; }

    public ImmutableArray<AdvisoryProvenance> Provenance { get; }

    private static string NormalizeTaxonomy(string taxonomy)
    {
        var normalized = Validation.EnsureNotNullOrWhiteSpace(taxonomy, nameof(taxonomy)).Trim();
        return normalized.Length == 0 ? "cwe" : normalized.ToLowerInvariant();
    }

    private static string NormalizeIdentifier(string identifier)
    {
        var normalized = Validation.EnsureNotNullOrWhiteSpace(identifier, nameof(identifier)).Trim();
        return normalized.ToUpperInvariant();
    }
}
