using GermanApp.Application.DTOs.Auth; using GermanApp.Application.Interfaces; using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Mvc; using System.IdentityModel.Tokens.Jwt; using System.Net; using System.Security.Claims; namespace GermanApp.Presentation.Controllers; /// /// Controller for authentication endpoints. /// Part of the Presentation layer. /// [ApiController] [Route("api/[controller]")] public class AuthController : ControllerBase { private readonly IAuthService _authService; public AuthController(IAuthService authService) { _authService = authService; } /// /// Register a new user. /// /// Registration data /// Authentication response with JWT token [HttpPost("register")] [AllowAnonymous] [ProducesResponseType(typeof(AuthResponse), (int)HttpStatusCode.OK)] [ProducesResponseType(typeof(string), (int)HttpStatusCode.BadRequest)] public async Task Register([FromBody] RegisterDto registerDto) { try { var result = await _authService.RegisterAsync(registerDto); return Ok(result); } catch (InvalidOperationException ex) { return BadRequest(ex.Message); } catch (Exception ex) { return StatusCode((int)HttpStatusCode.InternalServerError, ex.Message); } } /// /// Login an existing user. /// /// Login data /// Authentication response with JWT token [HttpPost("login")] [AllowAnonymous] [ProducesResponseType(typeof(AuthResponse), (int)HttpStatusCode.OK)] [ProducesResponseType(typeof(string), (int)HttpStatusCode.Unauthorized)] public async Task Login([FromBody] LoginDto loginDto) { try { var result = await _authService.LoginAsync(loginDto); return Ok(result); } catch (UnauthorizedAccessException ex) { return Unauthorized(ex.Message); } catch (Exception ex) { return StatusCode((int)HttpStatusCode.InternalServerError, ex.Message); } } /// /// Get current authenticated user information. /// /// Current user information [HttpGet("me")] [Authorize] [ProducesResponseType((int)HttpStatusCode.OK)] [ProducesResponseType((int)HttpStatusCode.Unauthorized)] public async Task GetCurrentUser() { try { // Get user ID from JWT claim // Note: JWT "sub" claim is mapped by ASP.NET Core JWT middleware to ClaimTypes.NameIdentifier // (http://schemas.xmlsoap.org/ws/2005/05/identity/claims/nameidentifier) var userIdClaim = User.FindFirst(ClaimTypes.NameIdentifier) ?? User.FindFirst("sub"); if (userIdClaim == null || !int.TryParse(userIdClaim.Value, out var userId) || userId == 0) return Unauthorized(); var user = await _authService.GetCurrentUserAsync(userId); if (user == null) return Unauthorized(); // Return full user profile including role, level, streak, and points return Ok(new { userId = user.Id, username = user.Username, email = user.Email, role = user.Role, currentLevel = user.CurrentLevel, streak = user.Streak, totalPoints = user.TotalPoints }); } catch (Exception ex) { return StatusCode((int)HttpStatusCode.InternalServerError, ex.Message); } } /// /// Refresh the access token using a refresh token. /// /// The refresh token /// New access token and refresh token [HttpPost("refresh")] [ProducesResponseType(typeof(RefreshTokenResponse), (int)HttpStatusCode.OK)] [ProducesResponseType(typeof(string), (int)HttpStatusCode.Unauthorized)] [ProducesResponseType(typeof(string), (int)HttpStatusCode.BadRequest)] public async Task Refresh([FromBody] string refreshToken) { try { var result = await _authService.RefreshTokenAsync(refreshToken); return Ok(result); } catch (UnauthorizedAccessException ex) { return Unauthorized(ex.Message); } catch (Exception ex) { return StatusCode((int)HttpStatusCode.InternalServerError, ex.Message); } } /// /// Revoke a refresh token. /// /// The refresh token to revoke /// Success or error response [HttpPost("revoke-refresh")] [Authorize] [ProducesResponseType((int)HttpStatusCode.OK)] [ProducesResponseType(typeof(string), (int)HttpStatusCode.Unauthorized)] [ProducesResponseType(typeof(string), (int)HttpStatusCode.BadRequest)] public async Task RevokeRefreshToken([FromBody] string refreshToken) { try { await _authService.RevokeRefreshTokenAsync(refreshToken); return Ok(new { message = "Refresh token revoked successfully" }); } catch (UnauthorizedAccessException ex) { return Unauthorized(ex.Message); } catch (Exception ex) { return StatusCode((int)HttpStatusCode.InternalServerError, ex.Message); } } }