using Dapper; 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 DistribuidorRepository : IDistribuidorRepository { private readonly DbConnectionFactory _connectionFactory; private readonly ILogger _logger; public DistribuidorRepository(DbConnectionFactory connectionFactory, ILogger logger) { _connectionFactory = connectionFactory; _logger = logger; } public async Task> GetAllAsync(string? nombreFilter, string? nroDocFilter) { var sqlBuilder = new StringBuilder(@" SELECT d.*, z.Nombre AS NombreZona FROM dbo.dist_dtDistribuidores d LEFT JOIN dbo.dist_dtZonas z ON d.Id_Zona = z.Id_Zona WHERE 1=1"); var parameters = new DynamicParameters(); if (!string.IsNullOrWhiteSpace(nombreFilter)) { sqlBuilder.Append(" AND d.Nombre LIKE @Nombre"); parameters.Add("Nombre", $"%{nombreFilter}%"); } if (!string.IsNullOrWhiteSpace(nroDocFilter)) { sqlBuilder.Append(" AND d.NroDoc LIKE @NroDoc"); parameters.Add("NroDoc", $"%{nroDocFilter}%"); } sqlBuilder.Append(" ORDER BY d.Nombre;"); try { using var connection = _connectionFactory.CreateConnection(); return await connection.QueryAsync( sqlBuilder.ToString(), (dist, zona) => (dist, zona), parameters, splitOn: "NombreZona" ); } catch (Exception ex) { _logger.LogError(ex, "Error al obtener todos los Distribuidores."); return Enumerable.Empty<(Distribuidor, string?)>(); } } public async Task<(Distribuidor? Distribuidor, string? NombreZona)> GetByIdAsync(int id) { const string sql = @" SELECT d.*, z.Nombre AS NombreZona FROM dbo.dist_dtDistribuidores d LEFT JOIN dbo.dist_dtZonas z ON d.Id_Zona = z.Id_Zona WHERE d.Id_Distribuidor = @Id"; try { using var connection = _connectionFactory.CreateConnection(); var result = await connection.QueryAsync( sql, (dist, zona) => (dist, zona), new { Id = id }, splitOn: "NombreZona" ); return result.SingleOrDefault(); } catch (Exception ex) { _logger.LogError(ex, "Error al obtener Distribuidor por ID: {IdDistribuidor}", id); return (null, null); } } public async Task GetByIdSimpleAsync(int id) { const string sql = "SELECT * FROM dbo.dist_dtDistribuidores WHERE Id_Distribuidor = @Id"; using var connection = _connectionFactory.CreateConnection(); return await connection.QuerySingleOrDefaultAsync(sql, new { Id = id }); } public async Task ExistsByNroDocAsync(string nroDoc, int? excludeIdDistribuidor = null) { var sqlBuilder = new StringBuilder("SELECT COUNT(1) FROM dbo.dist_dtDistribuidores WHERE NroDoc = @NroDoc"); var parameters = new DynamicParameters(); parameters.Add("NroDoc", nroDoc); if (excludeIdDistribuidor.HasValue) { sqlBuilder.Append(" AND Id_Distribuidor != @ExcludeId"); parameters.Add("ExcludeId", excludeIdDistribuidor.Value); } using var connection = _connectionFactory.CreateConnection(); return await connection.ExecuteScalarAsync(sqlBuilder.ToString(), parameters); } public async Task ExistsByNameAsync(string nombre, int? excludeIdDistribuidor = null) { var sqlBuilder = new StringBuilder("SELECT COUNT(1) FROM dbo.dist_dtDistribuidores WHERE Nombre = @Nombre"); var parameters = new DynamicParameters(); parameters.Add("Nombre", nombre); if (excludeIdDistribuidor.HasValue) { sqlBuilder.Append(" AND Id_Distribuidor != @ExcludeId"); parameters.Add("ExcludeId", excludeIdDistribuidor.Value); } using var connection = _connectionFactory.CreateConnection(); return await connection.ExecuteScalarAsync(sqlBuilder.ToString(), parameters); } public async Task IsInUseAsync(int id) { using var connection = _connectionFactory.CreateConnection(); string[] checkQueries = { "SELECT TOP 1 1 FROM dbo.dist_EntradasSalidas WHERE Id_Distribuidor = @Id", "SELECT TOP 1 1 FROM dbo.cue_PagosDistribuidor WHERE Id_Distribuidor = @Id", "SELECT TOP 1 1 FROM dbo.dist_PorcPago WHERE Id_Distribuidor = @Id" }; foreach (var query in checkQueries) { if (await connection.ExecuteScalarAsync(query, new { Id = id }) == 1) return true; } return false; } public async Task CreateAsync(Distribuidor nuevoDistribuidor, int idUsuario, IDbTransaction transaction) { const string sqlInsert = @" INSERT INTO dbo.dist_dtDistribuidores (Nombre, Contacto, NroDoc, Id_Zona, Calle, Numero, Piso, Depto, Telefono, Email, Localidad) OUTPUT INSERTED.* VALUES (@Nombre, @Contacto, @NroDoc, @IdZona, @Calle, @Numero, @Piso, @Depto, @Telefono, @Email, @Localidad);"; const string sqlInsertHistorico = @" INSERT INTO dbo.dist_dtDistribuidores_H (Id_Distribuidor, Nombre, Contacto, NroDoc, Id_Zona, Calle, Numero, Piso, Depto, Telefono, Email, Localidad, Id_Usuario, FechaMod, TipoMod) VALUES (@IdDistribuidor, @Nombre, @Contacto, @NroDoc, @IdZona, @Calle, @Numero, @Piso, @Depto, @Telefono, @Email, @Localidad, @Id_Usuario, @FechaMod, @TipoMod);"; var connection = transaction.Connection!; var inserted = await connection.QuerySingleAsync(sqlInsert, nuevoDistribuidor, transaction); if (inserted == null) throw new DataException("Error al crear distribuidor."); await connection.ExecuteAsync(sqlInsertHistorico, new { inserted.IdDistribuidor, inserted.Nombre, inserted.Contacto, inserted.NroDoc, inserted.IdZona, inserted.Calle, inserted.Numero, inserted.Piso, inserted.Depto, inserted.Telefono, inserted.Email, inserted.Localidad, Id_Usuario = idUsuario, FechaMod = DateTime.Now, TipoMod = "Creado" }, transaction); return inserted; } public async Task UpdateAsync(Distribuidor distribuidorAActualizar, int idUsuario, IDbTransaction transaction) { var connection = transaction.Connection!; var actual = await connection.QuerySingleOrDefaultAsync( "SELECT * FROM dbo.dist_dtDistribuidores WHERE Id_Distribuidor = @IdDistribuidor", new { distribuidorAActualizar.IdDistribuidor }, transaction); if (actual == null) throw new KeyNotFoundException("Distribuidor no encontrado."); const string sqlUpdate = @" UPDATE dbo.dist_dtDistribuidores SET Nombre = @Nombre, Contacto = @Contacto, NroDoc = @NroDoc, Id_Zona = @IdZona, Calle = @Calle, Numero = @Numero, Piso = @Piso, Depto = @Depto, Telefono = @Telefono, Email = @Email, Localidad = @Localidad WHERE Id_Distribuidor = @IdDistribuidor;"; const string sqlInsertHistorico = @" INSERT INTO dbo.dist_dtDistribuidores_H (Id_Distribuidor, Nombre, Contacto, NroDoc, Id_Zona, Calle, Numero, Piso, Depto, Telefono, Email, Localidad, Id_Usuario, FechaMod, TipoMod) VALUES (@IdDistribuidor, @Nombre, @Contacto, @NroDoc, @IdZona, @Calle, @Numero, @Piso, @Depto, @Telefono, @Email, @Localidad, @Id_Usuario, @FechaMod, @TipoMod);"; await connection.ExecuteAsync(sqlInsertHistorico, new { IdDistribuidor = actual.IdDistribuidor, Nombre = actual.Nombre, Contacto = actual.Contacto, NroDoc = actual.NroDoc, IdZona = actual.IdZona, Calle = actual.Calle, Numero = actual.Numero, Piso = actual.Piso, Depto = actual.Depto, Telefono = actual.Telefono, Email = actual.Email, Localidad = actual.Localidad, Id_Usuario = idUsuario, FechaMod = DateTime.Now, TipoMod = "Actualizado" }, transaction); var rowsAffected = await connection.ExecuteAsync(sqlUpdate, distribuidorAActualizar, transaction); return rowsAffected == 1; } public async Task DeleteAsync(int id, int idUsuario, IDbTransaction transaction) { var connection = transaction.Connection!; var actual = await connection.QuerySingleOrDefaultAsync( "SELECT * FROM dbo.dist_dtDistribuidores WHERE Id_Distribuidor = @Id", new { Id = id }, transaction); if (actual == null) throw new KeyNotFoundException("Distribuidor no encontrado."); const string sqlDelete = "DELETE FROM dbo.dist_dtDistribuidores WHERE Id_Distribuidor = @Id"; const string sqlInsertHistorico = @" INSERT INTO dbo.dist_dtDistribuidores_H (Id_Distribuidor, Nombre, Contacto, NroDoc, Id_Zona, Calle, Numero, Piso, Depto, Telefono, Email, Localidad, Id_Usuario, FechaMod, TipoMod) VALUES (@IdDistribuidor, @Nombre, @Contacto, @NroDoc, @IdZona, @Calle, @Numero, @Piso, @Depto, @Telefono, @Email, @Localidad, @Id_Usuario, @FechaMod, @TipoMod);"; await connection.ExecuteAsync(sqlInsertHistorico, new { IdDistribuidor = actual.IdDistribuidor, actual.Nombre, actual.Contacto, actual.NroDoc, actual.IdZona, actual.Calle, actual.Numero, actual.Piso, actual.Depto, actual.Telefono, actual.Email, actual.Localidad, Id_Usuario = idUsuario, FechaMod = DateTime.Now, TipoMod = "Eliminado" }, transaction); var rowsAffected = await connection.ExecuteAsync(sqlDelete, new { Id = id }, transaction); return rowsAffected == 1; } } }