using API.Contracts.Auth;
using API.Models;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Identity;
using Microsoft.AspNetCore.Mvc;

namespace API.Controllers.Auth
{
    [ApiController]
    [Route("auth")]
    public class AuthController(
        SignInManager<AppUser> signInManager,
        UserManager<AppUser> userManager)
        : ControllerBase
    {
        [HttpPost("login")]
        [AllowAnonymous]
        public async Task<IActionResult> Login([FromBody] LoginRequest request)
        {
            if (string.IsNullOrWhiteSpace(request.UserName) || string.IsNullOrWhiteSpace(request.Password))
                return BadRequest(new { message = "Benutzername und Passwort sind erforderlich." });

            var user = await userManager.FindByNameAsync(request.UserName);
            if (user is null)
                return Unauthorized(new { message = "Ungültige Anmeldedaten." });

            if (!user.IsActive)
                return Forbid();

            var result = await signInManager.PasswordSignInAsync(
                user,
                request.Password,
                isPersistent: true,
                lockoutOnFailure: false);

            if (!result.Succeeded)
                return Unauthorized(new { message = "Ungültige Anmeldedaten." });

            user.UpdatedAt = DateTimeOffset.UtcNow;
            await userManager.UpdateAsync(user);

            return Ok(new { message = "Login erfolgreich." });
        }

        [HttpPost("logout")]
        [Authorize]
        public async Task<IActionResult> Logout()
        {
            await signInManager.SignOutAsync();
            return Ok(new { message = "Logout erfolgreich." });
        }

        [HttpGet("me")]
        [Authorize]
        public async Task<ActionResult<CurrentUserResponse>> Me()
        {
            var user = await userManager.GetUserAsync(User);
            if (user is null)
                return Unauthorized();

            return Ok(await user.ToCurrentUserResponseAsync(userManager));
        }

        [HttpPost("password")]
        [Authorize]
        public async Task<IActionResult> ChangePassword([FromBody] ChangePasswordRequest pwChangeDto)
        {
            var user = await userManager.GetUserAsync(User);
            if (user is null)
                return Unauthorized();

            if (string.IsNullOrWhiteSpace(pwChangeDto.NewPassword) ||
                string.IsNullOrWhiteSpace(pwChangeDto.OldPassword) ||
                string.IsNullOrWhiteSpace(pwChangeDto.NewPasswordConfirm))
            {
                return BadRequest(new { message = "Alle Passwörter müssen einen Wert enthalten." });
            }

            if (pwChangeDto.NewPassword != pwChangeDto.NewPasswordConfirm)
            {
                return BadRequest(new { message = "Die neuen Passwörter stimmen nicht überein." });
            }

            var result = await userManager.ChangePasswordAsync(
                user,
                pwChangeDto.OldPassword,
                pwChangeDto.NewPassword
            );

            if (!result.Succeeded)
            {
                return BadRequest(new
                {
                    message = "Passwort konnte nicht geändert werden.",
                    errors = result.Errors.Select(e => e.Description)
                });
            }

            user.MustChangePassword = false;
            user.UpdatedAt = DateTimeOffset.UtcNow;
            var updateResult = await userManager.UpdateAsync(user);
            if (!updateResult.Succeeded)
            {
                return StatusCode(500, new
                {
                    message = "Passwort wurde geändert, Benutzerdaten konnten aber nicht final gespeichert werden.",
                    errors = updateResult.Errors.Select(e => e.Description)
                });
            }

            var stampResult = await userManager.UpdateSecurityStampAsync(user);
            if (!stampResult.Succeeded)
            {
                return StatusCode(500, new { message = "Passwort geändert, aber Sessions konnten nicht invalidiert werden." });
            }

            await signInManager.SignOutAsync();

            return Ok(new { message = "Passwort geändert. Du wurdest auf allen Geräten abgemeldet." });
        }
    }
}
