using GestionIntegral.Api.Data; using GestionIntegral.Api.Data.Repositories.Usuarios; using GestionIntegral.Api.Dtos.Auditoria; using GestionIntegral.Api.Dtos.Usuarios; using GestionIntegral.Api.Models.Usuarios; using Microsoft.Extensions.Logging; using System.Collections.Generic; using System.Data; using System.Linq; using System.Threading.Tasks; namespace GestionIntegral.Api.Services.Usuarios { public class PermisoService : IPermisoService { private readonly IPermisoRepository _permisoRepository; private readonly DbConnectionFactory _connectionFactory; // Inyectar para transacciones private readonly ILogger _logger; public PermisoService(IPermisoRepository permisoRepository, DbConnectionFactory connectionFactory, ILogger logger) { _permisoRepository = permisoRepository; _connectionFactory = connectionFactory; // Asignar _logger = logger; } private PermisoDto MapToDto(Permiso permiso) => new PermisoDto { Id = permiso.Id, Modulo = permiso.Modulo, DescPermiso = permiso.DescPermiso, CodAcc = permiso.CodAcc }; public async Task> ObtenerTodosAsync(string? moduloFilter, string? codAccFilter) { var permisos = await _permisoRepository.GetAllAsync(moduloFilter, codAccFilter); return permisos.Select(MapToDto); } public async Task ObtenerPorIdAsync(int id) { var permiso = await _permisoRepository.GetByIdAsync(id); return permiso == null ? null : MapToDto(permiso); } public async Task<(PermisoDto? Permiso, string? Error)> CrearAsync(CreatePermisoDto createDto, int idUsuario) { if (await _permisoRepository.ExistsByCodAccAsync(createDto.CodAcc)) { return (null, "El código de acceso (CodAcc) ya existe."); } var nuevoPermiso = new Permiso { Modulo = createDto.Modulo, DescPermiso = createDto.DescPermiso, CodAcc = createDto.CodAcc }; 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 permisoCreado = await _permisoRepository.CreateAsync(nuevoPermiso, idUsuario, transaction); if (permisoCreado == null) throw new DataException("La creación en el repositorio devolvió null."); transaction.Commit(); _logger.LogInformation("Permiso ID {IdPermiso} creado por Usuario ID {IdUsuario}.", permisoCreado.Id, idUsuario); return (MapToDto(permisoCreado), null); } catch (Exception ex) { try { transaction.Rollback(); } catch (Exception rbEx) { _logger.LogError(rbEx, "Error rollback CrearAsync Permiso."); } _logger.LogError(ex, "Error CrearAsync Permiso. CodAcc: {CodAcc}", createDto.CodAcc); return (null, $"Error interno al crear el permiso: {ex.Message}"); } } public async Task<(bool Exito, string? Error)> ActualizarAsync(int id, UpdatePermisoDto updateDto, int idUsuario) { var permisoExistente = await _permisoRepository.GetByIdAsync(id); // Verificar existencia fuera de la TX if (permisoExistente == null) return (false, "Permiso no encontrado."); if (await _permisoRepository.ExistsByCodAccAsync(updateDto.CodAcc, id)) { return (false, "El código de acceso (CodAcc) ya existe para otro permiso."); } var permisoAActualizar = new Permiso { Id = id, Modulo = updateDto.Modulo, DescPermiso = updateDto.DescPermiso, CodAcc = updateDto.CodAcc }; 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 _permisoRepository.UpdateAsync(permisoAActualizar, idUsuario, transaction); if (!actualizado) throw new DataException("La operación de actualización no afectó ninguna fila."); transaction.Commit(); _logger.LogInformation("Permiso ID {IdPermiso} actualizado por Usuario ID {IdUsuario}.", id, idUsuario); return (true, null); } catch (KeyNotFoundException knfex) { try { transaction.Rollback(); } catch (Exception rbEx) { _logger.LogError(rbEx, "Error rollback ActualizarAsync Permiso (KeyNotFound)."); } _logger.LogWarning(knfex, "Intento de actualizar Permiso ID: {Id} no encontrado dentro de la transacción.", id); return (false, "Permiso no encontrado."); } catch (Exception ex) { try { transaction.Rollback(); } catch (Exception rbEx) { _logger.LogError(rbEx, "Error rollback ActualizarAsync Permiso."); } _logger.LogError(ex, "Error ActualizarAsync Permiso ID: {Id}", id); return (false, $"Error interno al actualizar el permiso: {ex.Message}"); } } public async Task<(bool Exito, string? Error)> EliminarAsync(int id, int idUsuario) { var permisoExistente = await _permisoRepository.GetByIdAsync(id); // Verificar existencia fuera de la TX if (permisoExistente == null) return (false, "Permiso no encontrado."); if (await _permisoRepository.IsInUseAsync(id)) { return (false, "No se puede eliminar. El permiso está asignado a uno o más perfiles."); } 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 _permisoRepository.DeleteAsync(id, idUsuario, transaction); if (!eliminado) throw new DataException("La operación de eliminación no afectó ninguna fila."); transaction.Commit(); _logger.LogInformation("Permiso ID {IdPermiso} eliminado por Usuario ID {IdUsuario}.", id, idUsuario); return (true, null); } catch (KeyNotFoundException knfex) { try { transaction.Rollback(); } catch (Exception rbEx) { _logger.LogError(rbEx, "Error rollback EliminarAsync Permiso (KeyNotFound)."); } _logger.LogWarning(knfex, "Intento de eliminar Permiso ID: {Id} no encontrado dentro de la transacción.", id); return (false, "Permiso no encontrado."); } catch (Exception ex) { try { transaction.Rollback(); } catch (Exception rbEx) { _logger.LogError(rbEx, "Error rollback EliminarAsync Permiso."); } _logger.LogError(ex, "Error EliminarAsync Permiso ID: {Id}", id); return (false, $"Error interno al eliminar el permiso: {ex.Message}"); } } public async Task> ObtenerHistorialAsync( DateTime? fechaDesde, DateTime? fechaHasta, int? idUsuarioModifico, string? tipoModificacion, int? idPermisoAfectado) { var historialData = await _permisoRepository.GetHistorialAsync(fechaDesde, fechaHasta, idUsuarioModifico, tipoModificacion, idPermisoAfectado); return historialData.Select(h => new PermisoHistorialDto { IdHistorial = h.Historial.IdHist, IdPermiso = h.Historial.IdPermiso, Modulo = h.Historial.Modulo, DescPermiso = h.Historial.DescPermiso, CodAcc = h.Historial.CodAcc, Id_Usuario = h.Historial.Id_Usuario, NombreUsuarioModifico = h.NombreUsuarioModifico, FechaMod = h.Historial.FechaMod, TipoMod = h.Historial.TipoMod }).ToList(); } } }