using System.Text.Json;
using Microsoft.EntityFrameworkCore;
using StackExchange.Redis;

public class ThresholdCacheLoader : IHostedService
{
    private readonly IServiceProvider _services;
    private readonly IConnectionMultiplexer _redis;
    private readonly ILogger<ThresholdCacheLoader> _logger;

    public ThresholdCacheLoader(
        IServiceProvider services,
        IConnectionMultiplexer redis,
        ILogger<ThresholdCacheLoader> logger)
    {
        _services = services;
        _redis = redis;
        _logger = logger;
    }

    public async Task StartAsync(CancellationToken cancellationToken)
    {
        using var scope = _services.CreateScope();
        var db = scope.ServiceProvider.GetRequiredService<AppDbContext>();

        var thresholds = await db.AlertThresholds.ToListAsync(cancellationToken);

        const int maxAttempts = 3;
        int[] backoffMs = [2000, 4000, 8000];

        for (var attempt = 0; attempt < maxAttempts; attempt++)
        {
            try
            {
                var cache = _redis.GetDatabase();
                var batch = cache.CreateBatch();

                foreach (var t in thresholds)
                {
                    var json = JsonSerializer.Serialize(new
                    {
                        t.ObservationCode,
                        t.CriticalLow,
                        t.WarningLow,
                        t.WarningHigh,
                        t.CriticalHigh
                    });
                    _ = batch.StringSetAsync($"threshold:{t.ObservationCode}", json);
                }

                batch.Execute();
                _logger.LogInformation("Loaded {Count} alert thresholds into Redis cache", thresholds.Count);
                return;
            }
            catch (RedisException ex)
            {
                _logger.LogWarning(ex,
                    "Redis unavailable during threshold cache load — attempt {Attempt}/{Max}",
                    attempt + 1, maxAttempts);

                if (attempt < maxAttempts - 1)
                    await Task.Delay(backoffMs[attempt], cancellationToken);
            }
        }

        _logger.LogError(
            "Failed to load thresholds into Redis after {Max} attempts — " +
            "application will start without cache; observation ingest falls back to PostgreSQL",
            maxAttempts);
    }

    public Task StopAsync(CancellationToken cancellationToken) => Task.CompletedTask;
}