using GestionIntegral.Api.Data; using GestionIntegral.Api.Data.Repositories.Impresion; using GestionIntegral.Api.Dtos.Impresion; using GestionIntegral.Api.Models.Impresion; using Microsoft.Extensions.Logging; using System.Collections.Generic; using System.Data; using System.Linq; using System.Threading.Tasks; namespace GestionIntegral.Api.Services.Impresion { public class TipoBobinaService : ITipoBobinaService { private readonly ITipoBobinaRepository _tipoBobinaRepository; private readonly DbConnectionFactory _connectionFactory; private readonly ILogger _logger; public TipoBobinaService(ITipoBobinaRepository tipoBobinaRepository, DbConnectionFactory connectionFactory, ILogger logger) { _tipoBobinaRepository = tipoBobinaRepository; _connectionFactory = connectionFactory; _logger = logger; } private TipoBobinaDto MapToDto(TipoBobina tipoBobina) => new TipoBobinaDto { IdTipoBobina = tipoBobina.IdTipoBobina, Denominacion = tipoBobina.Denominacion }; public async Task> ObtenerTodosAsync(string? denominacionFilter) { var tiposBobina = await _tipoBobinaRepository.GetAllAsync(denominacionFilter); return tiposBobina.Select(MapToDto); } public async Task ObtenerPorIdAsync(int id) { var tipoBobina = await _tipoBobinaRepository.GetByIdAsync(id); return tipoBobina == null ? null : MapToDto(tipoBobina); } public async Task<(TipoBobinaDto? TipoBobina, string? Error)> CrearAsync(CreateTipoBobinaDto createDto, int idUsuario) { if (await _tipoBobinaRepository.ExistsByDenominacionAsync(createDto.Denominacion)) { return (null, "La denominación del tipo de bobina ya existe."); } var nuevoTipoBobina = new TipoBobina { Denominacion = createDto.Denominacion }; using var connection = _connectionFactory.CreateConnection(); if (connection is System.Data.Common.DbConnection dbConnection) { await dbConnection.OpenAsync(); } else { connection.Open(); } using var transaction = connection.BeginTransaction(IsolationLevel.ReadCommitted); try { var tipoBobinaCreado = await _tipoBobinaRepository.CreateAsync(nuevoTipoBobina, idUsuario, transaction); if (tipoBobinaCreado == null) throw new DataException("La creación en el repositorio devolvió null."); transaction.Commit(); // Síncrono _logger.LogInformation("TipoBobina ID {IdTipoBobina} creado por Usuario ID {IdUsuario}.", tipoBobinaCreado.IdTipoBobina, idUsuario); return (MapToDto(tipoBobinaCreado), null); } catch (Exception ex) { try { transaction.Rollback(); } catch (Exception rbEx) { _logger.LogError(rbEx, "Error adicional durante el rollback en CrearAsync TipoBobina."); } _logger.LogError(ex, "Error en transacción CrearAsync para TipoBobina. Denominación: {Denominacion}", createDto.Denominacion); return (null, $"Error interno al crear el tipo de bobina: {ex.Message}"); } } public async Task<(bool Exito, string? Error)> ActualizarAsync(int id, UpdateTipoBobinaDto updateDto, int idUsuario) { if (await _tipoBobinaRepository.ExistsByDenominacionAsync(updateDto.Denominacion, id)) { return (false, "La denominación del tipo de bobina ya existe para otro registro."); } var tipoBobinaAActualizar = new TipoBobina { IdTipoBobina = id, Denominacion = updateDto.Denominacion }; using var connection = _connectionFactory.CreateConnection(); if (connection is System.Data.Common.DbConnection dbConnection) { await dbConnection.OpenAsync(); } else { connection.Open(); } using var transaction = connection.BeginTransaction(IsolationLevel.ReadCommitted); try { var actualizado = await _tipoBobinaRepository.UpdateAsync(tipoBobinaAActualizar, idUsuario, transaction); if (!actualizado) throw new DataException("La operación de actualización no afectó ninguna fila."); transaction.Commit(); // Síncrono _logger.LogInformation("TipoBobina ID {IdTipoBobina} actualizado por Usuario ID {IdUsuario}.", id, idUsuario); return (true, null); } catch (KeyNotFoundException knfex) { try { transaction.Rollback(); } catch (Exception rbEx) { _logger.LogError(rbEx, "Error adicional durante el rollback en ActualizarAsync TipoBobina."); } _logger.LogWarning(knfex, "Intento de actualizar TipoBobina ID: {Id} no encontrado.", id); return (false, "Tipo de bobina no encontrado."); } catch (Exception ex) { try { transaction.Rollback(); } catch (Exception rbEx) { _logger.LogError(rbEx, "Error adicional durante el rollback en ActualizarAsync TipoBobina."); } _logger.LogError(ex, "Error en transacción ActualizarAsync para TipoBobina ID: {Id}", id); return (false, $"Error interno al actualizar el tipo de bobina: {ex.Message}"); } } public async Task<(bool Exito, string? Error)> EliminarAsync(int id, int idUsuario) { if (await _tipoBobinaRepository.IsInUseAsync(id)) { return (false, "No se puede eliminar. El tipo de bobina está siendo utilizado en el stock."); } using var connection = _connectionFactory.CreateConnection(); if (connection is System.Data.Common.DbConnection dbConnection) { await dbConnection.OpenAsync(); } else { connection.Open(); } using var transaction = connection.BeginTransaction(IsolationLevel.ReadCommitted); try { var eliminado = await _tipoBobinaRepository.DeleteAsync(id, idUsuario, transaction); if (!eliminado) throw new DataException("La operación de eliminación no afectó ninguna fila."); transaction.Commit(); // Síncrono _logger.LogInformation("TipoBobina ID {IdTipoBobina} eliminado por Usuario ID {IdUsuario}.", id, idUsuario); return (true, null); } catch (KeyNotFoundException knfex) { try { transaction.Rollback(); } catch (Exception rbEx) { _logger.LogError(rbEx, "Error adicional durante el rollback en EliminarAsync TipoBobina."); } _logger.LogWarning(knfex, "Intento de eliminar TipoBobina ID: {Id} no encontrado.", id); return (false, "Tipo de bobina no encontrado."); } catch (Exception ex) { try { transaction.Rollback(); } catch (Exception rbEx) { _logger.LogError(rbEx, "Error adicional durante el rollback en EliminarAsync TipoBobina."); } _logger.LogError(ex, "Error en transacción EliminarAsync para TipoBobina ID: {Id}", id); return (false, $"Error interno al eliminar el tipo de bobina: {ex.Message}"); } } } }