using MongoDB.Driver;
using Nalu.Web.Data.Models;

namespace Nalu.Web.Data;

public class MongoDbContext
{
    private readonly IMongoDatabase? _database;

    public MongoDbContext(IConfiguration configuration, IMongoClient? mongoClient = null)
    {
        var connectionString = configuration.GetConnectionString("MongoDB");

        if (mongoClient is not null && !string.IsNullOrWhiteSpace(connectionString))
        {
            try
            {
                var url = MongoUrl.Create(connectionString);
                _database = mongoClient.GetDatabase(url.DatabaseName);
                IsConnected = true;
            }
            catch
            {
                IsConnected = false;
            }
        }
    }

    public bool IsConnected { get; }

    public IMongoCollection<NaluUser> Users =>
        _database!.GetCollection<NaluUser>("users");

    public IMongoCollection<ApiKey> ApiKeys =>
        _database!.GetCollection<ApiKey>("api_keys");

    public IMongoCollection<Subscription> Subscriptions =>
        _database!.GetCollection<Subscription>("subscriptions");

    public IMongoCollection<UsageDaily> UsageDaily =>
        _database!.GetCollection<UsageDaily>("usage_daily");

    public IMongoCollection<WebhookEvent> WebhookEvents =>
        _database!.GetCollection<WebhookEvent>("webhook_events");

    public IMongoCollection<UsageMonthly> UsageMonthly =>
        _database!.GetCollection<UsageMonthly>("usage_monthly");

    public async Task InitializeAsync()
    {
        if (!IsConnected) return;
        await CreateIndexesAsync();
    }

    private async Task CreateIndexesAsync()
    {
        // users
        await Users.Indexes.CreateManyAsync([
            new CreateIndexModel<NaluUser>(
                Builders<NaluUser>.IndexKeys.Ascending(u => u.Email),
                new CreateIndexOptions { Unique = true }),
            new CreateIndexModel<NaluUser>(
                Builders<NaluUser>.IndexKeys
                    .Ascending(u => u.Provider)
                    .Ascending(u => u.ProviderId),
                new CreateIndexOptions { Unique = true }),
        ]);

        // api_keys
        await ApiKeys.Indexes.CreateManyAsync([
            new CreateIndexModel<ApiKey>(
                Builders<ApiKey>.IndexKeys.Ascending(k => k.Key),
                new CreateIndexOptions { Unique = true }),
            new CreateIndexModel<ApiKey>(
                Builders<ApiKey>.IndexKeys.Ascending(k => k.UserId)),
        ]);

        // subscriptions
        await Subscriptions.Indexes.CreateManyAsync([
            new CreateIndexModel<Subscription>(
                Builders<Subscription>.IndexKeys.Ascending(s => s.StripeSubscriptionId),
                new CreateIndexOptions { Unique = true }),
            new CreateIndexModel<Subscription>(
                Builders<Subscription>.IndexKeys.Ascending(s => s.UserId)),
        ]);

        // usage_daily — compound (api_key + date) unique for atomic $inc upserts
        await UsageDaily.Indexes.CreateManyAsync([
            new CreateIndexModel<UsageDaily>(
                Builders<UsageDaily>.IndexKeys
                    .Ascending(u => u.ApiKey)
                    .Ascending(u => u.Date),
                new CreateIndexOptions { Unique = true }),
            new CreateIndexModel<UsageDaily>(
                Builders<UsageDaily>.IndexKeys
                    .Ascending(u => u.ApiKey)
                    .Ascending(u => u.YearMonth)),
        ]);

        // webhook_events — unique on stripe_event_id to prevent duplicate processing
        await WebhookEvents.Indexes.CreateManyAsync([
            new CreateIndexModel<WebhookEvent>(
                Builders<WebhookEvent>.IndexKeys.Ascending(w => w.StripeEventId),
                new CreateIndexOptions { Unique = true }),
        ]);

        // usage_monthly — compound (api_key + year_month) unique for atomic $inc upserts
        await UsageMonthly.Indexes.CreateManyAsync([
            new CreateIndexModel<UsageMonthly>(
                Builders<UsageMonthly>.IndexKeys
                    .Ascending(u => u.ApiKey)
                    .Ascending(u => u.YearMonth),
                new CreateIndexOptions { Unique = true }),
        ]);
    }
}
