using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Routing;

namespace IamService.Infrastructure.Authorization;

/// <summary>
/// EN: Authorization requirement for OwnerOrAdmin policy.
/// VI: Yêu cầu authorization cho policy OwnerOrAdmin.
/// </summary>
/// <remarks>
/// EN: This requirement allows access if:
///     - User has Admin or SuperAdmin role, OR
///     - User is accessing their own resource (userId in route matches current user)
/// VI: Yêu cầu này cho phép truy cập nếu:
///     - User có role Admin hoặc SuperAdmin, HOẶC
///     - User đang truy cập resource của chính mình (userId trong route khớp với user hiện tại)
/// </remarks>
public class OwnerOrAdminRequirement : IAuthorizationRequirement
{
}

/// <summary>
/// EN: Authorization handler for OwnerOrAdmin requirement.
/// VI: Authorization handler cho yêu cầu OwnerOrAdmin.
/// </summary>
public class OwnerOrAdminHandler : AuthorizationHandler<OwnerOrAdminRequirement>
{
    private readonly IHttpContextAccessor _httpContextAccessor;

    /// <summary>
    /// EN: Initializes a new instance of OwnerOrAdminHandler.
    /// VI: Khởi tạo instance mới của OwnerOrAdminHandler.
    /// </summary>
    /// <param name="httpContextAccessor">HTTP context accessor / HTTP context accessor</param>
    public OwnerOrAdminHandler(IHttpContextAccessor httpContextAccessor)
    {
        _httpContextAccessor = httpContextAccessor;
    }

    /// <summary>
    /// EN: Handle the authorization requirement.
    /// VI: Xử lý yêu cầu authorization.
    /// </summary>
    protected override Task HandleRequirementAsync(
        AuthorizationHandlerContext context,
        OwnerOrAdminRequirement requirement)
    {
        // EN: Admin or SuperAdmin always allowed
        // VI: Admin hoặc SuperAdmin luôn được phép
        if (context.User.IsInRole("Admin") || context.User.IsInRole("SuperAdmin"))
        {
            context.Succeed(requirement);
            return Task.CompletedTask;
        }

        // EN: Get current user ID from claims
        // VI: Lấy user ID hiện tại từ claims
        var currentUserId = context.User.FindFirst("sub")?.Value;
        if (string.IsNullOrEmpty(currentUserId))
        {
            return Task.CompletedTask;
        }

        // EN: Get the resource user ID from route
        // VI: Lấy resource user ID từ route
        var httpContext = _httpContextAccessor.HttpContext;
        if (httpContext == null)
        {
            return Task.CompletedTask;
        }

        // EN: Check if route has 'id' parameter
        // VI: Kiểm tra route có parameter 'id' không
        var routeUserId = httpContext.GetRouteValue("id")?.ToString();
        if (string.IsNullOrEmpty(routeUserId))
        {
            return Task.CompletedTask;
        }

        // EN: User accessing their own resource
        // VI: User đang truy cập resource của chính mình
        if (currentUserId.Equals(routeUserId, StringComparison.OrdinalIgnoreCase))
        {
            context.Succeed(requirement);
        }

        return Task.CompletedTask;
    }
}
