using FluentValidation;
using MediatR;
using Microsoft.AspNetCore.Identity;
using SolutionErp.Application.Auth.Dtos;
using SolutionErp.Application.Common.Exceptions;
using SolutionErp.Application.Common.Interfaces;
using SolutionErp.Domain.Identity;

namespace SolutionErp.Application.Auth.Commands.Login;

public record LoginCommand(string Email, string Password) : IRequest<AuthResponseDto>;

public class LoginCommandValidator : AbstractValidator<LoginCommand>
{
    public LoginCommandValidator()
    {
        RuleFor(x => x.Email).NotEmpty().EmailAddress();
        RuleFor(x => x.Password).NotEmpty().MinimumLength(6);
    }
}

public class LoginCommandHandler(
    UserManager<User> userManager,
    IJwtTokenService jwtTokenService) : IRequestHandler<LoginCommand, AuthResponseDto>
{
    public async Task<AuthResponseDto> Handle(LoginCommand request, CancellationToken cancellationToken)
    {
        var user = await userManager.FindByEmailAsync(request.Email);
        if (user is null || !user.IsActive)
            throw new UnauthorizedException("Email hoặc mật khẩu không đúng.");

        // Check lockout trước
        if (await userManager.IsLockedOutAsync(user))
        {
            var until = user.LockoutEnd;
            throw new UnauthorizedException($"Tài khoản bị khóa do nhập sai nhiều lần. Thử lại sau {until:HH:mm}.");
        }

        if (!await userManager.CheckPasswordAsync(user, request.Password))
        {
            // Tăng AccessFailedCount + auto lock khi đủ ngưỡng
            await userManager.AccessFailedAsync(user);
            throw new UnauthorizedException("Email hoặc mật khẩu không đúng.");
        }

        // Success → reset failed count
        await userManager.ResetAccessFailedCountAsync(user);

        var roles = await userManager.GetRolesAsync(user);
        var tokens = await jwtTokenService.GenerateTokensAsync(user, roles);

        user.RefreshToken = tokens.RefreshToken;
        user.RefreshTokenExpiresAt = tokens.RefreshTokenExpiresAt;
        await userManager.UpdateAsync(user);

        return new AuthResponseDto(
            tokens.AccessToken,
            tokens.RefreshToken,
            tokens.RefreshTokenExpiresAt,
            new UserInfoDto(user.Id, user.Email!, user.FullName, roles.ToList()));
    }
}
