using Dapper; using GestionIntegral.Api.Models.Impresion; using Microsoft.Extensions.Logging; using System.Collections.Generic; using System.Data; using System.Text; // Para StringBuilder using System.Threading.Tasks; namespace GestionIntegral.Api.Data.Repositories.Impresion { public class PlantaRepository : IPlantaRepository { private readonly DbConnectionFactory _connectionFactory; private readonly ILogger _logger; public PlantaRepository(DbConnectionFactory connectionFactory, ILogger logger) { _connectionFactory = connectionFactory; _logger = logger; } public async Task> GetAllAsync(string? nombreFilter, string? detalleFilter) { var sqlBuilder = new StringBuilder("SELECT Id_Planta AS IdPlanta, Nombre, Detalle FROM dbo.bob_dtPlantas 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 Plantas. Filtros: Nombre={Nombre}, Detalle={Detalle}", nombreFilter, detalleFilter); return Enumerable.Empty(); } } public async Task GetByIdAsync(int id) { const string sql = "SELECT Id_Planta AS IdPlanta, Nombre, Detalle FROM dbo.bob_dtPlantas WHERE Id_Planta = @Id"; try { using var connection = _connectionFactory.CreateConnection(); return await connection.QuerySingleOrDefaultAsync(sql, new { Id = id }); } catch (Exception ex) { _logger.LogError(ex, "Error al obtener Planta por ID: {IdPlanta}", id); return null; } } public async Task ExistsByNameAsync(string nombre, int? excludeId = null) { var sqlBuilder = new StringBuilder("SELECT COUNT(1) FROM dbo.bob_dtPlantas WHERE Nombre = @Nombre"); var parameters = new DynamicParameters(); parameters.Add("Nombre", nombre); if (excludeId.HasValue) { sqlBuilder.Append(" AND Id_Planta != @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 Planta con nombre: {Nombre}", nombre); // Asumir que existe en caso de error para prevenir duplicados accidentales return true; } } public async Task IsInUseAsync(int id) { // Verificar si la planta está referenciada en bob_StockBobinas O bob_RegPublicaciones const string sqlCheckStock = "SELECT TOP 1 1 FROM dbo.bob_StockBobinas WHERE Id_Planta = @IdPlanta"; const string sqlCheckRegPubli = "SELECT TOP 1 1 FROM dbo.bob_RegPublicaciones WHERE Id_Planta = @IdPlanta"; try { using var connection = _connectionFactory.CreateConnection(); var inStock = await connection.ExecuteScalarAsync(sqlCheckStock, new { IdPlanta = id }); if (inStock.HasValue && inStock.Value == 1) return true; var inRegPubli = await connection.ExecuteScalarAsync(sqlCheckRegPubli, new { IdPlanta = id }); return inRegPubli.HasValue && inRegPubli.Value == 1; } catch (Exception ex) { _logger.LogError(ex, "Error en IsInUseAsync para Planta ID: {IdPlanta}", id); // Asumir que está en uso si hay error para prevenir borrado incorrecto return true; } } // --- Métodos de Escritura (USAN TRANSACCIÓN PASADA DESDE EL SERVICIO) --- public async Task CreateAsync(Planta nuevaPlanta, int idUsuario, IDbTransaction transaction) { const string sqlInsert = @" INSERT INTO dbo.bob_dtPlantas (Nombre, Detalle) OUTPUT INSERTED.Id_Planta AS IdPlanta, INSERTED.Nombre, INSERTED.Detalle VALUES (@Nombre, @Detalle);"; const string sqlInsertHistorico = @" INSERT INTO dbo.bob_dtPlantas_H (Id_Planta, Nombre, Detalle, Id_Usuario, FechaMod, TipoMod) VALUES (@IdPlanta, @Nombre, @Detalle, @IdUsuario, @FechaMod, @TipoMod);"; // Dapper requiere que la conexión esté asociada a la transacción var connection = transaction.Connection ?? throw new InvalidOperationException("Transaction has no associated connection."); var insertedPlanta = await connection.QuerySingleAsync( sqlInsert, new { nuevaPlanta.Nombre, nuevaPlanta.Detalle }, transaction: transaction // Pasar la transacción ); if (insertedPlanta == null || insertedPlanta.IdPlanta <= 0) { throw new DataException("No se pudo obtener el ID de la planta insertada."); // Usar DataException } // Insertar en historial await connection.ExecuteAsync(sqlInsertHistorico, new { IdPlanta = insertedPlanta.IdPlanta, insertedPlanta.Nombre, insertedPlanta.Detalle, IdUsuario = idUsuario, FechaMod = DateTime.Now, TipoMod = "Insertada" }, transaction: transaction); return insertedPlanta; // Devolver la entidad con el ID } public async Task UpdateAsync(Planta plantaAActualizar, int idUsuario, IDbTransaction transaction) { // El servicio ya verificó que existe. Obtener estado actual para historial dentro de la transacción. var connection = transaction.Connection!; var plantaActual = await connection.QuerySingleOrDefaultAsync( "SELECT Id_Planta AS IdPlanta, Nombre, Detalle FROM dbo.bob_dtPlantas WHERE Id_Planta = @Id", new { Id = plantaAActualizar.IdPlanta }, transaction); if (plantaActual == null) throw new KeyNotFoundException($"No se encontró la planta con ID {plantaAActualizar.IdPlanta} para actualizar."); // Más específico const string sqlUpdate = @" UPDATE dbo.bob_dtPlantas SET Nombre = @Nombre, Detalle = @Detalle WHERE Id_Planta = @IdPlanta;"; const string sqlInsertHistorico = @" INSERT INTO dbo.bob_dtPlantas_H (Id_Planta, Nombre, Detalle, Id_Usuario, FechaMod, TipoMod) VALUES (@IdPlanta, @NombreActual, @DetalleActual, @IdUsuario, @FechaMod, @TipoMod);"; // Insertar en historial (estado anterior) await connection.ExecuteAsync(sqlInsertHistorico, new { IdPlanta = plantaActual.IdPlanta, NombreActual = plantaActual.Nombre, DetalleActual = plantaActual.Detalle, IdUsuario = idUsuario, FechaMod = DateTime.Now, TipoMod = "Modificada" }, transaction: transaction); // Actualizar principal var rowsAffected = await connection.ExecuteAsync(sqlUpdate, new { plantaAActualizar.Nombre, plantaAActualizar.Detalle, plantaAActualizar.IdPlanta }, transaction: transaction); return rowsAffected == 1; } public async Task DeleteAsync(int id, int idUsuario, IDbTransaction transaction) { var connection = transaction.Connection!; // Obtener datos para historial ANTES de borrar var plantaActual = await connection.QuerySingleOrDefaultAsync( "SELECT Id_Planta AS IdPlanta, Nombre, Detalle FROM dbo.bob_dtPlantas WHERE Id_Planta = @Id", new { Id = id }, transaction); if (plantaActual == null) throw new KeyNotFoundException($"No se encontró la planta con ID {id} para eliminar."); const string sqlDelete = "DELETE FROM dbo.bob_dtPlantas WHERE Id_Planta = @Id"; const string sqlInsertHistorico = @" INSERT INTO dbo.bob_dtPlantas_H (Id_Planta, Nombre, Detalle, Id_Usuario, FechaMod, TipoMod) VALUES (@IdPlanta, @Nombre, @Detalle, @IdUsuario, @FechaMod, @TipoMod);"; // Insertar en historial (estado antes de borrar) await connection.ExecuteAsync(sqlInsertHistorico, new { IdPlanta = plantaActual.IdPlanta, plantaActual.Nombre, plantaActual.Detalle, IdUsuario = idUsuario, FechaMod = DateTime.Now, TipoMod = "Eliminada" }, transaction: transaction); // Eliminar de la tabla principal var rowsAffected = await connection.ExecuteAsync(sqlDelete, new { Id = id }, transaction: transaction); return rowsAffected == 1; } } }