using Intentor.Models;
using Microsoft.EntityFrameworkCore;

namespace Intentor.Data;

public sealed class IntentActivationRepository(IntentorDbContext db) : IIntentActivationRepository
{
    public async Task<IntentActivation> ActivateAsync(
        int spaceId,
        int intentId,
        DateTimeOffset? until = null,
        string? source = null,
        CancellationToken ct = default)
    {
        var activation = new IntentActivation
        {
            SpaceId = spaceId,
            IntentId = intentId,
            Until = until,
            Source = source,
            CreatedAt = DateTimeOffset.UtcNow
        };

        db.IntentActivations.Add(activation);
        await db.SaveChangesAsync(ct);
        return activation;
    }

    public async Task DeactivateAsync(long activationId, CancellationToken ct = default)
    {
        var entity = await db.IntentActivations.FirstOrDefaultAsync(a => a.Id == activationId, ct);
        if (entity is null) return;

        db.IntentActivations.Remove(entity);
        await db.SaveChangesAsync(ct);
    }

    public async Task<int> DeactivateBySourceAsync(int spaceId, string source, CancellationToken ct = default)
    {
        var entities = await db.IntentActivations
            .Where(a => a.SpaceId == spaceId && a.Source == source)
            .ToListAsync(ct);

        if (entities.Count == 0) return 0;

        db.IntentActivations.RemoveRange(entities);
        return await db.SaveChangesAsync(ct);
    }

    public async Task<int> CleanupExpiredAsync(DateTimeOffset now, CancellationToken ct = default)
    {
        var expired = await db.IntentActivations
            .Where(a => a.Until != null && a.Until < now)
            .ToListAsync(ct);

        if (expired.Count == 0) return 0;

        db.IntentActivations.RemoveRange(expired);
        return await db.SaveChangesAsync(ct);
    }

    public Task<Intent?> GetEffectiveIntentAsync(int spaceId, DateTimeOffset now, CancellationToken ct = default)
    {
        // Active activations: Until == null OR Until >= now
        // Winner rule: highest intent priority; tie-breaker: most recently activated
        return db.IntentActivations
            .AsNoTracking()
            .Where(a => a.SpaceId == spaceId && (a.Until == null || a.Until >= now))
            .OrderByDescending(a => a.Intent.Priority)
            .ThenByDescending(a => a.CreatedAt)
            .Select(a => a.Intent)
            .FirstOrDefaultAsync(ct);
    }
}
