using MongoDB.Bson;
using MongoDB.Driver;

namespace Nalu.Web.Services;

/// <summary>
/// Checks whether a name (or all significant tokens in a name) exists in the
/// nomes_br MongoDB collection (seeded from IBGE + curated list).
///
/// Used by ExtractionPipeline after a deterministic accept for validators with
/// name_lookup: true. All non-connective tokens must be found for certain=true.
/// Any unknown token → fall through to LLM.
/// </summary>
public class NameLookupService
{
    // Prepositions and articles common in Brazilian names — not checked in nomes_br
    private static readonly HashSet<string> Connectives =
        new(StringComparer.OrdinalIgnoreCase)
        { "DE", "DA", "DO", "DOS", "DAS", "E", "VON", "VAN", "DEL", "DI" };

    private readonly IMongoCollection<BsonDocument> _collection;

    public NameLookupService(IMongoClient mongoClient, IConfiguration configuration)
    {
        var connStr = configuration.GetConnectionString("MongoDB") ?? string.Empty;
        var url     = MongoUrl.Create(connStr);
        var dbName  = string.IsNullOrWhiteSpace(url.DatabaseName) ? "nalu" : url.DatabaseName;
        var db      = mongoClient.GetDatabase(dbName);
        _collection = db.GetCollection<BsonDocument>("nomes_br");
    }

    /// <summary>
    /// Returns true when every significant token in <paramref name="name"/>
    /// is present in nomes_br (uppercase, exact match on the "nome" field).
    /// Connectives (de/da/do/etc.) are ignored.
    /// </summary>
    public async Task<bool> AllTokensKnownAsync(string name, CancellationToken ct)
    {
        var tokens = name
            .Split(' ', StringSplitOptions.RemoveEmptyEntries)
            .Select(w => Normalize(w))
            .Where(w => !Connectives.Contains(w))
            .Distinct(StringComparer.OrdinalIgnoreCase)
            .ToArray();

        if (tokens.Length == 0) return false;

        var filter = Builders<BsonDocument>.Filter.In("nome", tokens);
        var found  = await _collection.CountDocumentsAsync(filter, cancellationToken: ct);

        return found == tokens.Length;
    }

    // Uppercase + remove diacritics for lookup
    private static string Normalize(string word)
    {
        // Quick normalization: uppercase.
        // The nomes_br collection stores names in uppercase (e.g. "JOÃO"),
        // so exact match works for names with diacritics.
        return word.ToUpperInvariant();
    }
}
