using System.IdentityModel.Tokens.Jwt; using System.Security.Claims; using System.Text; using BCrypt.Net; using iknow_api.Services; using iknow_api.Models; using iknow_api.DTOs; using iknow_api.Repositories; using Microsoft.IdentityModel.Tokens; using iknow_api.Data; using Microsoft.EntityFrameworkCore; namespace iknow_api.Services { public class AuthService : IAuthService { private readonly IUserRepository _userRepository; private readonly IRefreshTokenRepository _refreshTokenRepository; private readonly IRefreshTokenService _refreshTokenService; private readonly IConfiguration _configuration; private readonly AppDbContext _context; public AuthService(IUserRepository userRepository, IConfiguration configuration, IRefreshTokenService refreshTokenService, IRefreshTokenRepository refreshTokenRepository, AppDbContext context) { _userRepository = userRepository; _configuration = configuration; _refreshTokenService = refreshTokenService; _refreshTokenRepository = refreshTokenRepository; _context = context; } public async Task RegisterAsync(RegisterDto registerDto) { // Debug: Log all incoming DTO values Console.WriteLine("=== RegisterDto Debug Info ==="); Console.WriteLine($"Name: {registerDto.Name}"); Console.WriteLine($"Email: {registerDto.Email}"); Console.WriteLine($"majorType: {registerDto.majorType}"); Console.WriteLine($"enrollmentYear: {registerDto.enrollmentYear}"); Console.WriteLine($"quotaType: {registerDto.quotaType}"); Console.WriteLine($"Role: {registerDto.Role}"); Console.WriteLine($"tip: {registerDto.tip}"); Console.WriteLine("=============================="); // Check if user already exists if (await _userRepository.UserExistsAsync(registerDto.Email)) throw new InvalidOperationException("User with this email already exists"); // Use a transaction to ensure all entities are saved together using var transaction = await _context.Database.BeginTransactionAsync(); try { var user = new User { Name = registerDto.Name, MiddleName = registerDto.MiddleName, Surname = registerDto.Surname, Index = registerDto.Index, Email = registerDto.Email, PasswordHash = BCrypt.Net.BCrypt.HashPassword(registerDto.Password), Bday = DateTime.SpecifyKind(registerDto.Bday, DateTimeKind.Utc), CreatedAt = DateTime.UtcNow, Role = (Models.UserRole)registerDto.Role, EMBG = registerDto.EMBG, Nationality = registerDto.nationality, Citizenship = registerDto.citizenship, Gender = registerDto.gender }; _context.User.Add(user); await _context.SaveChangesAsync(); int userId = user.Id; var contactInfo = new ContactInfo { UserId = userId, City = registerDto.city, Address = registerDto.address, Municipality = registerDto.municipality, PhoneNumber = registerDto.phoneNumber, MicrosoftEmail = registerDto.microsoftEmail }; var enrollmentInfo = new EnrollmentInfo { UserId = userId, enrollmentYear = registerDto.enrollmentYear, quota = (Models.Quota)registerDto.quotaType, MajorId = registerDto.majorType, StudyStatus = registerDto.studyStatus, StudyType = registerDto.studyType }; var highSchool = new HighSchool { UserId = userId, GPA = registerDto.gpa, HighSchoolType = (Models.HighSchoolType)registerDto.tip }; _context.ContactInfo.Add(contactInfo); _context.EnrollmentInfo.Add(enrollmentInfo); _context.HighSchool.Add(highSchool); // Save all related entities in a single transaction await _context.SaveChangesAsync(); await transaction.CommitAsync(); return true; } catch { await transaction.RollbackAsync(); throw; } } public async Task LoginAsync(LoginDto loginDto) { var user = await _userRepository.GetUserByUsernameAsync(loginDto.Email); if (user == null || !BCrypt.Net.BCrypt.Verify(loginDto.Password, user.PasswordHash)) return null; var result = new AuthResultDto { AccessToken = CreateToken(user) }; if (loginDto.GenerateRefreshToken) { result.RefreshToken = await _refreshTokenService.GenerateRefreshToken(user.Id); } return result; } public async Task GetUsersCountAsync() { return await _userRepository.GetUsersCountAsync(); } public async Task GenerateNewJWT(VerifyRefreshTokenDto token) { int userid = await _refreshTokenRepository.GetUserId(token.token) ?? 0; User ?user = await _userRepository.GetOnlyUserByIdAsync(userid); var result = new AuthResultDto { AccessToken = CreateToken(user) }; return result; } private string CreateToken(User user) { var claims = new[] { new Claim("id", user.Id.ToString()), new Claim("email", user.Email ?? string.Empty), new Claim("role", user.Role.ToString()) }; var keyString = _configuration["Jwt:Key"]; if (string.IsNullOrEmpty(keyString)) throw new Exception("JWT Key is missing in configuration!"); var key = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(keyString)); var creds = new SigningCredentials(key, SecurityAlgorithms.HmacSha256); var token = new JwtSecurityToken( issuer: "iknow-api", audience: "iknow-api", claims: claims, expires: DateTime.UtcNow.AddHours(1), signingCredentials: creds ); return new JwtSecurityTokenHandler().WriteToken(token); } } }