using Dapper; using GestionIntegral.Api.Models.Usuarios; using Microsoft.Extensions.Logging; using System.Collections.Generic; using System.Data; using System.Linq; using System.Text; using System.Threading.Tasks; namespace GestionIntegral.Api.Data.Repositories.Usuarios { public class PermisoRepository : IPermisoRepository { private readonly DbConnectionFactory _connectionFactory; private readonly ILogger _logger; public PermisoRepository(DbConnectionFactory connectionFactory, ILogger logger) { _connectionFactory = connectionFactory; _logger = logger; } public async Task> GetAllAsync(string? moduloFilter, string? codAccFilter) { var sqlBuilder = new StringBuilder("SELECT id AS Id, modulo, descPermiso, codAcc FROM dbo.gral_Permisos WHERE 1=1"); var parameters = new DynamicParameters(); if (!string.IsNullOrWhiteSpace(moduloFilter)) { sqlBuilder.Append(" AND modulo LIKE @ModuloFilter"); parameters.Add("ModuloFilter", $"%{moduloFilter}%"); } if (!string.IsNullOrWhiteSpace(codAccFilter)) { sqlBuilder.Append(" AND codAcc LIKE @CodAccFilter"); parameters.Add("CodAccFilter", $"%{codAccFilter}%"); } sqlBuilder.Append(" ORDER BY modulo, codAcc;"); try { using var connection = _connectionFactory.CreateConnection(); return await connection.QueryAsync(sqlBuilder.ToString(), parameters); } catch (Exception ex) { _logger.LogError(ex, "Error al obtener todos los Permisos. Filtros: Modulo={Modulo}, CodAcc={CodAcc}", moduloFilter, codAccFilter); return Enumerable.Empty(); } } public async Task GetByIdAsync(int id) { const string sql = "SELECT id AS Id, modulo, descPermiso, codAcc FROM dbo.gral_Permisos WHERE id = @Id"; try { using var connection = _connectionFactory.CreateConnection(); return await connection.QuerySingleOrDefaultAsync(sql, new { Id = id }); } catch (Exception ex) { _logger.LogError(ex, "Error al obtener Permiso por ID: {IdPermiso}", id); return null; } } public async Task ExistsByCodAccAsync(string codAcc, int? excludeId = null) { var sqlBuilder = new StringBuilder("SELECT COUNT(1) FROM dbo.gral_Permisos WHERE codAcc = @CodAcc"); var parameters = new DynamicParameters(); parameters.Add("CodAcc", codAcc); if (excludeId.HasValue) { sqlBuilder.Append(" AND id != @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 ExistsByCodAccAsync para Permiso con codAcc: {CodAcc}", codAcc); return true; } } public async Task IsInUseAsync(int id) { const string sqlCheckPermisosPerfiles = "SELECT TOP 1 1 FROM dbo.gral_PermisosPerfiles WHERE idPermiso = @IdPermiso"; try { using var connection = _connectionFactory.CreateConnection(); var inUse = await connection.ExecuteScalarAsync(sqlCheckPermisosPerfiles, new { IdPermiso = id }); return inUse.HasValue && inUse.Value == 1; } catch (Exception ex) { _logger.LogError(ex, "Error en IsInUseAsync para Permiso ID: {IdPermiso}", id); return true; } } public async Task> GetPermisosByIdsAsync(IEnumerable ids) { if (ids == null || !ids.Any()) { return Enumerable.Empty(); } const string sql = "SELECT id AS Id, modulo, descPermiso, codAcc FROM dbo.gral_Permisos WHERE id IN @Ids;"; try { using var connection = _connectionFactory.CreateConnection(); return await connection.QueryAsync(sql, new { Ids = ids }); } catch (Exception ex) { _logger.LogError(ex, "Error al obtener permisos por IDs."); return Enumerable.Empty(); } } public async Task CreateAsync(Permiso nuevoPermiso, int idUsuario, IDbTransaction transaction) { const string sqlInsert = @" INSERT INTO dbo.gral_Permisos (modulo, descPermiso, codAcc) OUTPUT INSERTED.id AS Id, INSERTED.modulo, INSERTED.descPermiso, INSERTED.codAcc VALUES (@Modulo, @DescPermiso, @CodAcc);"; const string sqlInsertHistorico = @" INSERT INTO dbo.gral_Permisos_H (idPermiso, modulo, descPermiso, codAcc, Id_Usuario, FechaMod, TipoMod) VALUES (@IdPermisoHist, @ModuloHist, @DescPermisoHist, @CodAccHist, @IdUsuarioHist, @FechaModHist, @TipoModHist);"; var connection = transaction.Connection!; var insertedPermiso = await connection.QuerySingleAsync( sqlInsert, nuevoPermiso, transaction: transaction); if (insertedPermiso == null || insertedPermiso.Id <= 0) { throw new DataException("No se pudo obtener el ID del permiso insertado."); } await connection.ExecuteAsync(sqlInsertHistorico, new { IdPermisoHist = insertedPermiso.Id, ModuloHist = insertedPermiso.Modulo, DescPermisoHist = insertedPermiso.DescPermiso, CodAccHist = insertedPermiso.CodAcc, IdUsuarioHist = idUsuario, FechaModHist = DateTime.Now, TipoModHist = "Insertada" }, transaction: transaction); return insertedPermiso; } public async Task UpdateAsync(Permiso permisoAActualizar, int idUsuario, IDbTransaction transaction) { var connection = transaction.Connection!; var permisoActual = await connection.QuerySingleOrDefaultAsync( "SELECT id AS Id, modulo, descPermiso, codAcc FROM dbo.gral_Permisos WHERE id = @Id", new { Id = permisoAActualizar.Id }, transaction); if (permisoActual == null) { throw new KeyNotFoundException($"Permiso con ID {permisoAActualizar.Id} no encontrado para actualizar."); } const string sqlUpdate = @"UPDATE dbo.gral_Permisos SET modulo = @Modulo, descPermiso = @DescPermiso, codAcc = @CodAcc WHERE id = @Id;"; const string sqlInsertHistorico = @" INSERT INTO dbo.gral_Permisos_H (idPermiso, modulo, descPermiso, codAcc, Id_Usuario, FechaMod, TipoMod) VALUES (@IdPermisoHist, @ModuloHist, @DescPermisoHist, @CodAccHist, @IdUsuarioHist, @FechaModHist, @TipoModHist);"; await connection.ExecuteAsync(sqlInsertHistorico, new { IdPermisoHist = permisoActual.Id, ModuloHist = permisoActual.Modulo, DescPermisoHist = permisoActual.DescPermiso, CodAccHist = permisoActual.CodAcc, IdUsuarioHist = idUsuario, FechaModHist = DateTime.Now, TipoModHist = "Modificada" }, transaction: transaction); var rowsAffected = await connection.ExecuteAsync(sqlUpdate, permisoAActualizar, transaction: transaction); return rowsAffected == 1; } public async Task DeleteAsync(int id, int idUsuario, IDbTransaction transaction) { var connection = transaction.Connection!; var permisoActual = await connection.QuerySingleOrDefaultAsync( "SELECT id AS Id, modulo, descPermiso, codAcc FROM dbo.gral_Permisos WHERE id = @Id", new { Id = id }, transaction); if (permisoActual == null) { throw new KeyNotFoundException($"Permiso con ID {id} no encontrado para eliminar."); } const string sqlDelete = "DELETE FROM dbo.gral_Permisos WHERE id = @Id"; const string sqlInsertHistorico = @" INSERT INTO dbo.gral_Permisos_H (idPermiso, modulo, descPermiso, codAcc, Id_Usuario, FechaMod, TipoMod) VALUES (@IdPermisoHist, @ModuloHist, @DescPermisoHist, @CodAccHist, @IdUsuarioHist, @FechaModHist, @TipoModHist);"; await connection.ExecuteAsync(sqlInsertHistorico, new { IdPermisoHist = permisoActual.Id, ModuloHist = permisoActual.Modulo, DescPermisoHist = permisoActual.DescPermiso, CodAccHist = permisoActual.CodAcc, IdUsuarioHist = idUsuario, FechaModHist = DateTime.Now, TipoModHist = "Eliminada" }, transaction: transaction); var rowsAffected = await connection.ExecuteAsync(sqlDelete, new { Id = id }, transaction: transaction); return rowsAffected == 1; } public async Task> GetHistorialAsync( DateTime? fechaDesde, DateTime? fechaHasta, int? idUsuarioModifico, string? tipoModificacion, int? idPermisoOriginal) { using var connection = _connectionFactory.CreateConnection(); var sqlBuilder = new StringBuilder(@" SELECT h.IdHist, h.idPermiso, h.modulo, h.descPermiso, h.codAcc, h.Id_Usuario, h.FechaMod, h.TipoMod, u.Nombre + ' ' + u.Apellido AS NombreUsuarioModifico FROM dbo.gral_Permisos_H h JOIN dbo.gral_Usuarios u ON h.Id_Usuario = u.Id WHERE 1=1"); var parameters = new DynamicParameters(); if (fechaDesde.HasValue) { sqlBuilder.Append(" AND h.FechaMod >= @FechaDesdeParam"); parameters.Add("FechaDesdeParam", fechaDesde.Value.Date); } if (fechaHasta.HasValue) { sqlBuilder.Append(" AND h.FechaMod <= @FechaHastaParam"); parameters.Add("FechaHastaParam", fechaHasta.Value.Date.AddDays(1).AddTicks(-1)); } if (idUsuarioModifico.HasValue) { sqlBuilder.Append(" AND h.Id_Usuario = @IdUsuarioModificoParam"); parameters.Add("IdUsuarioModificoParam", idUsuarioModifico.Value); } if (!string.IsNullOrWhiteSpace(tipoModificacion)) { sqlBuilder.Append(" AND h.TipoMod = @TipoModParam"); parameters.Add("TipoModParam", tipoModificacion); } if (idPermisoOriginal.HasValue) { sqlBuilder.Append(" AND h.idPermiso = @IdPermisoOriginalParam"); parameters.Add("IdPermisoOriginalParam", idPermisoOriginal.Value); } sqlBuilder.Append(" ORDER BY h.FechaMod DESC;"); try { var result = await connection.QueryAsync( sqlBuilder.ToString(), (hist, userName) => (hist, userName), parameters, splitOn: "NombreUsuarioModifico" ); return result; } catch (Exception ex) { _logger.LogError(ex, "Error al obtener historial de Permisos (Maestro)."); return Enumerable.Empty<(PermisoHistorico, string)>(); } } } }