using Dapper; using GestionIntegral.Api.Data.Repositories; using GestionIntegral.Api.Models.Distribucion; using System.Collections.Generic; using System.Data; using System.Text; using System.Threading.Tasks; namespace GestionIntegral.Api.Data.Repositories.Distribucion { public class EmpresaRepository : IEmpresaRepository { private readonly DbConnectionFactory _connectionFactory; private readonly ILogger _logger; public EmpresaRepository(DbConnectionFactory connectionFactory, ILogger logger) { _connectionFactory = connectionFactory; _logger = logger; } // --- Métodos de Lectura (no necesitan transacción explícita aquí) --- public async Task> GetAllAsync(string? nombreFilter, string? detalleFilter) { var sqlBuilder = new StringBuilder("SELECT Id_Empresa AS IdEmpresa, Nombre, Detalle FROM dbo.dist_dtEmpresas WHERE 1=1"); var parameters = new DynamicParameters(); if (!string.IsNullOrWhiteSpace(nombreFilter)) { sqlBuilder.Append(" AND Nombre LIKE @NombreFilter"); parameters.Add("NombreFilter", $"%{nombreFilter}%"); } if (!string.IsNullOrWhiteSpace(detalleFilter)) { sqlBuilder.Append(" AND Detalle LIKE @DetalleFilter"); parameters.Add("DetalleFilter", $"%{detalleFilter}%"); } 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 todas las Empresas."); return Enumerable.Empty(); } } public async Task GetByIdAsync(int id) { var sql = "SELECT Id_Empresa AS IdEmpresa, Nombre, Detalle FROM dbo.dist_dtEmpresas WHERE Id_Empresa = @Id"; try { using (var connection = _connectionFactory.CreateConnection()) { return await connection.QuerySingleOrDefaultAsync(sql, new { Id = id }); } } catch (Exception ex) { _logger.LogError(ex, "Error al obtener Empresa por ID: {IdEmpresa}", id); return null; } } public async Task ExistsByNameAsync(string nombre, int? excludeId = null) { var sqlBuilder = new StringBuilder("SELECT COUNT(1) FROM dbo.dist_dtEmpresas WHERE Nombre = @Nombre"); var parameters = new DynamicParameters(); parameters.Add("Nombre", nombre); if (excludeId.HasValue) { sqlBuilder.Append(" AND Id_Empresa != @ExcludeId"); parameters.Add("ExcludeId", excludeId.Value); } try { using (var connection = _connectionFactory.CreateConnection()) { var count = await connection.ExecuteScalarAsync(sqlBuilder.ToString(), parameters); return count > 0; } } catch (Exception ex) { _logger.LogError(ex, "Error en ExistsByNameAsync para Empresa con nombre: {Nombre}", nombre); return true; // Asumir que existe si hay error } } public async Task IsInUseAsync(int id) { // Verifica si la empresa está referenciada en dist_dtPublicaciones var sql = "SELECT COUNT(1) FROM dbo.dist_dtPublicaciones WHERE Id_Empresa = @IdEmpresa"; try { using (var connection = _connectionFactory.CreateConnection()) { var count = await connection.ExecuteScalarAsync(sql, new { IdEmpresa = id }); return count > 0; } } catch (Exception ex) { _logger.LogError(ex, "Error en IsInUseAsync para Empresa ID: {IdEmpresa}", id); return true; // Asumir en uso si hay error } } // --- Métodos de Escritura (USAN TRANSACCIÓN PASADA DESDE EL SERVICIO) --- public async Task CreateAsync(Empresa nuevaEmpresa, int idUsuario, IDbTransaction transaction) { var sqlInsert = @" INSERT INTO dbo.dist_dtEmpresas (Nombre, Detalle) OUTPUT INSERTED.Id_Empresa AS IdEmpresa, INSERTED.Nombre, INSERTED.Detalle VALUES (@Nombre, @Detalle);"; var sqlInsertHistorico = @" INSERT INTO dbo.dist_dtEmpresas_H (Id_Empresa, Nombre, Detalle, Id_Usuario, FechaMod, TipoMod) VALUES (@IdEmpresa, @Nombre, @Detalle, @IdUsuario, @FechaMod, @TipoMod);"; // La ejecución y manejo de errores/commit/rollback se hará en el SERVICIO // Aquí solo ejecutamos los comandos DENTRO de la transacción existente. // Obtener el ID y datos insertados var insertedEmpresa = await transaction.Connection!.QuerySingleAsync( sqlInsert, new { nuevaEmpresa.Nombre, nuevaEmpresa.Detalle }, transaction: transaction ); if (insertedEmpresa == null || insertedEmpresa.IdEmpresa <= 0) { throw new Exception("No se pudo obtener el ID de la empresa insertada."); } // Insertar en historial await transaction.Connection!.ExecuteAsync(sqlInsertHistorico, new { IdEmpresa = insertedEmpresa.IdEmpresa, insertedEmpresa.Nombre, insertedEmpresa.Detalle, IdUsuario = idUsuario, FechaMod = DateTime.Now, TipoMod = "Insertada" }, transaction: transaction); return insertedEmpresa; // Devolver la entidad con el ID } public async Task UpdateAsync(Empresa empresaAActualizar, int idUsuario, IDbTransaction transaction) { // El servicio ya verificó que existe. Obtenemos estado actual para historial. var empresaActual = await GetByIdAsync(empresaAActualizar.IdEmpresa); // Podría fallar si ya no existe, controlar en servicio if (empresaActual == null) throw new InvalidOperationException("No se encontró la empresa para obtener datos para el historial de actualización."); var sqlUpdate = @" UPDATE dbo.dist_dtEmpresas SET Nombre = @Nombre, Detalle = @Detalle WHERE Id_Empresa = @IdEmpresa;"; var sqlInsertHistorico = @" INSERT INTO dbo.dist_dtEmpresas_H (Id_Empresa, Nombre, Detalle, Id_Usuario, FechaMod, TipoMod) VALUES (@IdEmpresa, @NombreActual, @DetalleActual, @IdUsuario, @FechaMod, @TipoMod);"; // Insertar en historial (estado anterior) await transaction.Connection!.ExecuteAsync(sqlInsertHistorico, new { IdEmpresa = empresaActual.IdEmpresa, NombreActual = empresaActual.Nombre, DetalleActual = empresaActual.Detalle, IdUsuario = idUsuario, FechaMod = DateTime.Now, TipoMod = "Modificada" }, transaction: transaction); // Actualizar principal var rowsAffected = await transaction.Connection!.ExecuteAsync(sqlUpdate, new { empresaAActualizar.Nombre, empresaAActualizar.Detalle, empresaAActualizar.IdEmpresa }, transaction: transaction); return rowsAffected == 1; } public async Task DeleteAsync(int id, int idUsuario, IDbTransaction transaction) { var empresaActual = await GetByIdAsync(id); // Obtener datos para historial if (empresaActual == null) throw new InvalidOperationException("No se encontró la empresa para obtener datos para el historial de eliminación."); var sqlDelete = "DELETE FROM dbo.dist_dtEmpresas WHERE Id_Empresa = @Id"; var sqlInsertHistorico = @" INSERT INTO dbo.dist_dtEmpresas_H (Id_Empresa, Nombre, Detalle, Id_Usuario, FechaMod, TipoMod) VALUES (@IdEmpresa, @Nombre, @Detalle, @IdUsuario, @FechaMod, @TipoMod);"; // Insertar en historial (estado antes de borrar) await transaction.Connection!.ExecuteAsync(sqlInsertHistorico, new { IdEmpresa = empresaActual.IdEmpresa, empresaActual.Nombre, empresaActual.Detalle, IdUsuario = idUsuario, FechaMod = DateTime.Now, TipoMod = "Eliminada" }, transaction: transaction); // Eliminar de la tabla principal var rowsAffected = await transaction.Connection!.ExecuteAsync(sqlDelete, new { Id = id }, transaction: transaction); return rowsAffected == 1; } } }