using GestionIntegral.Api.Data; using GestionIntegral.Api.Data.Repositories.Distribucion; using GestionIntegral.Api.Dtos.Auditoria; using GestionIntegral.Api.Dtos.Distribucion; using GestionIntegral.Api.Models.Distribucion; using Microsoft.Extensions.Logging; using System.Collections.Generic; using System.Data; using System.Linq; using System.Threading.Tasks; namespace GestionIntegral.Api.Services.Distribucion { public class OtroDestinoService : IOtroDestinoService { private readonly IOtroDestinoRepository _otroDestinoRepository; private readonly DbConnectionFactory _connectionFactory; private readonly ILogger _logger; public OtroDestinoService(IOtroDestinoRepository otroDestinoRepository, DbConnectionFactory connectionFactory, ILogger logger) { _otroDestinoRepository = otroDestinoRepository; _connectionFactory = connectionFactory; _logger = logger; } private OtroDestinoDto MapToDto(OtroDestino destino) => new OtroDestinoDto { IdDestino = destino.IdDestino, Nombre = destino.Nombre, Obs = destino.Obs }; public async Task> ObtenerTodosAsync(string? nombreFilter) { var destinos = await _otroDestinoRepository.GetAllAsync(nombreFilter); return destinos.Select(MapToDto); } public async Task ObtenerPorIdAsync(int id) { var destino = await _otroDestinoRepository.GetByIdAsync(id); return destino == null ? null : MapToDto(destino); } public async Task<(OtroDestinoDto? Destino, string? Error)> CrearAsync(CreateOtroDestinoDto createDto, int idUsuario) { if (await _otroDestinoRepository.ExistsByNameAsync(createDto.Nombre)) { return (null, "El nombre del destino ya existe."); } var nuevoDestino = new OtroDestino { Nombre = createDto.Nombre, Obs = createDto.Obs }; using var connection = _connectionFactory.CreateConnection(); if (connection is System.Data.Common.DbConnection dbConn) await dbConn.OpenAsync(); else connection.Open(); using var transaction = connection.BeginTransaction(IsolationLevel.ReadCommitted); try { var destinoCreado = await _otroDestinoRepository.CreateAsync(nuevoDestino, idUsuario, transaction); if (destinoCreado == null) throw new DataException("La creación en el repositorio devolvió null."); transaction.Commit(); _logger.LogInformation("OtroDestino ID {IdDestino} creado por Usuario ID {IdUsuario}.", destinoCreado.IdDestino, idUsuario); return (MapToDto(destinoCreado), null); } catch (Exception ex) { try { transaction.Rollback(); } catch { /* Log Rollback Error */ } _logger.LogError(ex, "Error CrearAsync OtroDestino. Nombre: {Nombre}", createDto.Nombre); return (null, $"Error interno al crear el destino: {ex.Message}"); } } public async Task<(bool Exito, string? Error)> ActualizarAsync(int id, UpdateOtroDestinoDto updateDto, int idUsuario) { if (await _otroDestinoRepository.ExistsByNameAsync(updateDto.Nombre, id)) { return (false, "El nombre del destino ya existe para otro registro."); } var destinoAActualizar = new OtroDestino { IdDestino = id, Nombre = updateDto.Nombre, Obs = updateDto.Obs }; using var connection = _connectionFactory.CreateConnection(); if (connection is System.Data.Common.DbConnection dbConn) await dbConn.OpenAsync(); else connection.Open(); using var transaction = connection.BeginTransaction(IsolationLevel.ReadCommitted); try { var actualizado = await _otroDestinoRepository.UpdateAsync(destinoAActualizar, idUsuario, transaction); if (!actualizado) throw new DataException("La operación de actualización no afectó ninguna fila."); transaction.Commit(); _logger.LogInformation("OtroDestino ID {IdDestino} actualizado por Usuario ID {IdUsuario}.", id, idUsuario); return (true, null); } catch (KeyNotFoundException) { try { transaction.Rollback(); } catch { /* Log Rollback Error */ } return (false, "Otro Destino no encontrado."); } catch (Exception ex) { try { transaction.Rollback(); } catch { /* Log Rollback Error */ } _logger.LogError(ex, "Error ActualizarAsync OtroDestino ID: {Id}", id); return (false, $"Error interno al actualizar el destino: {ex.Message}"); } } public async Task<(bool Exito, string? Error)> EliminarAsync(int id, int idUsuario) { if (await _otroDestinoRepository.IsInUseAsync(id)) { return (false, "No se puede eliminar. El destino está siendo utilizado en salidas registradas."); } using var connection = _connectionFactory.CreateConnection(); if (connection is System.Data.Common.DbConnection dbConn) await dbConn.OpenAsync(); else connection.Open(); using var transaction = connection.BeginTransaction(IsolationLevel.ReadCommitted); try { var eliminado = await _otroDestinoRepository.DeleteAsync(id, idUsuario, transaction); if (!eliminado) throw new DataException("La operación de eliminación no afectó ninguna fila."); transaction.Commit(); _logger.LogInformation("OtroDestino ID {IdDestino} eliminado por Usuario ID {IdUsuario}.", id, idUsuario); return (true, null); } catch (KeyNotFoundException) { try { transaction.Rollback(); } catch { /* Log Rollback Error */ } return (false, "Otro Destino no encontrado."); } catch (Exception ex) { try { transaction.Rollback(); } catch { /* Log Rollback Error */ } _logger.LogError(ex, "Error EliminarAsync OtroDestino ID: {Id}", id); return (false, $"Error interno al eliminar el destino: {ex.Message}"); } } public async Task> ObtenerHistorialAsync( DateTime? fechaDesde, DateTime? fechaHasta, int? idUsuarioModifico, string? tipoModificacion, int? idOtroDestinoAfectado) { var historialData = await _otroDestinoRepository.GetHistorialAsync(fechaDesde, fechaHasta, idUsuarioModifico, tipoModificacion, idOtroDestinoAfectado); return historialData.Select(h => new OtroDestinoHistorialDto { Id_Destino = h.Historial.Id_Destino, Nombre = h.Historial.Nombre, Obs = h.Historial.Obs, Id_Usuario = h.Historial.Id_Usuario, NombreUsuarioModifico = h.NombreUsuarioModifico, FechaMod = h.Historial.FechaMod, TipoMod = h.Historial.TipoMod }).ToList(); } } }