using Dapper; using GestionIntegral.Api.Dtos.Distribucion; using GestionIntegral.Api.Models.Distribucion; using Microsoft.Extensions.Logging; using System; // Añadido 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 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.Id_Distribuidor AS IdDistribuidor, d.Nombre, d.Contacto, d.NroDoc, d.Id_Zona AS IdZona, d.Calle, d.Numero, d.Piso, d.Depto, d.Telefono, d.Email, d.Localidad, 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 @NombreParam"); parameters.Add("NombreParam", $"%{nombreFilter}%"); } if (!string.IsNullOrWhiteSpace(nroDocFilter)) { sqlBuilder.Append(" AND d.NroDoc LIKE @NroDocParam"); parameters.Add("NroDocParam", $"%{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. Filtros: Nombre='{NombreFilter}', NroDoc='{NroDocFilter}'", nombreFilter, nroDocFilter); return Enumerable.Empty<(Distribuidor, string?)>(); } } public async Task> GetAllDropdownAsync() { var sqlBuilder = new StringBuilder(@" SELECT Id_Distribuidor AS IdDistribuidor, Nombre FROM dbo.dist_dtDistribuidores WHERE 1=1"); var parameters = new DynamicParameters(); sqlBuilder.Append(" ORDER BY Nombre;"); try { using var connection = _connectionFactory.CreateConnection(); return await connection.QueryAsync( sqlBuilder.ToString(), parameters ); } catch (Exception ex) { _logger.LogError(ex, "Error al obtener todos los Distribuidores."); return Enumerable.Empty(); } } public async Task<(Distribuidor? Distribuidor, string? NombreZona)> GetByIdAsync(int id) { const string sql = @" SELECT d.Id_Distribuidor AS IdDistribuidor, d.Nombre, d.Contacto, d.NroDoc, d.Id_Zona AS IdZona, d.Calle, d.Numero, d.Piso, d.Depto, d.Telefono, d.Email, d.Localidad, 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 = @IdParam"; try { using var connection = _connectionFactory.CreateConnection(); var result = await connection.QueryAsync( sql, (dist, zona) => (dist, zona), new { IdParam = 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 ObtenerLookupPorIdAsync(int id) { const string sql = @" SELECT Id_Distribuidor AS IdDistribuidor, Nombre FROM dbo.dist_dtDistribuidores WHERE Id_Distribuidor = @IdParam"; try { using var connection = _connectionFactory.CreateConnection(); return await connection.QuerySingleOrDefaultAsync(sql, new { IdParam = id }); } catch (Exception ex) { _logger.LogError(ex, "Error al obtener Distribuidor por ID: {IdDistribuidor}", id); return null; } } public async Task GetByIdSimpleAsync(int id) { const string sql = @" SELECT Id_Distribuidor AS IdDistribuidor, Nombre, Contacto, NroDoc, Id_Zona AS IdZona, Calle, Numero, Piso, Depto, Telefono, Email, Localidad FROM dbo.dist_dtDistribuidores WHERE Id_Distribuidor = @IdParam"; try { using var connection = _connectionFactory.CreateConnection(); return await connection.QuerySingleOrDefaultAsync(sql, new { IdParam = id }); } catch (Exception ex) { _logger.LogError(ex, "Error al obtener Distribuidor (simple) por ID: {IdDistribuidor}", id); return null; } } public async Task ExistsByNroDocAsync(string nroDoc, int? excludeIdDistribuidor = null) { var sqlBuilder = new StringBuilder("SELECT COUNT(1) FROM dbo.dist_dtDistribuidores WHERE NroDoc = @NroDocParam"); var parameters = new DynamicParameters(); parameters.Add("NroDocParam", nroDoc); if (excludeIdDistribuidor.HasValue) { sqlBuilder.Append(" AND Id_Distribuidor != @ExcludeIdParam"); parameters.Add("ExcludeIdParam", excludeIdDistribuidor.Value); } try { using var connection = _connectionFactory.CreateConnection(); return await connection.ExecuteScalarAsync(sqlBuilder.ToString(), parameters); } catch (Exception ex) { _logger.LogError(ex, "Error en ExistsByNroDocAsync. NroDoc: {NroDoc}", nroDoc); return true; } } public async Task ExistsByNameAsync(string nombre, int? excludeIdDistribuidor = null) { var sqlBuilder = new StringBuilder("SELECT COUNT(1) FROM dbo.dist_dtDistribuidores WHERE Nombre = @NombreParam"); var parameters = new DynamicParameters(); parameters.Add("NombreParam", nombre); if (excludeIdDistribuidor.HasValue) { sqlBuilder.Append(" AND Id_Distribuidor != @ExcludeIdParam"); parameters.Add("ExcludeIdParam", excludeIdDistribuidor.Value); } try { using var connection = _connectionFactory.CreateConnection(); return await connection.ExecuteScalarAsync(sqlBuilder.ToString(), parameters); } catch (Exception ex) { _logger.LogError(ex, "Error en ExistsByNameAsync. Nombre: {Nombre}", nombre); return true; } } public async Task IsInUseAsync(int id) { using var connection = _connectionFactory.CreateConnection(); string[] checkQueries = { "SELECT TOP 1 1 FROM dbo.dist_EntradasSalidas WHERE Id_Distribuidor = @IdParam", "SELECT TOP 1 1 FROM dbo.cue_PagosDistribuidor WHERE Id_Distribuidor = @IdParam", "SELECT TOP 1 1 FROM dbo.dist_PorcPago WHERE Id_Distribuidor = @IdParam" }; try { foreach (var query in checkQueries) { if (await connection.ExecuteScalarAsync(query, new { IdParam = id }) == 1) return true; } return false; } catch (Exception ex) { _logger.LogError(ex, "Error en IsInUseAsync para Distribuidor ID: {IdDistribuidor}", id); return true; } } 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.Id_Distribuidor AS IdDistribuidor, INSERTED.Nombre, INSERTED.Contacto, INSERTED.NroDoc, INSERTED.Id_Zona AS IdZona, INSERTED.Calle, INSERTED.Numero, INSERTED.Piso, INSERTED.Depto, INSERTED.Telefono, INSERTED.Email, INSERTED.Localidad VALUES (@Nombre, @Contacto, @NroDoc, @IdZona, @Calle, @Numero, @Piso, @Depto, @Telefono, @Email, @Localidad);"; var connection = transaction.Connection!; var inserted = await connection.QuerySingleAsync(sqlInsert, nuevoDistribuidor, transaction); if (inserted == null || inserted.IdDistribuidor == 0) throw new DataException("Error al crear distribuidor o al obtener el ID generado."); 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 (@IdDistribuidorParam, @NombreParam, @ContactoParam, @NroDocParam, @IdZonaParam, @CalleParam, @NumeroParam, @PisoParam, @DeptoParam, @TelefonoParam, @EmailParam, @LocalidadParam, @IdUsuarioParam, @FechaModParam, @TipoModParam);"; await connection.ExecuteAsync(sqlInsertHistorico, new { IdDistribuidorParam = inserted.IdDistribuidor, NombreParam = inserted.Nombre, ContactoParam = inserted.Contacto, NroDocParam = inserted.NroDoc, IdZonaParam = inserted.IdZona, CalleParam = inserted.Calle, NumeroParam = inserted.Numero, PisoParam = inserted.Piso, DeptoParam = inserted.Depto, TelefonoParam = inserted.Telefono, EmailParam = inserted.Email, LocalidadParam = inserted.Localidad, IdUsuarioParam = idUsuario, FechaModParam = DateTime.Now, TipoModParam = "Creado" }, transaction); return inserted; } public async Task UpdateAsync(Distribuidor distribuidorAActualizar, int idUsuario, IDbTransaction transaction) { var connection = transaction.Connection!; var actual = await connection.QuerySingleOrDefaultAsync( @"SELECT Id_Distribuidor AS IdDistribuidor, Nombre, Contacto, NroDoc, Id_Zona AS IdZona, Calle, Numero, Piso, Depto, Telefono, Email, Localidad FROM dbo.dist_dtDistribuidores WHERE Id_Distribuidor = @IdDistribuidorParam", new { IdDistribuidorParam = 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 (@IdDistribuidorParam, @NombreParam, @ContactoParam, @NroDocParam, @IdZonaParam, @CalleParam, @NumeroParam, @PisoParam, @DeptoParam, @TelefonoParam, @EmailParam, @LocalidadParam, @IdUsuarioParam, @FechaModParam, @TipoModParam);"; await connection.ExecuteAsync(sqlInsertHistorico, new { IdDistribuidorParam = actual.IdDistribuidor, NombreParam = actual.Nombre, ContactoParam = actual.Contacto, NroDocParam = actual.NroDoc, IdZonaParam = actual.IdZona, CalleParam = actual.Calle, NumeroParam = actual.Numero, PisoParam = actual.Piso, DeptoParam = actual.Depto, TelefonoParam = actual.Telefono, EmailParam = actual.Email, LocalidadParam = actual.Localidad, IdUsuarioParam = idUsuario, FechaModParam = DateTime.Now, TipoModParam = "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 Id_Distribuidor AS IdDistribuidor, Nombre, Contacto, NroDoc, Id_Zona AS IdZona, Calle, Numero, Piso, Depto, Telefono, Email, Localidad FROM dbo.dist_dtDistribuidores WHERE Id_Distribuidor = @IdParam", new { IdParam = id }, transaction); if (actual == null) throw new KeyNotFoundException("Distribuidor no encontrado."); // ... (resto del método DeleteAsync) const string sqlDelete = "DELETE FROM dbo.dist_dtDistribuidores WHERE Id_Distribuidor = @IdParam"; 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 (@IdDistribuidorParam, @NombreParam, @ContactoParam, @NroDocParam, @IdZonaParam, @CalleParam, @NumeroParam, @PisoParam, @DeptoParam, @TelefonoParam, @EmailParam, @LocalidadParam, @IdUsuarioParam, @FechaModParam, @TipoModParam);"; await connection.ExecuteAsync(sqlInsertHistorico, new { IdDistribuidorParam = actual.IdDistribuidor, NombreParam = actual.Nombre, ContactoParam = actual.Contacto, NroDocParam = actual.NroDoc, IdZonaParam = actual.IdZona, CalleParam = actual.Calle, NumeroParam = actual.Numero, PisoParam = actual.Piso, DeptoParam = actual.Depto, TelefonoParam = actual.Telefono, EmailParam = actual.Email, LocalidadParam = actual.Localidad, IdUsuarioParam = idUsuario, FechaModParam = DateTime.Now, TipoModParam = "Eliminado" }, transaction); var rowsAffected = await connection.ExecuteAsync(sqlDelete, new { IdParam = id }, transaction); return rowsAffected == 1; } } }