using Dapper; using GestionIntegral.Api.Models.Distribucion; using Microsoft.Extensions.Logging; using System; // Para Exception using System.Collections.Generic; using System.Data; using System.Linq; using System.Text; using System.Threading.Tasks; namespace GestionIntegral.Api.Data.Repositories.Distribucion { public class CanillaRepository : ICanillaRepository { private readonly DbConnectionFactory _connectionFactory; private readonly ILogger _logger; public CanillaRepository(DbConnectionFactory connectionFactory, ILogger logger) { _connectionFactory = connectionFactory; _logger = logger; } public async Task> GetAllAsync( string? nomApeFilter, int? legajoFilter, bool? esAccionista, bool? soloActivos) // <<-- Parámetro aquí { using var connection = _connectionFactory.CreateConnection(); var sqlBuilder = new System.Text.StringBuilder(@" SELECT c.Id_Canilla AS IdCanilla, c.Legajo, c.NomApe, c.Parada, c.Id_Zona AS IdZona, c.Accionista, c.Obs, c.Empresa, c.Baja, c.FechaBaja, z.Nombre AS NombreZona, e.Nombre AS NombreEmpresa FROM dbo.dist_dtCanillas c LEFT JOIN dbo.dist_dtZonas z ON c.Id_Zona = z.Id_Zona LEFT JOIN dbo.dist_dtEmpresas e ON c.Empresa = e.Id_Empresa WHERE 1=1 "); // Cláusula base para añadir AND fácilmente var parameters = new DynamicParameters(); if (!string.IsNullOrWhiteSpace(nomApeFilter)) { sqlBuilder.Append(" AND c.NomApe LIKE @NomApeFilter "); parameters.Add("NomApeFilter", $"%{nomApeFilter}%"); } if (legajoFilter.HasValue) { sqlBuilder.Append(" AND c.Legajo = @LegajoFilter "); parameters.Add("LegajoFilter", legajoFilter.Value); } if (soloActivos.HasValue) { sqlBuilder.Append(" AND c.Baja = @BajaStatus "); parameters.Add("BajaStatus", !soloActivos.Value); // Si soloActivos es true, Baja debe ser false } if (esAccionista.HasValue) { sqlBuilder.Append(" AND c.Accionista = @EsAccionista "); parameters.Add("EsAccionista", esAccionista.Value); // true para accionistas, false para no accionistas (canillitas) } sqlBuilder.Append(" ORDER BY c.NomApe;"); var result = await connection.QueryAsync( sqlBuilder.ToString(), (can, zona, emp) => (can, zona, emp), parameters, splitOn: "NombreZona,NombreEmpresa" ); return result; } public async Task<(Canilla? Canilla, string? NombreZona, string? NombreEmpresa)> GetByIdAsync(int id) { const string sql = @" SELECT c.Id_Canilla AS IdCanilla, c.Legajo, c.NomApe, c.Parada, c.Id_Zona AS IdZona, c.Accionista, c.Obs, c.Empresa, c.Baja, c.FechaBaja, z.Nombre AS NombreZona, ISNULL(e.Nombre, 'N/A (Accionista)') AS NombreEmpresa FROM dbo.dist_dtCanillas c INNER JOIN dbo.dist_dtZonas z ON c.Id_Zona = z.Id_Zona LEFT JOIN dbo.dist_dtEmpresas e ON c.Empresa = e.Id_Empresa WHERE c.Id_Canilla = @IdParam"; try { using var connection = _connectionFactory.CreateConnection(); var result = await connection.QueryAsync( sql, (canilla, nombreZona, nombreEmpresa) => (canilla, nombreZona, nombreEmpresa), new { IdParam = id }, splitOn: "NombreZona,NombreEmpresa" ); return result.SingleOrDefault(); } catch (Exception ex) { _logger.LogError(ex, "Error al obtener Canilla por ID: {IdCanilla}", id); return (null, null, null); } } public async Task GetByIdSimpleAsync(int id) { const string sql = @" SELECT Id_Canilla AS IdCanilla, Legajo, NomApe, Parada, Id_Zona AS IdZona, Accionista, Obs, Empresa, Baja, FechaBaja FROM dbo.dist_dtCanillas WHERE Id_Canilla = @IdParam"; try { using var connection = _connectionFactory.CreateConnection(); return await connection.QuerySingleOrDefaultAsync(sql, new { IdParam = id }); } catch (Exception ex) { _logger.LogError(ex, "Error al obtener Canilla (simple) por ID: {IdCanilla}", id); return null; } } public async Task ExistsByLegajoAsync(int legajo, int? excludeIdCanilla = null) { if (legajo == 0) return false; var sqlBuilder = new StringBuilder("SELECT COUNT(1) FROM dbo.dist_dtCanillas WHERE Legajo = @LegajoParam AND Legajo != 0"); var parameters = new DynamicParameters(); parameters.Add("LegajoParam", legajo); if (excludeIdCanilla.HasValue) { sqlBuilder.Append(" AND Id_Canilla != @ExcludeIdCanillaParam"); parameters.Add("ExcludeIdCanillaParam", excludeIdCanilla.Value); } try { using var connection = _connectionFactory.CreateConnection(); return await connection.ExecuteScalarAsync(sqlBuilder.ToString(), parameters); } catch (Exception ex) { _logger.LogError(ex, "Error en ExistsByLegajoAsync para Canilla con Legajo: {Legajo}", legajo); return true; } } public async Task CreateAsync(Canilla nuevoCanilla, int idUsuario, IDbTransaction transaction) { const string sqlInsert = @" INSERT INTO dbo.dist_dtCanillas (Legajo, NomApe, Parada, Id_Zona, Accionista, Obs, Empresa, Baja, FechaBaja) OUTPUT INSERTED.Id_Canilla AS IdCanilla, INSERTED.Legajo, INSERTED.NomApe, INSERTED.Parada, INSERTED.Id_Zona AS IdZona, INSERTED.Accionista, INSERTED.Obs, INSERTED.Empresa, INSERTED.Baja, INSERTED.FechaBaja VALUES (@Legajo, @NomApe, @Parada, @IdZona, @Accionista, @Obs, @Empresa, @Baja, @FechaBaja);"; var connection = transaction.Connection!; var insertedCanilla = await connection.QuerySingleAsync(sqlInsert, nuevoCanilla, transaction); if (insertedCanilla == null || insertedCanilla.IdCanilla == 0) throw new DataException("No se pudo crear el canillita o obtener su ID."); const string sqlInsertHistorico = @" INSERT INTO dbo.dist_dtCanillas_H (Id_Canilla, Legajo, NomApe, Parada, Id_Zona, Accionista, Obs, Empresa, Baja, FechaBaja, Id_Usuario, FechaMod, TipoMod) VALUES (@IdCanillaParam, @LegajoParam, @NomApeParam, @ParadaParam, @IdZonaParam, @AccionistaParam, @ObsParam, @EmpresaParam, @BajaParam, @FechaBajaParam, @Id_UsuarioParam, @FechaModParam, @TipoModParam);"; await connection.ExecuteAsync(sqlInsertHistorico, new { IdCanillaParam = insertedCanilla.IdCanilla, LegajoParam = insertedCanilla.Legajo, NomApeParam = insertedCanilla.NomApe, ParadaParam = insertedCanilla.Parada, IdZonaParam = insertedCanilla.IdZona, AccionistaParam = insertedCanilla.Accionista, ObsParam = insertedCanilla.Obs, EmpresaParam = insertedCanilla.Empresa, BajaParam = insertedCanilla.Baja, FechaBajaParam = insertedCanilla.FechaBaja, Id_UsuarioParam = idUsuario, FechaModParam = DateTime.Now, TipoModParam = "Creado" }, transaction); return insertedCanilla; } public async Task UpdateAsync(Canilla canillaAActualizar, int idUsuario, IDbTransaction transaction) { var connection = transaction.Connection!; var canillaActual = await connection.QuerySingleOrDefaultAsync( @"SELECT Id_Canilla AS IdCanilla, Legajo, NomApe, Parada, Id_Zona AS IdZona, Accionista, Obs, Empresa, Baja, FechaBaja FROM dbo.dist_dtCanillas WHERE Id_Canilla = @IdCanillaParam", new { IdCanillaParam = canillaAActualizar.IdCanilla }, transaction); if (canillaActual == null) throw new KeyNotFoundException("Canilla no encontrado para actualizar."); const string sqlUpdate = @" UPDATE dbo.dist_dtCanillas SET Legajo = @Legajo, NomApe = @NomApe, Parada = @Parada, Id_Zona = @IdZona, Accionista = @Accionista, Obs = @Obs, Empresa = @Empresa WHERE Id_Canilla = @IdCanilla;"; const string sqlInsertHistorico = @" INSERT INTO dbo.dist_dtCanillas_H (Id_Canilla, Legajo, NomApe, Parada, Id_Zona, Accionista, Obs, Empresa, Baja, FechaBaja, Id_Usuario, FechaMod, TipoMod) VALUES (@IdCanillaParam, @LegajoParam, @NomApeParam, @ParadaParam, @IdZonaParam, @AccionistaParam, @ObsParam, @EmpresaParam, @BajaParam, @FechaBajaParam, @Id_UsuarioParam, @FechaModParam, @TipoModParam);"; await connection.ExecuteAsync(sqlInsertHistorico, new { IdCanillaParam = canillaActual.IdCanilla, LegajoParam = canillaActual.Legajo, NomApeParam = canillaActual.NomApe, ParadaParam = canillaActual.Parada, IdZonaParam = canillaActual.IdZona, AccionistaParam = canillaActual.Accionista, ObsParam = canillaActual.Obs, EmpresaParam = canillaActual.Empresa, BajaParam = canillaActual.Baja, FechaBajaParam = canillaActual.FechaBaja, Id_UsuarioParam = idUsuario, FechaModParam = DateTime.Now, TipoModParam = "Actualizado" }, transaction); var rowsAffected = await connection.ExecuteAsync(sqlUpdate, canillaAActualizar, transaction); return rowsAffected == 1; } public async Task ToggleBajaAsync(int id, bool darDeBaja, DateTime? fechaBaja, int idUsuario, IDbTransaction transaction) { var connection = transaction.Connection!; var canillaActual = await connection.QuerySingleOrDefaultAsync( @"SELECT Id_Canilla AS IdCanilla, Legajo, NomApe, Parada, Id_Zona AS IdZona, Accionista, Obs, Empresa, Baja, FechaBaja FROM dbo.dist_dtCanillas WHERE Id_Canilla = @IdCanillaParam", new { IdCanillaParam = id }, transaction); if (canillaActual == null) throw new KeyNotFoundException("Canilla no encontrado para dar de baja/alta."); const string sqlUpdate = "UPDATE dbo.dist_dtCanillas SET Baja = @BajaParam, FechaBaja = @FechaBajaParam WHERE Id_Canilla = @IdCanillaParam;"; const string sqlInsertHistorico = @" INSERT INTO dbo.dist_dtCanillas_H (Id_Canilla, Legajo, NomApe, Parada, Id_Zona, Accionista, Obs, Empresa, Baja, FechaBaja, Id_Usuario, FechaMod, TipoMod) VALUES (@IdCanillaParam, @LegajoParam, @NomApeParam, @ParadaParam, @IdZonaParam, @AccionistaParam, @ObsParam, @EmpresaParam, @BajaNuevaParam, @FechaBajaNuevaParam, @Id_UsuarioParam, @FechaModParam, @TipoModHistParam);"; await connection.ExecuteAsync(sqlInsertHistorico, new { IdCanillaParam = canillaActual.IdCanilla, LegajoParam = canillaActual.Legajo, NomApeParam = canillaActual.NomApe, ParadaParam = canillaActual.Parada, IdZonaParam = canillaActual.IdZona, AccionistaParam = canillaActual.Accionista, ObsParam = canillaActual.Obs, EmpresaParam = canillaActual.Empresa, BajaNuevaParam = darDeBaja, FechaBajaNuevaParam = (darDeBaja ? fechaBaja : null), Id_UsuarioParam = idUsuario, FechaModParam = DateTime.Now, TipoModHistParam = (darDeBaja ? "Baja" : "Alta") }, transaction); var rowsAffected = await connection.ExecuteAsync(sqlUpdate, new { BajaParam = darDeBaja, FechaBajaParam = (darDeBaja ? fechaBaja : null), IdCanillaParam = id }, transaction); return rowsAffected == 1; } public async Task> GetHistorialAsync( DateTime? fechaDesde, DateTime? fechaHasta, int? idUsuarioModifico, string? tipoModificacion, int? idCanillaOriginal) { using var connection = _connectionFactory.CreateConnection(); // Asumiendo _cf es tu DbConnectionFactory var sqlBuilder = new StringBuilder(@" SELECT h.Id_Canilla, h.Legajo, h.NomApe, h.Parada, h.Id_Zona, h.Accionista, h.Obs, h.Empresa, h.Baja, h.FechaBaja, h.Id_Usuario, h.FechaMod, h.TipoMod, u.Nombre + ' ' + u.Apellido AS NombreUsuarioModifico FROM dbo.dist_dtCanillas_H h JOIN dbo.gral_Usuarios u ON h.Id_Usuario = u.Id WHERE 1=1"); var parameters = new DynamicParameters(); if (fechaDesde.HasValue) { sqlBuilder.Append(" AND h.FechaMod >= @FechaDesdeParam"); parameters.Add("FechaDesdeParam", fechaDesde.Value.Date); } if (fechaHasta.HasValue) { sqlBuilder.Append(" AND h.FechaMod <= @FechaHastaParam"); parameters.Add("FechaHastaParam", fechaHasta.Value.Date.AddDays(1).AddTicks(-1)); } if (idUsuarioModifico.HasValue) { sqlBuilder.Append(" AND h.Id_Usuario = @IdUsuarioModificoParam"); parameters.Add("IdUsuarioModificoParam", idUsuarioModifico.Value); } if (!string.IsNullOrWhiteSpace(tipoModificacion)) { sqlBuilder.Append(" AND h.TipoMod = @TipoModParam"); parameters.Add("TipoModParam", tipoModificacion); } if (idCanillaOriginal.HasValue) { sqlBuilder.Append(" AND h.Id_Canilla = @IdCanillaOriginalParam"); parameters.Add("IdCanillaOriginalParam", idCanillaOriginal.Value); } sqlBuilder.Append(" ORDER BY h.FechaMod DESC;"); try { var result = await connection.QueryAsync( sqlBuilder.ToString(), (hist, userName) => (hist, userName), parameters, splitOn: "NombreUsuarioModifico" ); return result; } catch (Exception ex) { _logger.LogError(ex, "Error al obtener historial de Canillitas (Maestro)."); return Enumerable.Empty<(CanillaHistorico, string)>(); } } } }