using ClaudeDo.Data;
using ClaudeDo.Data.Repositories;
using ClaudeDo.Worker.Usage.Interfaces;
using Microsoft.EntityFrameworkCore;

namespace ClaudeDo.Worker.Usage;

public sealed record UsageGateDecision(bool IsBlocked, string? Reason);

/// <summary>
/// Gates autonomous queue refill on the 5h/7d Claude usage window. Fail-open: no snapshot yet,
/// a failed last poll, or a settings read error all resolve to "not blocked" — an undocumented
/// or unreachable usage API must never stall automation. Only queue refill is gated; runs already
/// in flight (RunNow, ContinueTask, interactive sessions, planning, daily prep) are untouched.
/// </summary>
public sealed class UsageGate : IUsageGate
{
    private readonly IDbContextFactory<ClaudeDoDbContext> _dbFactory;
    private readonly UsageState _state;
    private readonly ILogger<UsageGate> _logger;

    public UsageGate(IDbContextFactory<ClaudeDoDbContext> dbFactory, UsageState state, ILogger<UsageGate> logger)
    {
        _dbFactory = dbFactory;
        _state = state;
        _logger = logger;
    }

    public async Task<UsageGateDecision> EvaluateAsync(CancellationToken ct = default)
    {
        var snapshot = _state.Snapshot;
        if (snapshot is null || _state.LastError is not null)
            return new UsageGateDecision(false, null);

        int fiveHourPct;
        int sevenDayPct;
        try
        {
            using var context = _dbFactory.CreateDbContext();
            var settings = await new AppSettingsRepository(context).GetAsync(ct);
            fiveHourPct = settings.UsageGateFiveHourPct;
            sevenDayPct = settings.UsageGateSevenDayPct;
        }
        catch (Exception ex)
        {
            _logger.LogWarning(ex, "UsageGate: failed to read gate thresholds; not blocking");
            return new UsageGateDecision(false, null);
        }

        if (fiveHourPct > 0 && snapshot.FiveHour is not null && snapshot.FiveHour.Utilization >= fiveHourPct)
            return new UsageGateDecision(true, $"5h-Limit {snapshot.FiveHour.Utilization:0}% >= {fiveHourPct}%");

        if (sevenDayPct > 0 && snapshot.SevenDay is not null && snapshot.SevenDay.Utilization >= sevenDayPct)
            return new UsageGateDecision(true, $"7d-Limit {snapshot.SevenDay.Utilization:0}% >= {sevenDayPct}%");

        return new UsageGateDecision(false, null);
    }
}
