using GestionIntegral.Api.Data.Repositories.Contables; using Microsoft.Extensions.Caching.Memory; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Logging; using System; using System.Threading.Tasks; namespace GestionIntegral.Api.Services.Contables { public class PeriodoCerradoValidator : IPeriodoCerradoValidator { private readonly IServiceScopeFactory _scopeFactory; private readonly IMemoryCache _cache; private readonly ILogger _logger; // TTL del cache: ventana stale aceptada por contrato (los cierres son operación rara). private static readonly TimeSpan CacheTtl = TimeSpan.FromMinutes(10); // Singleton consumiendo Scoped (ICierreCuentaCorrienteRepository) → resolver vía IServiceScopeFactory cada lookup. public PeriodoCerradoValidator( IServiceScopeFactory scopeFactory, IMemoryCache cache, ILogger logger) { _scopeFactory = scopeFactory; _cache = cache; _logger = logger; } public async Task EstaCerradoAsync(string destino, int idDestino, int idEmpresa, DateTime fechaOperacion) { // Sólo aplica a Distribuidores. Canillas no tiene cierre por (Canilla + Empresa). if (!string.Equals(destino, "Distribuidores", StringComparison.OrdinalIgnoreCase)) return new PeriodoCerradoResult(false, null, null); var key = CacheKey(idDestino, idEmpresa); var ultimo = await _cache.GetOrCreateAsync(key, async entry => { entry.AbsoluteExpirationRelativeToNow = CacheTtl; using var scope = _scopeFactory.CreateScope(); var repo = scope.ServiceProvider.GetRequiredService(); var cierre = await repo.GetUltimoCierreVigenteAsync(idDestino, idEmpresa); // Cacheamos sólo lo necesario para que la decisión sea rápida. return cierre == null ? null : new CachedUltimoCierre(cierre.IdCierre, cierre.FechaCorte); }); if (ultimo == null) return new PeriodoCerradoResult(false, null, null); // FechaCorte es DATE; comparar en .Date para ignorar componente hora. if (ultimo.FechaCorte.Date >= fechaOperacion.Date) return new PeriodoCerradoResult(true, ultimo.IdCierre, ultimo.FechaCorte); return new PeriodoCerradoResult(false, null, null); } public void InvalidarCache(int idDistribuidor, int idEmpresa) { _cache.Remove(CacheKey(idDistribuidor, idEmpresa)); } private static string CacheKey(int idDestino, int idEmpresa) => $"cierre-ultimo:{idDestino}:{idEmpresa}"; private sealed record CachedUltimoCierre(int IdCierre, DateTime FechaCorte); } }