using MediatR;
using MerchantService.Domain.AggregatesModel.MerchantStaffAggregate;

namespace MerchantService.API.Application.Behaviors;

/// <summary>
/// EN: MediatR pipeline behavior that checks permission claims from JWT token.
///     Only applies to commands implementing IRequirePermission.
///     Reads "permission" claims from HttpContext.User and converts to StaffPermissions bitmask.
/// VI: MediatR pipeline behavior kiểm tra permission claims từ JWT token.
///     Chỉ áp dụng cho commands implement IRequirePermission.
///     Đọc "permission" claims từ HttpContext.User và chuyển sang StaffPermissions bitmask.
/// </summary>
public class PermissionAuthorizationBehavior<TRequest, TResponse> : IPipelineBehavior<TRequest, TResponse>
    where TRequest : IRequest<TResponse>
{
    private readonly IHttpContextAccessor _httpContextAccessor;
    private readonly ILogger<PermissionAuthorizationBehavior<TRequest, TResponse>> _logger;

    public PermissionAuthorizationBehavior(
        IHttpContextAccessor httpContextAccessor,
        ILogger<PermissionAuthorizationBehavior<TRequest, TResponse>> logger)
    {
        _httpContextAccessor = httpContextAccessor;
        _logger = logger;
    }

    public async Task<TResponse> Handle(
        TRequest request,
        RequestHandlerDelegate<TResponse> next,
        CancellationToken cancellationToken)
    {
        // EN: Skip if command doesn't require permission check
        // VI: Bỏ qua nếu command không yêu cầu kiểm tra permission
        if (request is not IRequirePermission permissionRequest)
            return await next();

        var required = permissionRequest.RequiredPermission;
        if (required == StaffPermissions.None)
            return await next();

        var user = _httpContextAccessor.HttpContext?.User;
        if (user?.Identity?.IsAuthenticated != true)
        {
            _logger.LogWarning("EN: Permission check failed — user not authenticated for {Command}",
                typeof(TRequest).Name);
            throw new UnauthorizedAccessException("User not authenticated / Người dùng chưa xác thực");
        }

        // EN: Extract permission claims from JWT and convert to bitmask
        // VI: Trích xuất permission claims từ JWT và chuyển sang bitmask
        var permClaims = user.Claims
            .Where(c => c.Type == PermissionConstants.ClaimType)
            .Select(c => c.Value)
            .ToList();

        var granted = PermissionConstants.FromClaims(permClaims);

        // EN: Check if user has "All" permission or the specific required permission
        // VI: Kiểm tra user có "All" permission hoặc permission cụ thể cần thiết
        if (granted == StaffPermissions.All || (granted & required) == required)
            return await next();

        _logger.LogWarning(
            "EN: Permission denied — {Command} requires {Required}, user has {Granted}. " +
            "VI: Từ chối quyền — {Command} yêu cầu {Required}, user có {Granted}.",
            typeof(TRequest).Name, required, granted);

        throw new UnauthorizedAccessException(
            $"Permission denied: requires {required} / Từ chối quyền: yêu cầu {required}");
    }
}
