using System.Text;
using System.Text.Json;
using Microsoft.Extensions.Options;
using RabbitMQ.Client;
using RabbitMQ.Client.Events;

public sealed class ClinicalSyncBatchConsumer : BackgroundService
{
    private readonly IServiceScopeFactory _scopes;
    private readonly RabbitMqOptions _rabbitOpts;
    private readonly ILogger<ClinicalSyncBatchConsumer> _logger;

    public ClinicalSyncBatchConsumer(
        IServiceScopeFactory scopes,
        IOptions<RabbitMqOptions> rabbitOpts,
        ILogger<ClinicalSyncBatchConsumer> logger)
    {
        _scopes = scopes;
        _rabbitOpts = rabbitOpts.Value;
        _logger = logger;
    }

    protected override async Task ExecuteAsync(CancellationToken stoppingToken)
    {
        await Task.Delay(TimeSpan.FromSeconds(5), stoppingToken);

        var factory = RabbitMqConnectionFactory.Create(_rabbitOpts, dispatchConsumersAsync: true);

        using var connection = factory.CreateConnection("clinical-sync-consumer");
        using var channel = connection.CreateModel();
        channel.BasicQos(0, prefetchCount: 5, global: false);

        var consumer = new AsyncEventingBasicConsumer(channel);
        consumer.Received += async (_, ea) =>
        {
            try
            {
                await HandleMessageAsync(channel, ea, stoppingToken);
            }
            catch (JsonException ex)
            {
                _logger.LogError(ex, "Invalid sync batch message — NACK no requeue");
                channel.BasicNack(ea.DeliveryTag, false, requeue: false);
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, "Sync batch consumer failed — NACK requeue");
                channel.BasicNack(ea.DeliveryTag, false, requeue: true);
            }
        };

        channel.BasicConsume(RabbitMqTopologyProvisioner.SyncBatchQueue, autoAck: false, consumer);
        _logger.LogInformation("ClinicalSyncBatchConsumer consuming {Queue}", RabbitMqTopologyProvisioner.SyncBatchQueue);

        await Task.Delay(Timeout.Infinite, stoppingToken);
    }

    private async Task HandleMessageAsync(IModel channel, BasicDeliverEventArgs ea, CancellationToken ct)
    {
        var payload = Encoding.UTF8.GetString(ea.Body.Span);
        var doc = JsonDocument.Parse(payload);
        var batchId = Guid.Parse(doc.RootElement.GetProperty("batchId").GetString()!);

        await using var scope = _scopes.CreateAsyncScope();
        var processor = scope.ServiceProvider.GetRequiredService<ClinicalSyncBatchProcessor>();
        await processor.ProcessBatchAsync(batchId, ct);

        channel.BasicAck(ea.DeliveryTag, false);
    }
}