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

namespace IamService.API.Application.Commands.Roles;

/// <summary>
/// EN: Handler for UpdateRoleCommand.
/// VI: Handler cho UpdateRoleCommand.
/// </summary>
public class UpdateRoleCommandHandler : IRequestHandler<UpdateRoleCommand, UpdateRoleCommandResult>
{
    private readonly RoleManager<ApplicationRole> _roleManager;
    private readonly ILogger<UpdateRoleCommandHandler> _logger;

    public UpdateRoleCommandHandler(
        RoleManager<ApplicationRole> roleManager,
        ILogger<UpdateRoleCommandHandler> logger)
    {
        _roleManager = roleManager;
        _logger = logger;
    }

    public async Task<UpdateRoleCommandResult> Handle(UpdateRoleCommand request, CancellationToken cancellationToken)
    {
        _logger.LogInformation("Updating role: {RoleId}", request.RoleId);

        var role = await _roleManager.FindByIdAsync(request.RoleId.ToString());

        if (role == null)
        {
            _logger.LogWarning("Role not found: {RoleId}", request.RoleId);
            throw new DomainException($"Role with ID {request.RoleId} not found.");
        }

        // EN: Check if role is a system role
        // VI: Kiểm tra role có phải system role không
        if (role.IsSystemRole)
        {
            _logger.LogWarning("Cannot update system role: {RoleId}", request.RoleId);
            throw new DomainException("Cannot update system-defined roles.");
        }

        // EN: Check if new name conflicts with existing role
        // VI: Kiểm tra tên mới có trùng với role khác không
        if (!role.Name!.Equals(request.Name, StringComparison.OrdinalIgnoreCase))
        {
            var existingRole = await _roleManager.FindByNameAsync(request.Name);
            if (existingRole != null)
            {
                throw new DomainException($"Role with name '{request.Name}' already exists.");
            }
        }

        // EN: Update role
        // VI: Cập nhật role
        role.Update(request.Name, request.Description);

        var result = await _roleManager.UpdateAsync(role);

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

        _logger.LogInformation("Role {RoleId} updated successfully", request.RoleId);

        return new UpdateRoleCommandResult(
            role.Id,
            role.Name!,
            role.Description);
    }
}
