using GestionIntegral.Api.Dtos;
using GestionIntegral.Api.Services.Usuarios;
using Microsoft.AspNetCore.Authorization; // Para [Authorize]
using Microsoft.AspNetCore.Mvc;
using System.Security.Claims; // Para leer claims del token

namespace GestionIntegral.Api.Controllers.Usuarios
{
    [Route("api/[controller]")] // Ruta base: /api/auth
    [ApiController]
    public class AuthController : ControllerBase
    {
        private readonly IAuthService _authService;
        private readonly ILogger<AuthController> _logger; // Para logging

        public AuthController(IAuthService authService, ILogger<AuthController> logger)
        {
            _authService = authService;
            _logger = logger;
        }

        [HttpPost("login")] // Ruta: POST /api/auth/login
        [ProducesResponseType(typeof(LoginResponseDto), StatusCodes.Status200OK)]
        [ProducesResponseType(StatusCodes.Status400BadRequest)]
        [ProducesResponseType(StatusCodes.Status401Unauthorized)]
        public async Task<IActionResult> Login([FromBody] LoginRequestDto loginRequest)
        {
            if (!ModelState.IsValid)
            {
                return BadRequest(ModelState);
            }

            try
            {
                var loginResponse = await _authService.LoginAsync(loginRequest);

                if (loginResponse == null)
                {
                    _logger.LogWarning("Login failed for user {Username}", loginRequest.Username);
                    // Devolver Unauthorized genérico para no dar pistas sobre si el usuario existe o no
                    return Unauthorized(new { message = "Usuario o contraseña inválidos." });
                }

                _logger.LogInformation("User {Username} logged in successfully.", loginRequest.Username);
                return Ok(loginResponse);
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, "Error during login for user {Username}", loginRequest.Username);
                // No exponer detalles del error al cliente
                return StatusCode(StatusCodes.Status500InternalServerError, new { message = "Ocurrió un error interno durante el inicio de sesión." });
            }
        }

        [HttpPost("change-password")]
        [Authorize] // <-- Solo usuarios autenticados pueden cambiar su clave
        [ProducesResponseType(StatusCodes.Status204NoContent)] // Éxito sin contenido
        [ProducesResponseType(StatusCodes.Status400BadRequest)]
        [ProducesResponseType(StatusCodes.Status401Unauthorized)] // Si el token es inválido
        [ProducesResponseType(StatusCodes.Status404NotFound)] // Si el usuario del token no existe
        public async Task<IActionResult> ChangePassword([FromBody] ChangePasswordRequestDto changePasswordRequest)
        {
            if (!ModelState.IsValid)
            {
                // El [ApiController] y el [FromBody] ya validan DTOs (Required, StringLength, Compare)
                // y devuelven 400 automáticamente si falla.
                return BadRequest(ModelState);
            }

            // Obtener el ID del usuario desde el token JWT
            var userIdString = User.FindFirstValue(ClaimTypes.NameIdentifier) ?? User.FindFirstValue("sub"); // "sub" es el claim estándar para ID
            if (!int.TryParse(userIdString, out int userId))
            {
                _logger.LogWarning("ChangePassword failed: Could not parse UserId from token.");
                // Esto no debería pasar si el token es válido y generado por nosotros
                return Unauthorized(new { message = "Token de usuario inválido." });
            }

            try
            {
                var success = await _authService.ChangePasswordAsync(userId, changePasswordRequest);

                if (!success)
                {
                    // AuthService ya loggeó la razón específica (usuario no encontrado, clave actual inválida, etc.)
                    // Devolvemos un BadRequest genérico para no dar pistas
                    return BadRequest(new { message = "No se pudo cambiar la contraseña. Verifique la contraseña actual." });
                }

                // Éxito
                return NoContent(); // Código 204: Éxito, sin contenido que devolver
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, "Error during password change for user ID {UserId}", userId);
                return StatusCode(StatusCodes.Status500InternalServerError, new { message = "Ocurrió un error interno al cambiar la contraseña." });
            }
        }
    }
}