using Dapper; using GestionIntegral.Api.Models.Distribucion; 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.Distribucion { public class PrecioRepository : IPrecioRepository { private readonly DbConnectionFactory _connectionFactory; private readonly ILogger _logger; public PrecioRepository(DbConnectionFactory connectionFactory, ILogger logger) { _connectionFactory = connectionFactory; _logger = logger; } public async Task> GetByPublicacionIdAsync(int idPublicacion) { const string sql = @" SELECT Id_Precio AS IdPrecio, Id_Publicacion AS IdPublicacion, VigenciaD, VigenciaH, Lunes, Martes, Miercoles, Jueves, Viernes, Sabado, Domingo FROM dbo.dist_Precios WHERE Id_Publicacion = @IdPublicacionParam ORDER BY VigenciaD DESC"; try { using var connection = _connectionFactory.CreateConnection(); return await connection.QueryAsync(sql, new { IdPublicacionParam = idPublicacion }); } catch (Exception ex) { _logger.LogError(ex, "Error al obtener precios por IdPublicacion: {IdPublicacion}", idPublicacion); return Enumerable.Empty(); } } public async Task GetByIdAsync(int idPrecio) { const string sql = @" SELECT Id_Precio AS IdPrecio, Id_Publicacion AS IdPublicacion, VigenciaD, VigenciaH, Lunes, Martes, Miercoles, Jueves, Viernes, Sabado, Domingo FROM dbo.dist_Precios WHERE Id_Precio = @IdPrecioParam"; try { using var connection = _connectionFactory.CreateConnection(); return await connection.QuerySingleOrDefaultAsync(sql, new { IdPrecioParam = idPrecio }); } catch (Exception ex) { _logger.LogError(ex, "Error al obtener precio por ID: {idPrecio}", idPrecio); return null; } } public async Task GetActiveByPublicacionAndDateAsync(int idPublicacion, DateTime fecha, IDbTransaction? transaction = null) { const string sql = @" SELECT TOP 1 Id_Precio AS IdPrecio, Id_Publicacion AS IdPublicacion, VigenciaD, VigenciaH, Lunes, Martes, Miercoles, Jueves, Viernes, Sabado, Domingo FROM dbo.dist_Precios WHERE Id_Publicacion = @IdPublicacionParam AND VigenciaD <= @FechaParam AND (VigenciaH IS NULL OR VigenciaH >= @FechaParam) ORDER BY VigenciaD DESC;"; var cn = transaction?.Connection ?? _connectionFactory.CreateConnection(); bool ownConnection = transaction == null; Precio? result = null; try { if (ownConnection && cn.State == ConnectionState.Closed && cn is System.Data.Common.DbConnection dbConn) { await dbConn.OpenAsync(); } result = await cn.QuerySingleOrDefaultAsync(sql, new { IdPublicacionParam = idPublicacion, FechaParam = fecha.Date }, transaction); } catch (Exception ex) { _logger.LogError(ex, "Error en GetActiveByPublicacionAndDateAsync. IdPublicacion: {IdPublicacion}, Fecha: {Fecha}", idPublicacion, fecha); throw; // Re-lanzar para que el servicio lo maneje si es necesario } finally { if (ownConnection && cn.State == ConnectionState.Open && cn is System.Data.Common.DbConnection dbConnClose) { await dbConnClose.CloseAsync(); } if (ownConnection) (cn as IDisposable)?.Dispose(); } return result; } public async Task GetPreviousActivePriceAsync(int idPublicacion, DateTime vigenciaDNuevo, IDbTransaction transaction) { const string sql = @" SELECT TOP 1 Id_Precio AS IdPrecio, Id_Publicacion AS IdPublicacion, VigenciaD, VigenciaH, Lunes, Martes, Miercoles, Jueves, Viernes, Sabado, Domingo FROM dbo.dist_Precios WHERE Id_Publicacion = @IdPublicacionParam AND VigenciaD < @VigenciaDNuevoParam AND VigenciaH IS NULL ORDER BY VigenciaD DESC;"; return await transaction.Connection!.QuerySingleOrDefaultAsync(sql, new { IdPublicacionParam = idPublicacion, VigenciaDNuevoParam = vigenciaDNuevo.Date }, transaction); } public async Task CreateAsync(Precio nuevoPrecio, int idUsuario, IDbTransaction transaction) { const string sqlInsert = @" INSERT INTO dbo.dist_Precios (Id_Publicacion, VigenciaD, VigenciaH, Lunes, Martes, Miercoles, Jueves, Viernes, Sabado, Domingo) OUTPUT INSERTED.Id_Precio AS IdPrecio, INSERTED.Id_Publicacion AS IdPublicacion, INSERTED.VigenciaD, INSERTED.VigenciaH, INSERTED.Lunes, INSERTED.Martes, INSERTED.Miercoles, INSERTED.Jueves, INSERTED.Viernes, INSERTED.Sabado, INSERTED.Domingo VALUES (@IdPublicacion, @VigenciaD, @VigenciaH, @Lunes, @Martes, @Miercoles, @Jueves, @Viernes, @Sabado, @Domingo);"; var inserted = await transaction.Connection!.QuerySingleAsync(sqlInsert, nuevoPrecio, transaction); if (inserted == null || inserted.IdPrecio == 0) throw new DataException("Error al crear precio o al obtener el ID generado."); const string sqlInsertHistorico = @" INSERT INTO dbo.dist_Precios_H (Id_Precio, Id_Publicacion, VigenciaD, VigenciaH, Lunes, Martes, Miercoles, Jueves, Viernes, Sabado, Domingo, Id_Usuario, FechaMod, TipoMod) VALUES (@IdPrecioHist, @IdPublicacionHist, @VigenciaDHist, @VigenciaHHist, @LunesHist, @MartesHist, @MiercolesHist, @JuevesHist, @ViernesHist, @SabadoHist, @DomingoHist, @IdUsuarioHist, @FechaModHist, @TipoModHist);"; await transaction.Connection!.ExecuteAsync(sqlInsertHistorico, new { IdPrecioHist = inserted.IdPrecio, IdPublicacionHist = inserted.IdPublicacion, VigenciaDHist = inserted.VigenciaD, VigenciaHHist = inserted.VigenciaH, LunesHist = inserted.Lunes, MartesHist = inserted.Martes, MiercolesHist = inserted.Miercoles, JuevesHist = inserted.Jueves, ViernesHist = inserted.Viernes, SabadoHist = inserted.Sabado, DomingoHist = inserted.Domingo, IdUsuarioHist = idUsuario, FechaModHist = DateTime.Now, TipoModHist = "Creado" }, transaction); return inserted; } public async Task UpdateAsync(Precio precioAActualizar, int idUsuario, IDbTransaction transaction) { var actual = await transaction.Connection!.QuerySingleOrDefaultAsync( @"SELECT Id_Precio AS IdPrecio, Id_Publicacion AS IdPublicacion, VigenciaD, VigenciaH, Lunes, Martes, Miercoles, Jueves, Viernes, Sabado, Domingo FROM dbo.dist_Precios WHERE Id_Precio = @IdPrecioParam", // Usar parámetro con alias new { IdPrecioParam = precioAActualizar.IdPrecio }, transaction); if (actual == null) throw new KeyNotFoundException("Precio no encontrado."); const string sqlUpdate = @" UPDATE dbo.dist_Precios SET VigenciaH = @VigenciaH, Lunes = @Lunes, Martes = @Martes, Miercoles = @Miercoles, Jueves = @Jueves, Viernes = @Viernes, Sabado = @Sabado, Domingo = @Domingo WHERE Id_Precio = @IdPrecio;"; const string sqlInsertHistorico = @" INSERT INTO dbo.dist_Precios_H (Id_Precio, Id_Publicacion, VigenciaD, VigenciaH, Lunes, Martes, Miercoles, Jueves, Viernes, Sabado, Domingo, Id_Usuario, FechaMod, TipoMod) VALUES (@IdPrecioHist, @IdPublicacionHist, @VigenciaDHist, @VigenciaHHist, @LunesHist, @MartesHist, @MiercolesHist, @JuevesHist, @ViernesHist, @SabadoHist, @DomingoHist, @IdUsuarioHist, @FechaModHist, @TipoModHist);"; await transaction.Connection!.ExecuteAsync(sqlInsertHistorico, new { IdPrecioHist = actual.IdPrecio, IdPublicacionHist = actual.IdPublicacion, VigenciaDHist = actual.VigenciaD, VigenciaHHist = actual.VigenciaH, LunesHist = actual.Lunes, MartesHist = actual.Martes, MiercolesHist = actual.Miercoles, JuevesHist = actual.Jueves, ViernesHist = actual.Viernes, SabadoHist = actual.Sabado, DomingoHist = actual.Domingo, IdUsuarioHist = idUsuario, FechaModHist = DateTime.Now, TipoModHist = "Actualizado" }, transaction); var rowsAffected = await transaction.Connection!.ExecuteAsync(sqlUpdate, precioAActualizar, transaction); return rowsAffected == 1; } public async Task DeleteAsync(int idPrecio, int idUsuario, IDbTransaction transaction) { var actual = await transaction.Connection!.QuerySingleOrDefaultAsync( @"SELECT Id_Precio AS IdPrecio, Id_Publicacion AS IdPublicacion, VigenciaD, VigenciaH, Lunes, Martes, Miercoles, Jueves, Viernes, Sabado, Domingo FROM dbo.dist_Precios WHERE Id_Precio = @IdPrecioParam", new { IdPrecioParam = idPrecio }, transaction); if (actual == null) throw new KeyNotFoundException("Precio no encontrado para eliminar."); const string sqlDelete = "DELETE FROM dbo.dist_Precios WHERE Id_Precio = @IdPrecioParam"; // Usar parámetro con alias const string sqlInsertHistorico = @" INSERT INTO dbo.dist_Precios_H (Id_Precio, Id_Publicacion, VigenciaD, VigenciaH, Lunes, Martes, Miercoles, Jueves, Viernes, Sabado, Domingo, Id_Usuario, FechaMod, TipoMod) VALUES (@IdPrecioHist, @IdPublicacionHist, @VigenciaDHist, @VigenciaHHist, @LunesHist, @MartesHist, @MiercolesHist, @JuevesHist, @ViernesHist, @SabadoHist, @DomingoHist, @IdUsuarioHist, @FechaModHist, @TipoModHist);"; await transaction.Connection!.ExecuteAsync(sqlInsertHistorico, new { IdPrecioHist = actual.IdPrecio, IdPublicacionHist = actual.IdPublicacion, VigenciaDHist = actual.VigenciaD, VigenciaHHist = actual.VigenciaH, LunesHist = actual.Lunes, MartesHist = actual.Martes, MiercolesHist = actual.Miercoles, JuevesHist = actual.Jueves, ViernesHist = actual.Viernes, SabadoHist = actual.Sabado, DomingoHist = actual.Domingo, IdUsuarioHist = idUsuario, FechaModHist = DateTime.Now, TipoModHist = "Eliminado" }, transaction); var rowsAffected = await transaction.Connection!.ExecuteAsync(sqlDelete, new { IdPrecioParam = idPrecio }, transaction); // Usar parámetro con alias return rowsAffected == 1; } public async Task DeleteByPublicacionIdAsync(int idPublicacion, int idUsuarioAuditoria, IDbTransaction transaction) { const string selectSql = @" SELECT Id_Precio AS IdPrecio, Id_Publicacion AS IdPublicacion, VigenciaD, VigenciaH, Lunes, Martes, Miercoles, Jueves, Viernes, Sabado, Domingo FROM dbo.dist_Precios WHERE Id_Publicacion = @IdPublicacionParam"; var itemsToDelete = await transaction.Connection!.QueryAsync(selectSql, new { IdPublicacionParam = idPublicacion }, transaction); if (itemsToDelete.Any()) { const string insertHistoricoSql = @" INSERT INTO dbo.dist_Precios_H (Id_Precio, Id_Publicacion, VigenciaD, VigenciaH, Lunes, Martes, Miercoles, Jueves, Viernes, Sabado, Domingo, Id_Usuario, FechaMod, TipoMod) VALUES (@IdPrecioHist, @IdPublicacionHist, @VigenciaDHist, @VigenciaHHist, @LunesHist, @MartesHist, @MiercolesHist, @JuevesHist, @ViernesHist, @SabadoHist, @DomingoHist, @IdUsuarioHist, @FechaModHist, @TipoModHist);"; foreach (var item in itemsToDelete) { await transaction.Connection!.ExecuteAsync(insertHistoricoSql, new { IdPrecioHist = item.IdPrecio, IdPublicacionHist = item.IdPublicacion, VigenciaDHist = item.VigenciaD, VigenciaHHist = item.VigenciaH, LunesHist = item.Lunes, MartesHist = item.Martes, MiercolesHist = item.Miercoles, JuevesHist = item.Jueves, ViernesHist = item.Viernes, SabadoHist = item.Sabado, DomingoHist = item.Domingo, IdUsuarioHist = idUsuarioAuditoria, FechaModHist = DateTime.Now, TipoModHist = "Eliminado (Cascada)" }, transaction); } } const string deleteSql = "DELETE FROM dbo.dist_Precios WHERE Id_Publicacion = @IdPublicacionParam"; try { await transaction.Connection!.ExecuteAsync(deleteSql, new { IdPublicacionParam = idPublicacion }, transaction: transaction); return true; } catch (System.Exception ex) { _logger.LogError(ex, "Error al eliminar precios por IdPublicacion: {IdPublicacion}", idPublicacion); throw; } } } }