using Microsoft.AspNetCore.Mvc; using Microsoft.EntityFrameworkCore; using LingAdmin.API.Data; using LingAdmin.API.Models; using LingAdmin.API.DTOs; using LingAdmin.API.Services; using Dapr.Client; namespace LingAdmin.API.Controllers; [ApiController] [Route("api/[controller]")] public class AuthController : ControllerBase { private readonly AppDbContext _context; private readonly IPasswordHasher _passwordHasher; private readonly ITokenService _tokenService; private readonly DaprClient _daprClient; private readonly ILogger _logger; public AuthController( AppDbContext context, IPasswordHasher passwordHasher, ITokenService tokenService, DaprClient daprClient, ILogger logger) { _context = context; _passwordHasher = passwordHasher; _tokenService = tokenService; _daprClient = daprClient; _logger = logger; } [HttpPost("register")] public async Task>> Register(RegisterDto registerDto) { try { // Validate input if (string.IsNullOrWhiteSpace(registerDto.Email) || string.IsNullOrWhiteSpace(registerDto.Password)) { return BadRequest(ApiResponse.Error("Email and password are required", 400)); } // Check if user already exists if (await _context.Users.AnyAsync(u => u.Email == registerDto.Email)) { return BadRequest(ApiResponse.Error("User with this email already exists", 400)); } // Create new user var user = new User { Name = registerDto.Name, Email = registerDto.Email, Role = registerDto.Role, Status = "Active", PasswordHash = _passwordHasher.HashPassword(registerDto.Password), CreatedAt = DateTime.UtcNow }; _context.Users.Add(user); await _context.SaveChangesAsync(); // Publish user created event await _daprClient.PublishEventAsync("pubsub", "user-created", new { userId = user.Id, email = user.Email, name = user.Name, timestamp = DateTime.UtcNow }); _logger.LogInformation("User registered successfully: {Email}", user.Email); var userDto = MapToUserDto(user); return CreatedAtAction(nameof(GetProfile), new { id = user.Id }, ApiResponse.Success(userDto)); } catch (Exception ex) { _logger.LogError(ex, "Error during user registration"); return StatusCode(500, ApiResponse.Error("Internal server error", 500)); } } [HttpPost("login")] public async Task>> Login(LoginDto loginDto) { try { // Find user by email var user = await _context.Users.FirstOrDefaultAsync(u => u.Email == loginDto.Email); if (user == null) { return Unauthorized(ApiResponse.Error("Invalid email or password", 401)); } // Verify password if (!_passwordHasher.VerifyPassword(loginDto.Password, user.PasswordHash)) { return Unauthorized(ApiResponse.Error("Invalid email or password", 401)); } // Check if user is active if (user.Status != "Active") { return Unauthorized(ApiResponse.Error("User account is not active", 401)); } // Update last login time user.LastLoginAt = DateTime.UtcNow; await _context.SaveChangesAsync(); // Generate token var token = _tokenService.GenerateToken(user); // Publish login event await _daprClient.PublishEventAsync("pubsub", "user-login", new { userId = user.Id, email = user.Email, timestamp = DateTime.UtcNow }); _logger.LogInformation("User logged in successfully: {Email}", user.Email); var response = new LoginResponseDto { Token = token, User = MapToUserDto(user) }; return Ok(ApiResponse.Success(response)); } catch (Exception ex) { _logger.LogError(ex, "Error during user login"); return StatusCode(500, ApiResponse.Error("Internal server error", 500)); } } [HttpGet("profile/{id}")] public async Task>> GetProfile(int id) { try { var user = await _context.Users.FindAsync(id); if (user == null) { return NotFound(ApiResponse.Error("User not found", 404)); } return Ok(ApiResponse.Success(MapToUserDto(user))); } catch (Exception ex) { _logger.LogError(ex, "Error retrieving user profile"); return StatusCode(500, ApiResponse.Error("Internal server error", 500)); } } [HttpPost("change-password/{id}")] public async Task>> ChangePassword(int id, ChangePasswordDto changePasswordDto) { try { var user = await _context.Users.FindAsync(id); if (user == null) { return NotFound(ApiResponse.Error("User not found", 404)); } // Verify current password if (!_passwordHasher.VerifyPassword(changePasswordDto.CurrentPassword, user.PasswordHash)) { return BadRequest(ApiResponse.Error("Current password is incorrect", 400)); } // Update password user.PasswordHash = _passwordHasher.HashPassword(changePasswordDto.NewPassword); await _context.SaveChangesAsync(); // Publish password changed event await _daprClient.PublishEventAsync("pubsub", "user-password-changed", new { userId = user.Id, email = user.Email, timestamp = DateTime.UtcNow }); _logger.LogInformation("Password changed successfully for user: {Email}", user.Email); return Ok(ApiResponse.Success(new { message = "Password changed successfully" })); } catch (Exception ex) { _logger.LogError(ex, "Error changing password"); return StatusCode(500, ApiResponse.Error("Internal server error", 500)); } } private UserDto MapToUserDto(User user) { return new UserDto { Id = user.Id, Name = user.Name, Email = user.Email, Role = user.Role, Status = user.Status, CreatedAt = user.CreatedAt, LastLoginAt = user.LastLoginAt }; } }