using Dapper; using GestionIntegral.Api.Data.Repositories; using GestionIntegral.Api.Models.Distribucion; using Microsoft.Extensions.Logging; 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? soloActivos) { var sqlBuilder = new StringBuilder(@" SELECT c.*, 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 -- Empresa 0 no tendrá join WHERE 1=1"); var parameters = new DynamicParameters(); if (soloActivos.HasValue) { sqlBuilder.Append(soloActivos.Value ? " AND c.Baja = 0" : " AND c.Baja = 1"); } if (!string.IsNullOrWhiteSpace(nomApeFilter)) { sqlBuilder.Append(" AND c.NomApe LIKE @NomApe"); parameters.Add("NomApe", $"%{nomApeFilter}%"); } if (legajoFilter.HasValue) { sqlBuilder.Append(" AND c.Legajo = @Legajo"); parameters.Add("Legajo", legajoFilter.Value); } sqlBuilder.Append(" ORDER BY c.NomApe;"); try { using var connection = _connectionFactory.CreateConnection(); return await connection.QueryAsync( sqlBuilder.ToString(), (canilla, nombreZona, nombreEmpresa) => (canilla, nombreZona, nombreEmpresa), parameters, splitOn: "NombreZona,NombreEmpresa" ); } catch (Exception ex) { _logger.LogError(ex, "Error al obtener todos los Canillas."); return Enumerable.Empty<(Canilla, string, string)>(); } } public async Task<(Canilla? Canilla, string? NombreZona, string? NombreEmpresa)> GetByIdAsync(int id) { const string sql = @" SELECT c.*, 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 = @Id"; try { using var connection = _connectionFactory.CreateConnection(); var result = await connection.QueryAsync( sql, (canilla, nombreZona, nombreEmpresa) => (canilla, nombreZona, nombreEmpresa), new { Id = 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) // Para uso interno del servicio { const string sql = "SELECT * FROM dbo.dist_dtCanillas WHERE Id_Canilla = @Id"; using var connection = _connectionFactory.CreateConnection(); return await connection.QuerySingleOrDefaultAsync(sql, new { Id = id }); } public async Task ExistsByLegajoAsync(int legajo, int? excludeIdCanilla = null) { if (legajo == 0) return false; // Legajo 0 es como nulo, no debería validarse como único var sqlBuilder = new StringBuilder("SELECT COUNT(1) FROM dbo.dist_dtCanillas WHERE Legajo = @Legajo AND Legajo != 0"); // Excluir legajo 0 de la unicidad var parameters = new DynamicParameters(); parameters.Add("Legajo", legajo); if (excludeIdCanilla.HasValue) { sqlBuilder.Append(" AND Id_Canilla != @ExcludeIdCanilla"); parameters.Add("ExcludeIdCanilla", 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.* VALUES (@Legajo, @NomApe, @Parada, @IdZona, @Accionista, @Obs, @Empresa, @Baja, @FechaBaja);"; 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 (@IdCanilla, @Legajo, @NomApe, @Parada, @IdZona, @Accionista, @Obs, @Empresa, @Baja, @FechaBaja, @Id_Usuario, @FechaMod, @TipoMod);"; var connection = transaction.Connection!; var insertedCanilla = await connection.QuerySingleAsync(sqlInsert, nuevoCanilla, transaction); if (insertedCanilla == null) throw new DataException("No se pudo crear el canilla."); await connection.ExecuteAsync(sqlInsertHistorico, new { insertedCanilla.IdCanilla, insertedCanilla.Legajo, insertedCanilla.NomApe, insertedCanilla.Parada, insertedCanilla.IdZona, insertedCanilla.Accionista, insertedCanilla.Obs, insertedCanilla.Empresa, insertedCanilla.Baja, insertedCanilla.FechaBaja, Id_Usuario = idUsuario, FechaMod = DateTime.Now, TipoMod = "Creado" }, transaction); return insertedCanilla; } public async Task UpdateAsync(Canilla canillaAActualizar, int idUsuario, IDbTransaction transaction) { var connection = transaction.Connection!; var canillaActual = await connection.QuerySingleOrDefaultAsync( "SELECT * FROM dbo.dist_dtCanillas WHERE Id_Canilla = @IdCanilla", new { 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 -- Baja y FechaBaja se manejan por ToggleBajaAsync 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 (@IdCanilla, @LegajoActual, @NomApeActual, @ParadaActual, @IdZonaActual, @AccionistaActual, @ObsActual, @EmpresaActual, @BajaActual, @FechaBajaActual, @Id_Usuario, @FechaMod, @TipoMod);"; await connection.ExecuteAsync(sqlInsertHistorico, new { IdCanilla = canillaActual.IdCanilla, LegajoActual = canillaActual.Legajo, NomApeActual = canillaActual.NomApe, ParadaActual = canillaActual.Parada, IdZonaActual = canillaActual.IdZona, AccionistaActual = canillaActual.Accionista, ObsActual = canillaActual.Obs, EmpresaActual = canillaActual.Empresa, BajaActual = canillaActual.Baja, FechaBajaActual = canillaActual.FechaBaja, // Registrar estado actual de baja Id_Usuario = idUsuario, FechaMod = DateTime.Now, TipoMod = "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 * FROM dbo.dist_dtCanillas WHERE Id_Canilla = @IdCanilla", new { IdCanilla = 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 = @Baja, FechaBaja = @FechaBaja 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 (@IdCanilla, @Legajo, @NomApe, @Parada, @IdZona, @Accionista, @Obs, @Empresa, @BajaNueva, @FechaBajaNueva, @Id_Usuario, @FechaMod, @TipoModHist);"; await connection.ExecuteAsync(sqlInsertHistorico, new { canillaActual.IdCanilla, canillaActual.Legajo, canillaActual.NomApe, canillaActual.Parada, canillaActual.IdZona, canillaActual.Accionista, canillaActual.Obs, canillaActual.Empresa, BajaNueva = darDeBaja, FechaBajaNueva = (darDeBaja ? fechaBaja : null), // FechaBaja solo si se da de baja Id_Usuario = idUsuario, FechaMod = DateTime.Now, TipoModHist = (darDeBaja ? "Baja" : "Alta") }, transaction); var rowsAffected = await connection.ExecuteAsync(sqlUpdate, new { Baja = darDeBaja, FechaBaja = (darDeBaja ? fechaBaja : null), IdCanilla = id }, transaction); return rowsAffected == 1; } } }