using System.Text.Json;
using Confluent.Kafka;
using Microsoft.Extensions.Options;

public class WarningAlertService : BackgroundService
{
    private readonly IServiceProvider _services;
    private readonly KafkaOptions _kafkaOptions;
    private readonly ILogger<WarningAlertService> _logger;

    public WarningAlertService(
        IServiceProvider services,
        IOptions<KafkaOptions> kafkaOptions,
        ILogger<WarningAlertService> logger)
    {
        _services = services;
        _kafkaOptions = kafkaOptions.Value;
        _logger = logger;
    }

    protected override async Task ExecuteAsync(CancellationToken stoppingToken)
    {
        var config = new ConsumerConfig
        {
            BootstrapServers = _kafkaOptions.BootstrapServers,
            GroupId = "warning-evaluator",
            AutoOffsetReset = AutoOffsetReset.Earliest,
            EnableAutoCommit = false
        }.ApplySecurity(_kafkaOptions);

        using var consumer = new ConsumerBuilder<string, string>(config).Build();
        consumer.Subscribe(_kafkaOptions.Topics.ObservationRecorded);

        _logger.LogInformation("WarningAlertService started — consumer group: warning-evaluator");

        var guard = new PoisonPillGuard("warning-evaluator", _kafkaOptions.MaxPoisonRetries, _logger);

        try
        {
            while (!stoppingToken.IsCancellationRequested)
            {
                ConsumeResult<string, string>? result = null;
                try
                {
                    result = consumer.Consume(stoppingToken);

                    var evt = JsonSerializer.Deserialize<WarningObservationEvent>(
                        result.Message.Value,
                        new JsonSerializerOptions { PropertyNameCaseInsensitive = true })!;

                    using var scope = _services.CreateScope();
                    var evaluator = scope.ServiceProvider.GetRequiredService<WarningEvaluator>();

                    await evaluator.EvaluateAsync(
                        evt.ObservationId,
                        evt.EncounterId,
                        evt.PatientId,
                        evt.ObservationCode,
                        evt.Value,
                        stoppingToken);

                    consumer.Commit(result);
                    guard.OnSuccess();
                }
                catch (OperationCanceledException)
                {
                    break;
                }
                catch (Exception ex)
                {
                    if (result is not null && guard.ShouldSkip(result, ex))
                    {
                        consumer.Commit(result);
                        continue;
                    }

                    _logger.LogError(ex,
                        "WarningAlertService failed on topic={Topic} offset={Offset} — will retry",
                        result?.Topic, result?.Offset.Value);
                    await Task.Delay(2000, stoppingToken);
                }
            }
        }
        finally
        {
            consumer.Close();
        }
    }
}