using Elecciones.Database;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using System;
using System.Collections.Generic;
using System.Threading.Tasks;

namespace Elecciones.Infrastructure.Services;

public class WorkerSettings
{
    public bool ResultadosActivado { get; set; } = true;
    public bool BajasActivado { get; set; } = true;
    public string Prioridad { get; set; } = "Resultados";
}

public class WorkerConfigService
{
    private readonly IServiceProvider _serviceProvider;
    private readonly ILogger<WorkerConfigService> _logger;
    private WorkerSettings _cachedSettings = new();
    private DateTime _lastFetchTime = DateTime.MinValue;
    private readonly TimeSpan _cacheDuration = TimeSpan.FromSeconds(25); // Cachear por 25 segundos
    private readonly SemaphoreSlim _semaphore = new(1, 1);

    public WorkerConfigService(IServiceProvider serviceProvider, ILogger<WorkerConfigService> logger)
    {
        _serviceProvider = serviceProvider;
        _logger = logger;
    }

    public async Task<WorkerSettings> GetSettingsAsync()
    {
        // Si el caché es válido, lo devolvemos inmediatamente.
        if (DateTime.UtcNow < _lastFetchTime + _cacheDuration)
        {
            return _cachedSettings;
        }

        // Si el caché ha expirado, intentamos obtener el control para actualizarlo.
        await _semaphore.WaitAsync();
        try
        {
            // Volvemos a comprobar por si otra tarea ya actualizó el caché mientras esperábamos.
            if (DateTime.UtcNow < _lastFetchTime + _cacheDuration)
            {
                return _cachedSettings;
            }
            
            _logger.LogInformation("Caché de configuración del worker expirado. Actualizando desde la BD...");

            using var scope = _serviceProvider.CreateScope();
            var dbContext = scope.ServiceProvider.GetRequiredService<EleccionesDbContext>();
            
            var configMap = await dbContext.Configuraciones.AsNoTracking().ToDictionaryAsync(c => c.Clave, c => c.Valor);

            _cachedSettings = new WorkerSettings
            {
                ResultadosActivado = configMap.GetValueOrDefault("Worker_Resultados_Activado", "true") == "true",
                BajasActivado = configMap.GetValueOrDefault("Worker_Bajas_Activado", "true") == "true",
                Prioridad = configMap.GetValueOrDefault("Worker_Prioridad", "Resultados") ?? "Resultados"
            };

            _lastFetchTime = DateTime.UtcNow;
            _logger.LogInformation("Configuración del worker actualizada: Resultados={res}, Bajas={bajas}, Prioridad={prio}", 
                _cachedSettings.ResultadosActivado, _cachedSettings.BajasActivado, _cachedSettings.Prioridad);
        }
        catch (Exception ex)
        {
            _logger.LogError(ex, "No se pudo actualizar la configuración del worker desde la BD. Usando la última configuración cacheada.");
        }
        finally
        {
            _semaphore.Release();
        }

        return _cachedSettings;
    }
}