using System;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using System.Text.Json;

namespace StellaOps.Feedser.Source.CertCc.Internal;

internal static class CertCcSummaryParser
{
    public static IReadOnlyList<string> ParseNotes(byte[] payload)
    {
        if (payload is null || payload.Length == 0)
        {
            return Array.Empty<string>();
        }

        using var document = JsonDocument.Parse(payload, new JsonDocumentOptions
        {
            AllowTrailingCommas = true,
            CommentHandling = JsonCommentHandling.Skip,
        });

        var notesElement = document.RootElement.ValueKind switch
        {
            JsonValueKind.Object when document.RootElement.TryGetProperty("notes", out var notes) => notes,
            JsonValueKind.Array => document.RootElement,
            JsonValueKind.Null or JsonValueKind.Undefined => default,
            _ => throw new JsonException("CERT/CC summary payload must contain a 'notes' array."),
        };

        if (notesElement.ValueKind != JsonValueKind.Array || notesElement.GetArrayLength() == 0)
        {
            return Array.Empty<string>();
        }

        var results = new List<string>(notesElement.GetArrayLength());
        var seen = new HashSet<string>(StringComparer.Ordinal);

        foreach (var element in notesElement.EnumerateArray())
        {
            var token = ExtractToken(element);
            if (string.IsNullOrWhiteSpace(token))
            {
                continue;
            }

            var normalized = token.Trim();
            var dedupKey = CreateDedupKey(normalized);
            if (seen.Add(dedupKey))
            {
                results.Add(normalized);
            }
        }

        return results.Count == 0 ? Array.Empty<string>() : results;
    }

    private static string CreateDedupKey(string token)
    {
        var digits = string.Concat(token.Where(char.IsDigit));
        return digits.Length > 0
            ? digits
            : token.Trim().ToUpperInvariant();
    }

    private static string? ExtractToken(JsonElement element)
    {
        return element.ValueKind switch
        {
            JsonValueKind.String => element.GetString(),
            JsonValueKind.Number => element.TryGetInt64(out var number)
                ? number.ToString(CultureInfo.InvariantCulture)
                : element.GetRawText(),
            JsonValueKind.Object => ExtractFromObject(element),
            _ => null,
        };
    }

    private static string? ExtractFromObject(JsonElement element)
    {
        foreach (var propertyName in PropertyCandidates)
        {
            if (element.TryGetProperty(propertyName, out var property) && property.ValueKind == JsonValueKind.String)
            {
                var value = property.GetString();
                if (!string.IsNullOrWhiteSpace(value))
                {
                    return value;
                }
            }
        }

        return null;
    }

    private static readonly string[] PropertyCandidates =
    {
        "note",
        "notes",
        "id",
        "idnumber",
        "noteId",
        "vu",
        "vuid",
        "vuId",
    };
}
