using Dapper;
using GestionIntegral.Api.Dtos.Reportes;
using Microsoft.Extensions.Logging;
using System;
using System.Collections.Generic;
using System.Data;
using System.Linq;
using System.Threading.Tasks;

namespace GestionIntegral.Api.Data.Repositories.Reportes
{
    public class ReportesRepository : IReportesRepository
    {
        private readonly DbConnectionFactory _dbConnectionFactory;
        private readonly ILogger<ReportesRepository> _logger;

        public ReportesRepository(DbConnectionFactory dbConnectionFactory, ILogger<ReportesRepository> logger)
        {
            _dbConnectionFactory = dbConnectionFactory;
            _logger = logger;
        }

        public async Task<IEnumerable<ExistenciaPapelDto>> GetExistenciaPapelAsync(DateTime fechaDesde, DateTime fechaHasta, int? idPlanta, bool consolidado)
        {
            string spName = consolidado ? "dbo.SP_ConsumoBobinasConsolidado" : "dbo.SP_ConsumoBobinas";
            var parameters = new DynamicParameters();

            parameters.Add("FechaDesde", fechaDesde, DbType.Date);
            parameters.Add("FechaHasta", fechaHasta, DbType.Date);

            if (!consolidado)
            {
                if (!idPlanta.HasValue)
                {
                    throw new ArgumentNullException(nameof(idPlanta), "El ID de planta es requerido para el reporte no consolidado de existencia de papel.");
                }
                parameters.Add("@idPlanta", idPlanta.Value, DbType.Int32);
            }


            _logger.LogInformation("Ejecutando SP: {SPName} con parámetros: FechaDesde={FechaDesde}, FechaHasta={FechaHasta}, IdPlanta={IdPlanta}, Consolidado={Consolidado}",
                spName, fechaDesde, fechaHasta, idPlanta, consolidado);

            try
            {
                using var connection = _dbConnectionFactory.CreateConnection();
                var result = await connection.QueryAsync<ExistenciaPapelDto>(spName, parameters, commandType: CommandType.StoredProcedure, commandTimeout: 120);
                _logger.LogInformation("SP {SPName} ejecutado, {Count} filas devueltas.", spName, result.Count());
                return result;
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, "Error al ejecutar SP {SPName} para Existencia de Papel.", spName);
                return Enumerable.Empty<ExistenciaPapelDto>();
            }
        }

