using Microsoft.EntityFrameworkCore; using Rs_system.Data; using Rs_system.Models; using Rs_system.Models.ViewModels; using BC = BCrypt.Net.BCrypt; namespace Rs_system.Services; public class AuthService : IAuthService { private readonly ApplicationDbContext _context; private readonly ILogger _logger; public AuthService(ApplicationDbContext context, ILogger logger) { _context = context; _logger = logger; } public async Task ValidateUserAsync(string username, string password) { var usuario = await _context.Usuarios .AsNoTracking() .Include(u => u.Persona) .Include(u => u.RolesUsuario) .ThenInclude(ru => ru.Rol) .FirstOrDefaultAsync(u => u.NombreUsuario == username && u.Activo); if (usuario == null) { _logger.LogWarning("Login attempt for non-existent user: {Username}", username); return null; } // Verify password using BCrypt try { if (!BC.Verify(password, usuario.HashContrasena)) { _logger.LogWarning("Invalid password for user: {Username}", username); return null; } } catch (Exception ex) { _logger.LogError(ex, "Error verifying password for user: {Username}", username); return null; } _logger.LogInformation("User {Username} logged in successfully", username); return usuario; } public async Task<(bool Success, string Message, Usuario? User)> RegisterUserAsync(RegisterViewModel model) { // Check if username already exists if (await _context.Usuarios.AnyAsync(u => u.NombreUsuario == model.NombreUsuario)) { return (false, "El nombre de usuario ya existe", null); } // Check if email already exists if (await _context.Usuarios.AnyAsync(u => u.Email == model.Email)) { return (false, "El correo electrónico ya está registrado", null); } using var transaction = await _context.Database.BeginTransactionAsync(); try { // Create persona first var persona = new Persona { Nombres = model.Nombres, Apellidos = model.Apellidos, Email = model.Email, Activo = true, CreadoEn = DateTime.UtcNow, ActualizadoEn = DateTime.UtcNow }; _context.Personas.Add(persona); await _context.SaveChangesAsync(); // Create user with hashed password var usuario = new Usuario { PersonaId = persona.Id, NombreUsuario = model.NombreUsuario, Email = model.Email, HashContrasena = BC.HashPassword(model.Contrasena), Activo = true, CreadoEn = DateTime.UtcNow, ActualizadoEn = DateTime.UtcNow }; _context.Usuarios.Add(usuario); await _context.SaveChangesAsync(); // Assign default role (LECTOR - reader) var defaultRole = await _context.RolesSistema .FirstOrDefaultAsync(r => r.Codigo == "LECTOR"); if (defaultRole != null) { var rolUsuario = new RolUsuario { UsuarioId = usuario.Id, RolId = defaultRole.Id, AsignadoEn = DateTime.UtcNow }; _context.RolesUsuario.Add(rolUsuario); await _context.SaveChangesAsync(); } await transaction.CommitAsync(); _logger.LogInformation("New user registered: {Username}", model.NombreUsuario); return (true, "Usuario registrado exitosamente", usuario); } catch (Exception ex) { await transaction.RollbackAsync(); _logger.LogError(ex, "Error registering user: {Username}", model.NombreUsuario); return (false, "Error al registrar el usuario", null); } } public async Task> GetUserRolesAsync(long userId) { return await _context.RolesUsuario .AsNoTracking() .Where(ru => ru.UsuarioId == userId) .Select(ru => ru.Rol.Codigo) .ToListAsync(); } public async Task UpdateLastLoginAsync(long userId) { var usuario = await _context.Usuarios.FindAsync(userId); if (usuario != null) { usuario.UltimoLogin = DateTime.UtcNow; await _context.SaveChangesAsync(); } } public async Task HasPermissionAsync(long userId, string permissionCode) { // ROOT has all permissions var roles = await GetUserRolesAsync(userId); if (roles.Contains("ROOT")) return true; return await _context.RolesUsuario .AsNoTracking() .Where(ru => ru.UsuarioId == userId) .Join(_context.RolesPermisos.AsNoTracking(), ru => ru.RolId, rp => rp.RolId, (ru, rp) => rp.PermisoId) .Join(_context.Permisos.AsNoTracking(), permisoId => permisoId, p => p.Id, (permisoId, p) => p.Codigo) .AnyAsync(codigo => codigo == permissionCode); } }