using System;
using System.Collections.Generic;
using System.Linq;

namespace StellaOps.Feedser.Source.Vndr.Apple.Internal;

internal sealed record AppleDetailDto(
    string AdvisoryId,
    string ArticleId,
    string Title,
    string Summary,
    DateTimeOffset Published,
    DateTimeOffset? Updated,
    IReadOnlyList<string> CveIds,
    IReadOnlyList<AppleAffectedProductDto> Affected,
    IReadOnlyList<AppleReferenceDto> References,
    bool RapidSecurityResponse);

internal sealed record AppleAffectedProductDto(
    string Platform,
    string Name,
    string Version,
    string Build);

internal sealed record AppleReferenceDto(
    string Url,
    string? Title,
    string? Kind);

internal static class AppleDetailDtoExtensions
{
    public static AppleDetailDto WithAffectedFallback(this AppleDetailDto dto, IEnumerable<AppleIndexProduct> products)
    {
        if (dto.Affected.Count > 0)
        {
            return dto;
        }

        var fallback = products
            .Where(static product => !string.IsNullOrWhiteSpace(product.Version) || !string.IsNullOrWhiteSpace(product.Build))
            .Select(static product => new AppleAffectedProductDto(
                product.Platform,
                product.Name,
                product.Version,
                product.Build))
            .OrderBy(static product => NormalizeSortKey(product.Platform))
            .ThenBy(static product => NormalizeSortKey(product.Name))
            .ThenBy(static product => NormalizeSortKey(product.Version))
            .ThenBy(static product => NormalizeSortKey(product.Build))
            .ToArray();

        return fallback.Length == 0 ? dto : dto with { Affected = fallback };
    }

    private static string NormalizeSortKey(string? value)
    {
        if (string.IsNullOrWhiteSpace(value))
        {
            return string.Empty;
        }

        var span = value.AsSpan();
        var buffer = new char[span.Length];
        var index = 0;

        foreach (var ch in span)
        {
            if (char.IsWhiteSpace(ch))
            {
                continue;
            }

            buffer[index++] = char.ToUpperInvariant(ch);
        }

        return new string(buffer, 0, index);
    }
}
