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

namespace IamService.API.Application.Commands.Roles;

/// <summary>
/// EN: Command to update permissions for a role (stored in role_claims table).
/// VI: Command để cập nhật permissions cho một role (lưu trong bảng role_claims).
/// </summary>
public record UpdateRolePermissionsCommand(
    Guid RoleId,
    List<string> Permissions) : IRequest<bool>;

/// <summary>
/// EN: Valid permission names matching MerchantService StaffPermissions enum.
/// VI: Tên permission hợp lệ khớp với StaffPermissions enum của MerchantService.
/// </summary>
public static class ValidPermissions
{
    public static readonly HashSet<string> Names = new(StringComparer.OrdinalIgnoreCase)
    {
        "ViewSales", "ProcessPayment", "RefundOrder",
        "ManageInventory", "ViewReports", "ManageStaff", "ManageSettings", "All"
    };
}

/// <summary>
/// EN: Handler for UpdateRolePermissionsCommand.
/// VI: Handler cho UpdateRolePermissionsCommand.
/// </summary>
public class UpdateRolePermissionsCommandHandler : IRequestHandler<UpdateRolePermissionsCommand, bool>
{
    private readonly RoleManager<ApplicationRole> _roleManager;
    private readonly IamServiceContext _dbContext;
    private readonly ILogger<UpdateRolePermissionsCommandHandler> _logger;

    public UpdateRolePermissionsCommandHandler(
        RoleManager<ApplicationRole> roleManager,
        IamServiceContext dbContext,
        ILogger<UpdateRolePermissionsCommandHandler> logger)
    {
        _roleManager = roleManager;
        _dbContext = dbContext;
        _logger = logger;
    }

    public async Task<bool> Handle(UpdateRolePermissionsCommand request, CancellationToken cancellationToken)
    {
        var role = await _roleManager.FindByIdAsync(request.RoleId.ToString())
            ?? throw new DomainException($"Role with ID {request.RoleId} not found");

        if (role.IsSystemRole)
            throw new DomainException("Cannot modify permissions of system roles");

        // EN: Validate all permission names
        // VI: Kiểm tra tất cả tên permission
        var invalid = request.Permissions.Where(p => !ValidPermissions.Names.Contains(p)).ToList();
        if (invalid.Any())
            throw new DomainException($"Invalid permissions: {string.Join(", ", invalid)}");

        // EN: Remove existing permission claims
        // VI: Xóa permission claims hiện tại
        var existing = await _dbContext.RoleClaims
            .Where(rc => rc.RoleId == request.RoleId && rc.ClaimType == "permission")
            .ToListAsync(cancellationToken);
        _dbContext.RoleClaims.RemoveRange(existing);

        // EN: Add new permission claims
        // VI: Thêm permission claims mới
        foreach (var perm in request.Permissions.Distinct())
        {
            _dbContext.RoleClaims.Add(new IdentityRoleClaim<Guid>
            {
                RoleId = request.RoleId,
                ClaimType = "permission",
                ClaimValue = perm
            });
        }

        await _dbContext.SaveChangesAsync(cancellationToken);
        _logger.LogInformation("Updated permissions for role {RoleName}: [{Permissions}]",
            role.Name, string.Join(", ", request.Permissions));

        return true;
    }
}
