using MediatR;
using Microsoft.AspNetCore.Identity;
using IamService.Domain.AggregatesModel.UserAggregate;
using IamService.Domain.AggregatesModel.RoleAggregate;
using IamService.Domain.Exceptions;

namespace IamService.API.Application.Commands.Roles;

/// <summary>
/// EN: Handler for AssignRoleToUserCommand.
/// VI: Handler cho AssignRoleToUserCommand.
/// </summary>
public class AssignRoleToUserCommandHandler : IRequestHandler<AssignRoleToUserCommand, bool>
{
    private readonly UserManager<ApplicationUser> _userManager;
    private readonly RoleManager<ApplicationRole> _roleManager;
    private readonly ILogger<AssignRoleToUserCommandHandler> _logger;

    public AssignRoleToUserCommandHandler(
        UserManager<ApplicationUser> userManager,
        RoleManager<ApplicationRole> roleManager,
        ILogger<AssignRoleToUserCommandHandler> logger)
    {
        _userManager = userManager;
        _roleManager = roleManager;
        _logger = logger;
    }

    public async Task<bool> Handle(AssignRoleToUserCommand request, CancellationToken cancellationToken)
    {
        _logger.LogInformation("Assigning role {RoleName} to user {UserId}", request.RoleName, request.UserId);

        // EN: Find user
        // VI: Tìm user
        var user = await _userManager.FindByIdAsync(request.UserId.ToString());
        if (user == null)
        {
            _logger.LogWarning("User not found: {UserId}", request.UserId);
            throw new DomainException($"User with ID {request.UserId} not found.");
        }

        // EN: Check if role exists
        // VI: Kiểm tra role có tồn tại không
        var roleExists = await _roleManager.RoleExistsAsync(request.RoleName);
        if (!roleExists)
        {
            _logger.LogWarning("Role not found: {RoleName}", request.RoleName);
            throw new DomainException($"Role '{request.RoleName}' not found.");
        }

        // EN: Check if user already has this role
        // VI: Kiểm tra user đã có role này chưa
        var isInRole = await _userManager.IsInRoleAsync(user, request.RoleName);
        if (isInRole)
        {
            _logger.LogWarning("User {UserId} already has role {RoleName}", request.UserId, request.RoleName);
            throw new DomainException($"User already has role '{request.RoleName}'.");
        }

        // EN: Add role to user
        // VI: Thêm role cho user
        var result = await _userManager.AddToRoleAsync(user, request.RoleName);

        if (!result.Succeeded)
        {
            var errors = string.Join(", ", result.Errors.Select(e => e.Description));
            _logger.LogError("Failed to assign role {RoleName} to user {UserId}: {Errors}", 
                request.RoleName, request.UserId, errors);
            throw new DomainException($"Failed to assign role: {errors}");
        }

        _logger.LogInformation("Role {RoleName} assigned to user {UserId} successfully", 
            request.RoleName, request.UserId);

        return true;
    }
}
