using System.Text.Json;
using System.Text.Json.Serialization;
using Microsoft.Extensions.Logging;
using MongoDB.Driver;

namespace Nalu.Jobs;

/// <summary>
/// Imports the curated Brazilian names list (Data/names_curated.json) into MongoDB.
/// Complements the IBGE importer with names not covered by the IBGE top-20 ranking.
/// Uses the same nomes_br collection and upsert logic.
/// </summary>
public static class CuratedNamesImporter
{
    private static readonly JsonSerializerOptions JsonOpts = new()
    {
        PropertyNameCaseInsensitive = true
    };

    private static readonly string[] EmbeddedFiles =
    [
        "names_curated.json",
        "names_curated_en.json",
        "names_curated_es.json"
    ];

    public static async Task ImportAsync(
        IMongoDatabase db,
        ILogger logger,
        CancellationToken ct)
    {
        var repo = new NameRepository(db);
        await repo.EnsureIndexesAsync(ct);

        var now = DateTime.UtcNow;
        int totalInserted = 0, totalUpdated = 0;

        foreach (var fileName in EmbeddedFiles)
        {
            var entries = LoadEmbeddedList(fileName);
            logger.LogInformation("Curated list '{File}' loaded — {Count} entries", fileName, entries.Length);

            foreach (var entry in entries)
            {
                ct.ThrowIfCancellationRequested();
                if (string.IsNullOrWhiteSpace(entry.Nome)) continue;

                var aggregated = new AggregatedName(
                    Nome:       entry.Nome.Trim().ToUpperInvariant(),
                    Frequencia: entry.Frequencia,
                    Genero:     NormalizeGenero(entry.Genero));

                var wasInserted = await repo.UpsertAsync(aggregated, now, ct);
                if (wasInserted) totalInserted++; else totalUpdated++;
            }
        }

        logger.LogInformation(
            "Curated import done — inserted={I} updated={U}", totalInserted, totalUpdated);
    }

    private static CuratedEntry[] LoadEmbeddedList(string fileName)
    {
        var asm = typeof(CuratedNamesImporter).Assembly;
        var resourceName = asm.GetManifestResourceNames()
            .FirstOrDefault(n => n.EndsWith(fileName, StringComparison.OrdinalIgnoreCase))
            ?? throw new InvalidOperationException($"Embedded resource '{fileName}' not found.");

        using var stream = asm.GetManifestResourceStream(resourceName)!;
        return JsonSerializer.Deserialize<CuratedEntry[]>(stream, JsonOpts)
               ?? throw new InvalidDataException($"'{fileName}' is empty or invalid.");
    }

    private static string NormalizeGenero(string? g) => g?.ToUpperInvariant() switch
    {
        "M" => "M",
        "F" => "F",
        _   => "N"
    };

    private record CuratedEntry
    {
        [JsonPropertyName("nome")]      public string Nome      { get; init; } = "";
        [JsonPropertyName("genero")]    public string? Genero   { get; init; }
        [JsonPropertyName("frequencia")] public long Frequencia { get; init; }
    }
}