        public async Task<IEnumerable<MovimientoBobinasDto>> GetMovimientoBobinasAsync(DateTime fechaInicio, int diasPeriodo, int idPlanta)
        {
            const string spName = "dbo.SP_MovimientoBobinas";
            var parameters = new DynamicParameters();
            parameters.Add("@FechaInicio", fechaInicio, DbType.Date); // El SP espera DateTime
            parameters.Add("@DiasPeriodo", diasPeriodo, DbType.Int32);
            parameters.Add("@idPlanta", idPlanta, DbType.Int32);

            _logger.LogInformation("Ejecutando SP: {SPName} con parámetros: FechaInicio={FechaInicio}, DiasPeriodo={DiasPeriodo}, IdPlanta={IdPlanta}",
                spName, fechaInicio, diasPeriodo, idPlanta);
            try
            {
                using var connection = _dbConnectionFactory.CreateConnection();
                return await connection.QueryAsync<MovimientoBobinasDto>(spName, parameters, commandType: CommandType.StoredProcedure, commandTimeout: 120);
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, "Error al ejecutar SP {SPName} para Movimiento de Bobinas.", spName);
                return Enumerable.Empty<MovimientoBobinasDto>();
            }
        }
        public async Task<IEnumerable<DevueltosOtrosDiasDto>> GetEntradaSalidaOtrosDiasAsync(DateTime fecha, int idEmpresa)
        {
            using var conn = _dbConnectionFactory.CreateConnection() as IDbConnection;
            // si no es IDbConnection, haz conn.Open() manual
            var parametros = new { fecha, idEmpresa };
            return await conn.QueryAsync<DevueltosOtrosDiasDto>(
                "SP_DistCanillasCantidadEntradaSalidaOtrosDias",
                parametros,
                commandType: CommandType.StoredProcedure, commandTimeout: 120
            );
        }

        public async Task<IEnumerable<MovimientoBobinaEstadoDetalleDto>> GetMovimientoBobinasEstadoDetalleAsync(DateTime fechaInicio, DateTime fechaFin, int idPlanta)
        {
            const string spName = "dbo.SP_MovimientosBobinasEstado";
            var parameters = new DynamicParameters();
            parameters.Add("@FechaInicio", fechaInicio, DbType.Date);
            parameters.Add("@FechaFin", fechaFin, DbType.Date);
            parameters.Add("@IdPlanta", idPlanta, DbType.Int32);

            _logger.LogInformation("Ejecutando SP: {SPName} con parámetros: FechaInicio={FechaInicio}, FechaFin={FechaFin}, IdPlanta={IdPlanta}",
                spName, fechaInicio, fechaFin, idPlanta);
            try
            {
                using var connection = _dbConnectionFactory.CreateConnection();
                return await connection.QueryAsync<MovimientoBobinaEstadoDetalleDto>(spName, parameters, commandType: CommandType.StoredProcedure, commandTimeout: 120);
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, "Error al ejecutar SP {SPName} para Detalle de Movimiento de Bobinas por Estado.", spName);
                return Enumerable.Empty<MovimientoBobinaEstadoDetalleDto>();
            }
        }

        public async Task<IEnumerable<MovimientoBobinaEstadoTotalDto>> GetMovimientoBobinasEstadoTotalesAsync(DateTime fechaInicio, DateTime fechaFin, int idPlanta)
        {
            const string spName = "dbo.SP_MovimientosBobinasEstadoTotales";
            var parameters = new DynamicParameters();
            parameters.Add("@FechaInicio", fechaInicio, DbType.Date);
            parameters.Add("@FechaFin", fechaFin, DbType.Date);
            parameters.Add("@IdPlanta", idPlanta, DbType.Int32);

            _logger.LogInformation("Ejecutando SP: {SPName} con parámetros: FechaInicio={FechaInicio}, FechaFin={FechaFin}, IdPlanta={IdPlanta}",
                spName, fechaInicio, fechaFin, idPlanta);
            try
            {
                using var connection = _dbConnectionFactory.CreateConnection();
                return await connection.QueryAsync<MovimientoBobinaEstadoTotalDto>(spName, parameters, commandType: CommandType.StoredProcedure, commandTimeout: 120);
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, "Error al ejecutar SP {SPName} para Totales de Movimiento de Bobinas por Estado.", spName);
                return Enumerable.Empty<MovimientoBobinaEstadoTotalDto>();
            }
        }

        public async Task<IEnumerable<ListadoDistribucionGeneralResumenDto>> GetListadoDistribucionGeneralResumenAsync(int idPublicacion, DateTime fechaDesde, DateTime fechaHasta)
        {
            const string spName = "dbo.SP_DistObtenerResumenMensual";
            var parameters = new DynamicParameters();
            parameters.Add("@Id_Publicacion", idPublicacion, DbType.Int32);
            parameters.Add("@Mes", fechaDesde.Month, DbType.Int32);
            parameters.Add("@Anio", fechaDesde.Year, DbType.Int32);
            // El SP no usa fechaHasta explícitamente, calcula el fin de mes internamente
            try { using var connection = _dbConnectionFactory.CreateConnection(); return await connection.QueryAsync<ListadoDistribucionGeneralResumenDto>(spName, parameters, commandType: CommandType.StoredProcedure, commandTimeout: 120); }
            catch (Exception ex) { _logger.LogError(ex, "Error SP {SPName}", spName); return Enumerable.Empty<ListadoDistribucionGeneralResumenDto>(); }
        }

        public async Task<IEnumerable<ListadoDistribucionGeneralPromedioDiaDto>> GetListadoDistribucionGeneralPromedioDiaAsync(int idPublicacion, DateTime fechaDesde, DateTime fechaHasta)
        {
            const string spName = "dbo.SP_DistObtenerResumenMensualPorDiaSemana";
            var parameters = new DynamicParameters();
            parameters.Add("@Id_Publicacion", idPublicacion, DbType.Int32);
            parameters.Add("@Mes", fechaDesde.Month, DbType.Int32);
            parameters.Add("@Anio", fechaDesde.Year, DbType.Int32);
            try { using var connection = _dbConnectionFactory.CreateConnection(); return await connection.QueryAsync<ListadoDistribucionGeneralPromedioDiaDto>(spName, parameters, commandType: CommandType.StoredProcedure, commandTimeout: 120); }
            catch (Exception ex) { _logger.LogError(ex, "Error SP {SPName}", spName); return Enumerable.Empty<ListadoDistribucionGeneralPromedioDiaDto>(); }
        }

        public async Task<IEnumerable<ListadoDistribucionCanillasSimpleDto>> GetListadoDistribucionCanillasSimpleAsync(int idPublicacion, DateTime fechaDesde, DateTime fechaHasta)
        {
            const string spName = "dbo.SP_CantidadEntradaSalidaCanillas";
            var parameters = new DynamicParameters();
            parameters.Add("@idPublicacion", idPublicacion, DbType.Int32);
            parameters.Add("@fechaDesde", fechaDesde, DbType.DateTime);
            parameters.Add("@fechaHasta", fechaHasta, DbType.DateTime);
            try { using var connection = _dbConnectionFactory.CreateConnection(); return await connection.QueryAsync<ListadoDistribucionCanillasSimpleDto>(spName, parameters, commandType: CommandType.StoredProcedure, commandTimeout: 120); }
            catch (Exception ex) { _logger.LogError(ex, "Error SP {SPName}", spName); return Enumerable.Empty<ListadoDistribucionCanillasSimpleDto>(); }
        }

        public async Task<IEnumerable<ListadoDistribucionCanillasPromedioDiaDto>> GetListadoDistribucionCanillasPromedioDiaAsync(int idPublicacion, DateTime fechaDesde, DateTime fechaHasta)
        {
            const string spName = "dbo.SP_CantidadEntradaSalidaCPromAgDiaCanilla";
            var parameters = new DynamicParameters();
            parameters.Add("@idPublicacion", idPublicacion, DbType.Int32);
            parameters.Add("@fechaDesde", fechaDesde, DbType.DateTime);
            parameters.Add("@fechaHasta", fechaHasta, DbType.DateTime);
            try { using var connection = _dbConnectionFactory.CreateConnection(); return await connection.QueryAsync<ListadoDistribucionCanillasPromedioDiaDto>(spName, parameters, commandType: CommandType.StoredProcedure, commandTimeout: 120); }
            catch (Exception ex) { _logger.LogError(ex, "Error SP {SPName}", spName); return Enumerable.Empty<ListadoDistribucionCanillasPromedioDiaDto>(); }
        }

        public async Task<IEnumerable<ListadoDistribucionCanillasImporteDto>> GetListadoDistribucionCanillasImporteAsync(int idPublicacion, DateTime fechaDesde, DateTime fechaHasta, bool esAccionista)
        {
            const string spName = "dbo.SP_CantidadESCanillasConImporte";
            var parameters = new DynamicParameters();
            parameters.Add("@idPublicacion", idPublicacion, DbType.Int32);
            parameters.Add("@fechaDesde", fechaDesde, DbType.DateTime);
            parameters.Add("@fechaHasta", fechaHasta, DbType.DateTime);
            parameters.Add("@accionista", esAccionista, DbType.Boolean);
            try { using var connection = _dbConnectionFactory.CreateConnection(); return await connection.QueryAsync<ListadoDistribucionCanillasImporteDto>(spName, parameters, commandType: CommandType.StoredProcedure, commandTimeout: 120); }
            catch (Exception ex) { _logger.LogError(ex, "Error SP {SPName}", spName); return Enumerable.Empty<ListadoDistribucionCanillasImporteDto>(); }
        }

        public async Task<IEnumerable<VentaMensualSecretariaElDiaDto>> GetVentaMensualSecretariaElDiaAsync(DateTime fechaDesde, DateTime fechaHasta)
        {
            const string spName = "dbo.SP_VentaMensualSecretariaElDia";
            var parameters = new DynamicParameters();
            parameters.Add("@fechaDesde", fechaDesde, DbType.DateTime);
            parameters.Add("@fechaHasta", fechaHasta, DbType.DateTime);
            try { using var connection = _dbConnectionFactory.CreateConnection(); return await connection.QueryAsync<VentaMensualSecretariaElDiaDto>(spName, parameters, commandType: CommandType.StoredProcedure, commandTimeout: 120); }
            catch (Exception ex) { _logger.LogError(ex, "Error SP {SPName}", spName); return Enumerable.Empty<VentaMensualSecretariaElDiaDto>(); }
        }

        public async Task<IEnumerable<VentaMensualSecretariaElPlataDto>> GetVentaMensualSecretariaElPlataAsync(DateTime fechaDesde, DateTime fechaHasta)
        {
            const string spName = "dbo.SP_VentaMensualSecretariaElPlata";
            var parameters = new DynamicParameters();
            parameters.Add("@fechaDesde", fechaDesde, DbType.DateTime);
            parameters.Add("@fechaHasta", fechaHasta, DbType.DateTime);
            try { using var connection = _dbConnectionFactory.CreateConnection(); return await connection.QueryAsync<VentaMensualSecretariaElPlataDto>(spName, parameters, commandType: CommandType.StoredProcedure, commandTimeout: 120); }
            catch (Exception ex) { _logger.LogError(ex, "Error SP {SPName}", spName); return Enumerable.Empty<VentaMensualSecretariaElPlataDto>(); }
        }

        public async Task<IEnumerable<VentaMensualSecretariaTirDevoDto>> GetVentaMensualSecretariaTirDevoAsync(DateTime fechaDesde, DateTime fechaHasta)
        {
            const string spName = "dbo.SP_VentaMensualSecretariaTirDevo";
            var parameters = new DynamicParameters();
            parameters.Add("@fechaDesde", fechaDesde, DbType.DateTime);
            parameters.Add("@fechaHasta", fechaHasta, DbType.DateTime);
            try { using var connection = _dbConnectionFactory.CreateConnection(); return await connection.QueryAsync<VentaMensualSecretariaTirDevoDto>(spName, parameters, commandType: CommandType.StoredProcedure, commandTimeout: 120); }
            catch (Exception ex) { _logger.LogError(ex, "Error SP {SPName}", spName); return Enumerable.Empty<VentaMensualSecretariaTirDevoDto>(); }
        }

        public async Task<IEnumerable<DetalleDistribucionCanillaDto>> GetDetalleDistribucionCanillasPubliAsync(DateTime fecha, int idEmpresa)
        {
            const string spName = "dbo.SP_DistCanillasEntradaSalidaPubli";
            var parameters = new DynamicParameters();
            parameters.Add("@fecha", fecha, DbType.DateTime);
            parameters.Add("@idEmpresa", idEmpresa, DbType.Int32);
            try { using var connection = _dbConnectionFactory.CreateConnection(); return await connection.QueryAsync<DetalleDistribucionCanillaDto>(spName, parameters, commandType: CommandType.StoredProcedure, commandTimeout: 120); }
            catch (Exception ex) { _logger.LogError(ex, "Error SP {SPName}", spName); return Enumerable.Empty<DetalleDistribucionCanillaDto>(); }
        }

        public async Task<IEnumerable<DetalleDistribucionCanillaDto>> GetDetalleDistribucionCanillasAccPubliAsync(DateTime fecha, int idEmpresa)
        {
            const string spName = "dbo.SP_DistCanillasAccEntradaSalidaPubli";
            var parameters = new DynamicParameters();
            parameters.Add("@fecha", fecha, DbType.DateTime);
            parameters.Add("@idEmpresa", idEmpresa, DbType.Int32);
            try { using var connection = _dbConnectionFactory.CreateConnection(); return await connection.QueryAsync<DetalleDistribucionCanillaDto>(spName, parameters, commandType: CommandType.StoredProcedure, commandTimeout: 120); }
            catch (Exception ex) { _logger.LogError(ex, "Error SP {SPName}", spName); return Enumerable.Empty<DetalleDistribucionCanillaDto>(); }
        }

        public async Task<IEnumerable<DetalleDistribucionCanillaAllDto>> GetDetalleDistribucionCanillasAllPubliAsync(DateTime fecha, int idEmpresa)
        {
            const string spName = "dbo.SP_DistCanALLEntradaSalidaPubli";
            var parameters = new DynamicParameters();
            parameters.Add("@fecha", fecha, DbType.DateTime);
            parameters.Add("@idEmpresa", idEmpresa, DbType.Int32);
            try { using var connection = _dbConnectionFactory.CreateConnection(); return await connection.QueryAsync<DetalleDistribucionCanillaAllDto>(spName, parameters, commandType: CommandType.StoredProcedure, commandTimeout: 120); }
            catch (Exception ex) { _logger.LogError(ex, "Error SP {SPName}", spName); return Enumerable.Empty<DetalleDistribucionCanillaAllDto>(); }
        }

        public async Task<IEnumerable<DetalleDistribucionCanillaDto>> GetDetalleDistribucionCanillasPubliFechaLiqAsync(DateTime fechaLiquidacion, int idEmpresa)
        {
            const string spName = "dbo.SP_DistCanillasEntradaSalidaPubliFechaLiq";
            var parameters = new DynamicParameters();
            parameters.Add("@fecha", fechaLiquidacion, DbType.DateTime);
            parameters.Add("@idEmpresa", idEmpresa, DbType.Int32);
            try { using var connection = _dbConnectionFactory.CreateConnection(); return await connection.QueryAsync<DetalleDistribucionCanillaDto>(spName, parameters, commandType: CommandType.StoredProcedure, commandTimeout: 120); }
            catch (Exception ex) { _logger.LogError(ex, "Error SP {SPName}", spName); return Enumerable.Empty<DetalleDistribucionCanillaDto>(); }
        }

        public async Task<IEnumerable<DetalleDistribucionCanillaDto>> GetDetalleDistribucionCanillasAccPubliFechaLiqAsync(DateTime fechaLiquidacion, int idEmpresa)
        {
            const string spName = "dbo.SP_DistCanillasAccEntradaSalidaPubliFechaLiq";
            var parameters = new DynamicParameters();
            parameters.Add("@fecha", fechaLiquidacion, DbType.DateTime);
            parameters.Add("@idEmpresa", idEmpresa, DbType.Int32);
            try { using var connection = _dbConnectionFactory.CreateConnection(); return await connection.QueryAsync<DetalleDistribucionCanillaDto>(spName, parameters, commandType: CommandType.StoredProcedure, commandTimeout: 120); }
            catch (Exception ex) { _logger.LogError(ex, "Error SP {SPName}", spName); return Enumerable.Empty<DetalleDistribucionCanillaDto>(); }
        }

        public async Task<IEnumerable<ObtenerCtrlDevolucionesDto>> GetReporteObtenerCtrlDevolucionesAsync(DateTime fecha, int idEmpresa)
        {
            const string spName = "dbo.SP_ObtenerCtrlDevoluciones";
            var parameters = new DynamicParameters();
            parameters.Add("@Fecha", fecha, DbType.DateTime);
            parameters.Add("@IdEmpresa", idEmpresa, DbType.Int32);
            try { using var connection = _dbConnectionFactory.CreateConnection(); return await connection.QueryAsync<ObtenerCtrlDevolucionesDto>(spName, parameters, commandType: CommandType.StoredProcedure, commandTimeout: 120); }
            catch (Exception ex) { _logger.LogError(ex, "Error SP {SPName}", spName); return Enumerable.Empty<ObtenerCtrlDevolucionesDto>(); }
        }

        public async Task<IEnumerable<ControlDevolucionesReporteDto>> GetReporteCtrlDevolucionesParaDistCanAsync(DateTime fecha, int idEmpresa)
        {
            const string spName = "dbo.SP_DistCanillasCantidadEntradaSalida";
            var parameters = new DynamicParameters();
            parameters.Add("@fecha", fecha, DbType.DateTime);
            parameters.Add("@idEmpresa", idEmpresa, DbType.Int32);
            try { using var connection = _dbConnectionFactory.CreateConnection(); return await connection.QueryAsync<ControlDevolucionesReporteDto>(spName, parameters, commandType: CommandType.StoredProcedure, commandTimeout: 120); }
            catch (Exception ex) { _logger.LogError(ex, "Error SP {SPName}", spName); return Enumerable.Empty<ControlDevolucionesReporteDto>(); }
        }

        public async Task<IEnumerable<TiradasPublicacionesSeccionesDto>> GetTiradasPublicacionesSeccionesAsync(int idPublicacion, DateTime fechaDesde, DateTime fechaHasta, int idPlanta)
        {
            const string spName = "dbo.SP_TiradasPublicacionesSecciones";
            var parameters = new DynamicParameters();
            parameters.Add("@IdPublicacion", idPublicacion, DbType.Int32);
            parameters.Add("@FechaInicio", fechaDesde, DbType.Date);
            parameters.Add("@FechaFin", fechaHasta, DbType.Date);
            parameters.Add("@IdPlanta", idPlanta, DbType.Int32);
            try { using var connection = _dbConnectionFactory.CreateConnection(); return await connection.QueryAsync<TiradasPublicacionesSeccionesDto>(spName, parameters, commandType: CommandType.StoredProcedure, commandTimeout: 120); }
            catch (Exception ex) { _logger.LogError(ex, "Error SP {SPName}", spName); return Enumerable.Empty<TiradasPublicacionesSeccionesDto>(); }
        }

        public async Task<IEnumerable<TiradasPublicacionesSeccionesDto>> GetTiradasPublicacionesSeccionesConsolidadoAsync(int idPublicacion, DateTime fechaDesde, DateTime fechaHasta)
        {
            const string spName = "dbo.SP_TiradasPublicacionesSeccionesConsolidado";
            var parameters = new DynamicParameters();
            parameters.Add("@IdPublicacion", idPublicacion, DbType.Int32);
            parameters.Add("@FechaInicio", fechaDesde, DbType.Date);
            parameters.Add("@FechaFin", fechaHasta, DbType.Date);
            try { using var connection = _dbConnectionFactory.CreateConnection(); return await connection.QueryAsync<TiradasPublicacionesSeccionesDto>(spName, parameters, commandType: CommandType.StoredProcedure, commandTimeout: 120); }
            catch (Exception ex) { _logger.LogError(ex, "Error SP {SPName}", spName); return Enumerable.Empty<TiradasPublicacionesSeccionesDto>(); }
        }

        public async Task<IEnumerable<ConsumoBobinasSeccionDto>> GetConsumoBobinasPorSeccionAsync(DateTime fechaDesde, DateTime fechaHasta, int idPlanta)
        {
            const string spName = "dbo.SP_BobinasUtilizadasPorSeccion";
            var parameters = new DynamicParameters();
            parameters.Add("@FechaInicio", fechaDesde, DbType.DateTime2);
            parameters.Add("@FechaFin", fechaHasta, DbType.DateTime2);
            parameters.Add("@idPlanta", idPlanta, DbType.Int32);
            try { using var connection = _dbConnectionFactory.CreateConnection(); return await connection.QueryAsync<ConsumoBobinasSeccionDto>(spName, parameters, commandType: CommandType.StoredProcedure, commandTimeout: 120); }
            catch (Exception ex) { _logger.LogError(ex, "Error SP {SPName}", spName); return Enumerable.Empty<ConsumoBobinasSeccionDto>(); }
        }

        public async Task<IEnumerable<ConsumoBobinasSeccionDto>> GetConsumoBobinasPorSeccionConsolidadoAsync(DateTime fechaDesde, DateTime fechaHasta)
        {
            const string spName = "dbo.SP_BobinasUtilizadasPorSeccionConsolidado";
            var parameters = new DynamicParameters();
            parameters.Add("@FechaInicio", fechaDesde, DbType.DateTime2);
            parameters.Add("@FechaFin", fechaHasta, DbType.DateTime2);
            try { using var connection = _dbConnectionFactory.CreateConnection(); return await connection.QueryAsync<ConsumoBobinasSeccionDto>(spName, parameters, commandType: CommandType.StoredProcedure, commandTimeout: 120); }
            catch (Exception ex) { _logger.LogError(ex, "Error SP {SPName}", spName); return Enumerable.Empty<ConsumoBobinasSeccionDto>(); }
        }

        public async Task<IEnumerable<ConsumoBobinasPublicacionDto>> GetConsumoBobinasPorPublicacionAsync(DateTime fechaDesde, DateTime fechaHasta)
        {
            const string spName = "dbo.SP_BobinasUtilizadasPorPublicacion";
            var parameters = new DynamicParameters();
            parameters.Add("@FechaInicio", fechaDesde, DbType.DateTime2);
            parameters.Add("@FechaFin", fechaHasta, DbType.DateTime2);
            try { using var connection = _dbConnectionFactory.CreateConnection(); return await connection.QueryAsync<ConsumoBobinasPublicacionDto>(spName, parameters, commandType: CommandType.StoredProcedure, commandTimeout: 120); }
            catch (Exception ex) { _logger.LogError(ex, "Error SP {SPName}", spName); return Enumerable.Empty<ConsumoBobinasPublicacionDto>(); }
        }

        public async Task<IEnumerable<ComparativaConsumoBobinasDto>> GetComparativaConsumoBobinasAsync(DateTime fechaInicioMesA, DateTime fechaFinMesA, DateTime fechaInicioMesB, DateTime fechaFinMesB, int idPlanta)
        {
            const string spName = "dbo.SP_CompararConsumoBobinasMeses";
            var parameters = new DynamicParameters();
            parameters.Add("@FechaInicioMesA", fechaInicioMesA, DbType.Date);
            parameters.Add("@FechaFinMesA", fechaFinMesA, DbType.Date);
            parameters.Add("@FechaInicioMesB", fechaInicioMesB, DbType.Date);
            parameters.Add("@FechaFinMesB", fechaFinMesB, DbType.Date);
            parameters.Add("@IdPlanta", idPlanta, DbType.Int32);
            try { using var connection = _dbConnectionFactory.CreateConnection(); return await connection.QueryAsync<ComparativaConsumoBobinasDto>(spName, parameters, commandType: CommandType.StoredProcedure, commandTimeout: 120); }
            catch (Exception ex) { _logger.LogError(ex, "Error SP {SPName}", spName); return Enumerable.Empty<ComparativaConsumoBobinasDto>(); }
        }

        public async Task<IEnumerable<ComparativaConsumoBobinasDto>> GetComparativaConsumoBobinasConsolidadoAsync(DateTime fechaInicioMesA, DateTime fechaFinMesA, DateTime fechaInicioMesB, DateTime fechaFinMesB)
        {
            const string spName = "dbo.SP_CompararConsumoBobinasMesesConsolidado";
            var parameters = new DynamicParameters();
            parameters.Add("@FechaInicioMesA", fechaInicioMesA, DbType.Date);
            parameters.Add("@FechaFinMesA", fechaFinMesA, DbType.Date);
            parameters.Add("@FechaInicioMesB", fechaInicioMesB, DbType.Date);
            parameters.Add("@FechaFinMesB", fechaFinMesB, DbType.Date);
            try { using var connection = _dbConnectionFactory.CreateConnection(); return await connection.QueryAsync<ComparativaConsumoBobinasDto>(spName, parameters, commandType: CommandType.StoredProcedure, commandTimeout: 120); }
            catch (Exception ex) { _logger.LogError(ex, "Error SP {SPName}", spName); return Enumerable.Empty<ComparativaConsumoBobinasDto>(); }
        }

        // Implementación para SP_BalanceCuentaDistEntradaSalidaPorEmpresa
        public async Task<IEnumerable<BalanceCuentaDistDto>> GetBalanceCuentaDistEntradaSalidaPorEmpresaAsync(int idDistribuidor, int idEmpresa, DateTime fechaDesde, DateTime fechaHasta)
        {
            const string spName = "dbo.SP_BalanceCuentaDistEntradaSalidaPorEmpresa";
            var parameters = new DynamicParameters();
            parameters.Add("@idDistribuidor", idDistribuidor, DbType.Int32);
            parameters.Add("@idEmpresa", idEmpresa, DbType.Int32);
            parameters.Add("@fechaDesde", fechaDesde, DbType.DateTime);
            parameters.Add("@fechaHasta", fechaHasta, DbType.DateTime);
            try { using var connection = _dbConnectionFactory.CreateConnection(); return await connection.QueryAsync<BalanceCuentaDistDto>(spName, parameters, commandType: CommandType.StoredProcedure, commandTimeout: 120); }
            catch (Exception ex) { _logger.LogError(ex, "Error SP {SPName}", spName); return Enumerable.Empty<BalanceCuentaDistDto>(); }
        }

        // Implementación para SP_BalanceCuentDistDebCredEmpresa
        public async Task<IEnumerable<BalanceCuentaDebCredDto>> GetBalanceCuentDistDebCredEmpresaAsync(int idDistribuidor, int idEmpresa, DateTime fechaDesde, DateTime fechaHasta)
        {
            const string spName = "dbo.SP_BalanceCuentDistDebCredEmpresa";
            var parameters = new DynamicParameters();
            parameters.Add("@idDistribuidor", idDistribuidor, DbType.Int32);
            parameters.Add("@idEmpresa", idEmpresa, DbType.Int32);
            parameters.Add("@fechaDesde", fechaDesde, DbType.DateTime);
            parameters.Add("@fechaHasta", fechaHasta, DbType.DateTime);
            try { using var connection = _dbConnectionFactory.CreateConnection(); return await connection.QueryAsync<BalanceCuentaDebCredDto>(spName, parameters, commandType: CommandType.StoredProcedure, commandTimeout: 120); }
            catch (Exception ex) { _logger.LogError(ex, "Error SP {SPName}", spName); return Enumerable.Empty<BalanceCuentaDebCredDto>(); }
        }

        // Implementación para SP_BalanceCuentDistPagosEmpresa
        public async Task<IEnumerable<BalanceCuentaPagosDto>> GetBalanceCuentDistPagosEmpresaAsync(int idDistribuidor, int idEmpresa, DateTime fechaDesde, DateTime fechaHasta)
        {
            const string spName = "dbo.SP_BalanceCuentDistPagosEmpresa";
            var parameters = new DynamicParameters();
            parameters.Add("@idDistribuidor", idDistribuidor, DbType.Int32);
            parameters.Add("@idEmpresa", idEmpresa, DbType.Int32);
            parameters.Add("@fechaDesde", fechaDesde, DbType.DateTime);
            parameters.Add("@fechaHasta", fechaHasta, DbType.DateTime);
            try { using var connection = _dbConnectionFactory.CreateConnection(); return await connection.QueryAsync<BalanceCuentaPagosDto>(spName, parameters, commandType: CommandType.StoredProcedure, commandTimeout: 120); }
            catch (Exception ex) { _logger.LogError(ex, "Error SP {SPName}", spName); return Enumerable.Empty<BalanceCuentaPagosDto>(); }
        }

        // Implementación para SP_BalanceCuentSaldosEmpresas
        public async Task<IEnumerable<SaldoDto>> GetBalanceCuentSaldosEmpresasAsync(string destino, int idDestino, int idEmpresa)
        {
            const string spName = "dbo.SP_BalanceCuentSaldosEmpresas";
            var parameters = new DynamicParameters();
            parameters.Add("@Destino", destino, DbType.String);
            parameters.Add("@idDestino", idDestino, DbType.Int32);
            parameters.Add("@idEmpresa", idEmpresa, DbType.Int32);
            try { using var connection = _dbConnectionFactory.CreateConnection(); return await connection.QueryAsync<SaldoDto>(spName, parameters, commandType: CommandType.StoredProcedure, commandTimeout: 120); }
            catch (Exception ex) { _logger.LogError(ex, "Error SP {SPName}", spName); return Enumerable.Empty<SaldoDto>(); }
        }

        public async Task<IEnumerable<ListadoDistribucionDistSimpleDto>> GetListadoDistribucionDistSimpleAsync(int idDistribuidor, int idPublicacion, DateTime fechaDesde, DateTime fechaHasta)
        {
            const string spName = "dbo.SP_CantidadEntradaSalida";
            var parameters = new DynamicParameters();
            parameters.Add("@idDistribuidor", idDistribuidor, DbType.Int32);
            parameters.Add("@idPublicacion", idPublicacion, DbType.Int32);
            parameters.Add("@fechaDesde", fechaDesde, DbType.DateTime);
            parameters.Add("@fechaHasta", fechaHasta, DbType.DateTime);
            try
            {
                using var connection = _dbConnectionFactory.CreateConnection(); // <--- CORREGIDO AQUÍ
                return await connection.QueryAsync<ListadoDistribucionDistSimpleDto>(spName, parameters, commandType: CommandType.StoredProcedure, commandTimeout: 120);
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, "Error al ejecutar SP {SPName} para Listado Distribucion Distribuidores (Simple). Params: Dist={idDistribuidor}, Pub={idPublicacion}, Desde={fechaDesde}, Hasta={fechaHasta}", spName, idDistribuidor, idPublicacion, fechaDesde, fechaHasta);
                return Enumerable.Empty<ListadoDistribucionDistSimpleDto>();
            }
        }

        public async Task<IEnumerable<ListadoDistribucionDistPromedioDiaDto>> GetListadoDistribucionDistPromedioDiaAsync(int idDistribuidor, int idPublicacion, DateTime fechaDesde, DateTime fechaHasta)
        {
            const string spName = "dbo.SP_CantidadEntradaSalidaCPromAgDia";
            var parameters = new DynamicParameters();
            parameters.Add("@idDistribuidor", idDistribuidor, DbType.Int32);
            parameters.Add("@idPublicacion", idPublicacion, DbType.Int32);
            parameters.Add("@fechaDesde", fechaDesde, DbType.DateTime);
            parameters.Add("@fechaHasta", fechaHasta, DbType.DateTime);
            try
            {
                using var connection = _dbConnectionFactory.CreateConnection(); // <--- CORREGIDO AQUÍ
                return await connection.QueryAsync<ListadoDistribucionDistPromedioDiaDto>(spName, parameters, commandType: CommandType.StoredProcedure, commandTimeout: 120);
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, "Error al ejecutar SP {SPName} para Listado Distribucion Distribuidores (Promedios). Params: Dist={idDistribuidor}, Pub={idPublicacion}, Desde={fechaDesde}, Hasta={fechaHasta}", spName, idDistribuidor, idPublicacion, fechaDesde, fechaHasta);
                return Enumerable.Empty<ListadoDistribucionDistPromedioDiaDto>();
            }
        }

        public async Task<(IEnumerable<ListadoDistribucionDistSimpleDto> Simple, IEnumerable<ListadoDistribucionDistPromedioDiaDto> Promedios, string? Error)> ObtenerListadoDistribucionDistribuidoresAsync(int idDistribuidor, int idPublicacion, DateTime fechaDesde, DateTime fechaHasta)
        {
            if (fechaDesde > fechaHasta)
                return (Enumerable.Empty<ListadoDistribucionDistSimpleDto>(), Enumerable.Empty<ListadoDistribucionDistPromedioDiaDto>(), "La fecha 'Desde' no puede ser mayor que la fecha 'Hasta'.");

            try
            {
                var simpleDataTask = this.GetListadoDistribucionDistSimpleAsync(idDistribuidor, idPublicacion, fechaDesde, fechaHasta);
                var promediosDataTask = this.GetListadoDistribucionDistPromedioDiaAsync(idDistribuidor, idPublicacion, fechaDesde, fechaHasta);

                await Task.WhenAll(simpleDataTask, promediosDataTask);

                return (await simpleDataTask, await promediosDataTask, null);
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, "Error en ReportesService al obtener Listado Distribucion (Distribuidores).");
                return (Enumerable.Empty<ListadoDistribucionDistSimpleDto>(), Enumerable.Empty<ListadoDistribucionDistPromedioDiaDto>(), "Error interno al generar el reporte.");
            }
        }

        public async Task<IEnumerable<LiquidacionCanillaDetalleDto>> GetLiquidacionCanillaDetalleAsync(DateTime fecha, int idCanilla)
        {
            const string spName = "dbo.SP_DistCanillasLiquidacion";
            var parameters = new DynamicParameters();
            parameters.Add("@fecha", fecha, DbType.DateTime);
            parameters.Add("@idCanilla", idCanilla, DbType.Int32);
            try
            {
                using var connection = _dbConnectionFactory.CreateConnection();
                return await connection.QueryAsync<LiquidacionCanillaDetalleDto>(spName, parameters, commandType: CommandType.StoredProcedure, commandTimeout: 120);
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, "Error SP {SPName} para Liquidacion Canilla Detalle. Fecha: {Fecha}, Canilla: {IdCanilla}", spName, fecha, idCanilla);
                return Enumerable.Empty<LiquidacionCanillaDetalleDto>();
            }
        }

        public async Task<IEnumerable<LiquidacionCanillaGananciaDto>> GetLiquidacionCanillaGananciasAsync(DateTime fecha, int idCanilla)
        {
            const string spName = "dbo.SP_DistCanillasLiquidacionGanancias";
            var parameters = new DynamicParameters();
            parameters.Add("@fecha", fecha, DbType.DateTime);
            parameters.Add("@idCanilla", idCanilla, DbType.Int32);
            try
            {
                using var connection = _dbConnectionFactory.CreateConnection();
                return await connection.QueryAsync<LiquidacionCanillaGananciaDto>(spName, parameters, commandType: CommandType.StoredProcedure, commandTimeout: 120);
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, "Error SP {SPName} para Liquidacion Canilla Ganancias. Fecha: {Fecha}, Canilla: {IdCanilla}", spName, fecha, idCanilla);
                return Enumerable.Empty<LiquidacionCanillaGananciaDto>();
            }
        }

        public async Task<IEnumerable<ListadoDistCanMensualDiariosDto>> GetReporteMensualDiariosAsync(DateTime fechaDesde, DateTime fechaHasta, bool esAccionista)
        {
            using var connection = _dbConnectionFactory.CreateConnection();
            var parameters = new
            {
                fechaDesde = fechaDesde.Date,
                fechaHasta = fechaHasta.Date, // El SP parece manejar el rango incluyendo el último día
                accionista = esAccionista
            };
            return await connection.QueryAsync<ListadoDistCanMensualDiariosDto>(
                "dbo.SP_DistCanillasAccConImporteEntreFechasDiarios",
                parameters,
                commandType: CommandType.StoredProcedure, commandTimeout: 120
            );
        }

        public async Task<IEnumerable<ListadoDistCanMensualPubDto>> GetReporteMensualPorPublicacionAsync(DateTime fechaDesde, DateTime fechaHasta, bool esAccionista)
        {
            using var connection = _dbConnectionFactory.CreateConnection();
            var parameters = new
            {
                fechaDesde = fechaDesde.Date,
                fechaHasta = fechaHasta.Date,
                accionista = esAccionista
            };
            return await connection.QueryAsync<ListadoDistCanMensualPubDto>(
                "dbo.SP_DistCanillasAccConImporteEntreFechas",
                parameters,
                commandType: CommandType.StoredProcedure, commandTimeout: 120
            );
        }

        public async Task<IEnumerable<FacturasParaReporteDto>> GetDatosReportePublicidadAsync(string periodo)
        {
            // Esta consulta une todas las tablas necesarias para obtener los datos del reporte
            const string sql = @"
              SELECT 
                  f.IdFactura,
                  f.Periodo,
                  s.NombreCompleto AS NombreSuscriptor,
                  s.TipoDocumento,
                  s.NroDocumento,
                  f.ImporteFinal,
                  e.Id_Empresa AS IdEmpresa,
                  e.Nombre AS NombreEmpresa
              FROM dbo.susc_Facturas f
              JOIN dbo.susc_Suscriptores s ON f.IdSuscriptor = s.IdSuscriptor
              -- Usamos una subconsulta para obtener la empresa de forma segura
              JOIN (
                  SELECT DISTINCT 
                      fd.IdFactura, 
                      p.Id_Empresa
                  FROM dbo.susc_FacturaDetalles fd
                  JOIN dbo.susc_Suscripciones sub ON fd.IdSuscripcion = sub.IdSuscripcion
                  JOIN dbo.dist_dtPublicaciones p ON sub.IdPublicacion = p.Id_Publicacion
              ) AS FacturaEmpresa ON f.IdFactura = FacturaEmpresa.IdFactura
              JOIN dbo.dist_dtEmpresas e ON FacturaEmpresa.Id_Empresa = e.Id_Empresa
              WHERE 
                  f.Periodo = @Periodo
                  AND f.EstadoPago = 'Pagada'
                  AND f.EstadoFacturacion = 'Pendiente de Facturar'
              ORDER BY 
                  e.Nombre, s.NombreCompleto;
          ";

            try
            {
                using var connection = _dbConnectionFactory.CreateConnection();
                return await connection.QueryAsync<FacturasParaReporteDto>(sql, new { Periodo = periodo });
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, "Error al ejecutar la consulta para el Reporte de Publicidad para el período {Periodo}", periodo);
                return Enumerable.Empty<FacturasParaReporteDto>();
            }
        }

        public async Task<IEnumerable<DistribucionSuscripcionDto>> GetDistribucionSuscripcionesActivasAsync(DateTime fechaDesde, DateTime fechaHasta)
        {
            const string sql = @"
                SELECT 
                    e.Nombre AS NombreEmpresa, p.Nombre AS NombrePublicacion,
                    sus.NombreCompleto AS NombreSuscriptor, sus.Direccion, sus.Telefono,
                    s.FechaInicio, s.FechaFin, s.DiasEntrega, s.Observaciones
                FROM dbo.susc_Suscripciones s
                JOIN dbo.susc_Suscriptores sus ON s.IdSuscriptor = sus.IdSuscriptor
                JOIN dbo.dist_dtPublicaciones p ON s.IdPublicacion = p.Id_Publicacion
                JOIN dbo.dist_dtEmpresas e ON p.Id_Empresa = e.Id_Empresa
                WHERE 
                    -- --- INICIO DE LA CORRECCIÓN ---
                    -- Se asegura de que SOLO se incluyan suscripciones y suscriptores ACTIVOS.
                    s.Estado = 'Activa' AND sus.Activo = 1
                    -- --- FIN DE LA CORRECCIÓN ---
                    AND s.FechaInicio <= @FechaHasta
                    AND (s.FechaFin IS NULL OR s.FechaFin >= @FechaDesde)
                ORDER BY e.Nombre, p.Nombre, sus.NombreCompleto;";

            try
            {
                using var connection = _dbConnectionFactory.CreateConnection();
                return await connection.QueryAsync<DistribucionSuscripcionDto>(sql, new { FechaDesde = fechaDesde, FechaHasta = fechaHasta });
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, "Error al obtener datos para Reporte de Distribución (Activas).");
                return Enumerable.Empty<DistribucionSuscripcionDto>();
            }
        }

        public async Task<IEnumerable<DistribucionSuscripcionDto>> GetDistribucionSuscripcionesBajasAsync(DateTime fechaDesde, DateTime fechaHasta)
        {
            const string sql = @"
                SELECT 
                    e.Nombre AS NombreEmpresa, p.Nombre AS NombrePublicacion,
                    sus.NombreCompleto AS NombreSuscriptor, sus.Direccion, sus.Telefono,
                    s.FechaInicio, s.FechaFin, s.DiasEntrega, s.Observaciones
                FROM dbo.susc_Suscripciones s
                JOIN dbo.susc_Suscriptores sus ON s.IdSuscriptor = sus.IdSuscriptor
                JOIN dbo.dist_dtPublicaciones p ON s.IdPublicacion = p.Id_Publicacion
                JOIN dbo.dist_dtEmpresas e ON p.Id_Empresa = e.Id_Empresa
                WHERE 
                    -- La lógica aquí es correcta: buscamos cualquier suscripción cuya fecha de fin
                    -- caiga dentro del rango de fechas seleccionado.
                    s.FechaFin BETWEEN @FechaDesde AND @FechaHasta
                ORDER BY e.Nombre, p.Nombre, s.FechaFin, sus.NombreCompleto;";

            try
            {
                using var connection = _dbConnectionFactory.CreateConnection();
                return await connection.QueryAsync<DistribucionSuscripcionDto>(sql, new { FechaDesde = fechaDesde, FechaHasta = fechaHasta });
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, "Error al obtener datos para Reporte de Distribución (Bajas).");
                return Enumerable.Empty<DistribucionSuscripcionDto>();
            }
        }

        public async Task<IEnumerable<DetalleDistribucionCanillaDto>> GetDetalleDistribucionCanillasPubli_AllEmpresasAsync(DateTime fecha)
        {
            const string spName = "dbo.SP_DistCanillasEntradaSalidaPubli_AllEmpresas";
            var parameters = new DynamicParameters();
            parameters.Add("@fecha", fecha, DbType.DateTime);
            try
            {
                using var connection = _dbConnectionFactory.CreateConnection();
                return await connection.QueryAsync<DetalleDistribucionCanillaDto>(spName, parameters, commandType: CommandType.StoredProcedure, commandTimeout: 120);
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, "Error SP {SPName}", spName);
                return Enumerable.Empty<DetalleDistribucionCanillaDto>();
            }
        }

        public async Task<IEnumerable<DetalleDistribucionCanillaDto>> GetDetalleDistribucionCanillasAccPubli_AllEmpresasAsync(DateTime fecha)
        {
            const string spName = "dbo.SP_DistCanillasAccEntradaSalidaPubli_AllEmpresas";
            var parameters = new DynamicParameters();
            parameters.Add("@fecha", fecha, DbType.DateTime);
            try
            {
                using var connection = _dbConnectionFactory.CreateConnection();
                return await connection.QueryAsync<DetalleDistribucionCanillaDto>(spName, parameters, commandType: CommandType.StoredProcedure, commandTimeout: 120);
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, "Error SP {SPName}", spName);
                return Enumerable.Empty<DetalleDistribucionCanillaDto>();
            }
        }
    }
}