using Dapper;
using KArtSell.BuildingBlocks.Data;
using KArtSell.BuildingBlocks.Time;
using KArtSell.Modules.ModelOperations.ShadowRun.Events;
using Microsoft.Extensions.Logging;

namespace KArtSell.Host.Consumers;

/// <summary>
/// Creates approval queue entries when shadow run passes all validation gates.
/// Idempotent: run_id UNIQUE constraint ensures no duplicates.
/// Triggers: Approval workflow notification to model owner/manager.
/// </summary>
public sealed class ApprovalQueueConsumer : IInboxConsumer<ShadowRunCompletedEvent>
{
    private readonly IDbConnectionFactory _connectionFactory;
    private readonly IClock _clock;
    private readonly ILogger<ApprovalQueueConsumer> _logger;

    public ApprovalQueueConsumer(
        IDbConnectionFactory connectionFactory,
        IClock clock,
        ILogger<ApprovalQueueConsumer> logger)
    {
        _connectionFactory = connectionFactory;
        _clock = clock;
        _logger = logger;
    }

    public async Task HandleAsync(ShadowRunCompletedEvent message, CancellationToken cancellationToken = default)
    {
        try
        {
            // Only create approval queue if all gates passed
            if (!message.AllGatesPassed)
            {
                _logger.LogInformation(
                    "Shadow run {RunId} failed gates; skipping approval queue",
                    message.RunId);
                return;
            }

            _logger.LogInformation(
                "Creating approval queue entry for shadow run {RunId}, model {ModelId}",
                message.RunId, message.ModelId);

            const string sql = """
                insert into model_operations.approval_queue
                (run_id, model_id, status, requested_at)
                values (@RunId, @ModelId, @Status, @RequestedAt)
                on conflict (run_id) do nothing
                """;

            await using var connection = await _connectionFactory.OpenAsync(cancellationToken);
            await connection.ExecuteAsync(
                new CommandDefinition(
                    sql,
                    new
                    {
                        RunId = message.RunId,
                        ModelId = message.ModelId,
                        Status = "Pending",
                        RequestedAt = _clock.UtcNow
                    },
                    cancellationToken: cancellationToken));

            _logger.LogInformation(
                "Approval queue entry created for {RunId}",
                message.RunId);
        }
        catch (Exception ex)
        {
            _logger.LogError(ex, "Failed to create approval queue entry for {RunId}", message.RunId);
            throw;  // Let Hangfire classify
        }
    }
}
