// EN: Custom Resource Owner Password Validator for Duende IdentityServer.
// VI: Custom Resource Owner Password Validator cho Duende IdentityServer.

using Duende.IdentityServer.Models;
using Duende.IdentityServer.Validation;
using Microsoft.AspNetCore.Identity;
using Microsoft.Extensions.Logging;
using IamService.Domain.AggregatesModel.UserAggregate;

namespace IamService.Infrastructure.IdentityServer;

/// <summary>
/// EN: Custom Resource Owner Password Validator using ASP.NET Identity UserManager.
/// EN: Avoids SignInManager cookie-based validation that can deadlock in token endpoint.
/// VI: Custom Resource Owner Password Validator sử dụng ASP.NET Identity UserManager.
/// VI: Tránh SignInManager dựa trên cookie có thể gây deadlock trong token endpoint.
/// </summary>
public class ResourceOwnerPasswordValidator : IResourceOwnerPasswordValidator
{
    private readonly UserManager<ApplicationUser> _userManager;
    private readonly ILogger<ResourceOwnerPasswordValidator> _logger;

    public ResourceOwnerPasswordValidator(
        UserManager<ApplicationUser> userManager,
        ILogger<ResourceOwnerPasswordValidator> logger)
    {
        _userManager = userManager;
        _logger = logger;
    }

    public async Task ValidateAsync(ResourceOwnerPasswordValidationContext context)
    {
        try
        {
            // EN: Find user by username (which is email)
            // VI: Tìm user bằng username (tức là email)
            var user = await _userManager.FindByNameAsync(context.UserName);
            
            if (user == null)
            {
                _logger.LogWarning("User not found: {Username}", context.UserName);
                context.Result = new GrantValidationResult(
                    TokenRequestErrors.InvalidGrant,
                    "Invalid username or password");
                return;
            }

            // EN: Check if account is locked out
            // VI: Kiểm tra tài khoản có bị khóa không
            if (await _userManager.IsLockedOutAsync(user))
            {
                _logger.LogWarning("User account is locked: {Username}", context.UserName);
                context.Result = new GrantValidationResult(
                    TokenRequestErrors.InvalidGrant,
                    "Account is locked. Please try again later.");
                return;
            }

            // EN: Validate password directly via UserManager (avoids cookie-based SignInManager)
            // VI: Xác thực password trực tiếp qua UserManager (tránh SignInManager dựa trên cookie)
            var passwordValid = await _userManager.CheckPasswordAsync(user, context.Password);
            
            if (!passwordValid)
            {
                _logger.LogWarning("Invalid password for user: {Username}", context.UserName);
                await _userManager.AccessFailedAsync(user);
                context.Result = new GrantValidationResult(
                    TokenRequestErrors.InvalidGrant,
                    "Invalid username or password");
                return;
            }

            // EN: Reset failed access count on successful login
            // VI: Reset số lần truy cập thất bại khi đăng nhập thành công
            await _userManager.ResetAccessFailedCountAsync(user);
            
            // EN: Record login
            // VI: Ghi nhận đăng nhập
            user.RecordLogin();

            _logger.LogInformation("User {Username} authenticated successfully via password grant", context.UserName);
            
            // EN: Return successful result with subject claim
            // VI: Trả về kết quả thành công với subject claim
            context.Result = new GrantValidationResult(
                subject: user.Id.ToString(),
                authenticationMethod: "password",
                claims: null);
        }
        catch (Exception ex)
        {
            _logger.LogError(ex, "Error validating resource owner password for {Username}", context.UserName);
            context.Result = new GrantValidationResult(
                TokenRequestErrors.InvalidGrant,
                "An error occurred during authentication");
        }
    }
}
