using System.Text.Json;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Authorization.Policy;

namespace SIGCM2.Api.Authorization;

/// <summary>
/// Custom IAuthorizationMiddlewareResultHandler that emits a structured ProblemDetails
/// response for 403 Forbidden outcomes (authenticated user, missing permission).
///
/// For 401 Unauthorized and successful outcomes, delegates to the default handler
/// so the existing JWT Bearer challenge flow is unaffected (REQ-B-07).
///
/// Registered as singleton in Program.cs — depends only on framework services.
/// </summary>
public sealed class ForbiddenProblemDetailsHandler : IAuthorizationMiddlewareResultHandler
{
    private static readonly AuthorizationMiddlewareResultHandler DefaultHandler = new();

    private static readonly JsonSerializerOptions SerializerOptions = new()
    {
        PropertyNamingPolicy = JsonNamingPolicy.CamelCase,
    };

    public async Task HandleAsync(
        RequestDelegate next,
        HttpContext context,
        AuthorizationPolicy policy,
        PolicyAuthorizationResult authorizeResult)
    {
        // Only intercept 403s for authenticated users.
        // If the user is not authenticated, the 401 challenge is handled by JwtBearer (REQ-B-07).
        if (authorizeResult.Forbidden && context.User.Identity?.IsAuthenticated == true)
        {
            var requiredPermission = context.Items["RequiredPermission"] as string;

            context.Response.StatusCode = StatusCodes.Status403Forbidden;
            context.Response.ContentType = "application/problem+json; charset=utf-8";

            var problem = new
            {
                type = "https://sigcm2.local/errors/forbidden",
                title = "Acceso denegado",
                status = 403,
                detail = "No tenés el permiso requerido para ejecutar esta acción.",
                permisoRequerido = requiredPermission,
            };

            await context.Response.WriteAsync(
                JsonSerializer.Serialize(problem, SerializerOptions));

            return;
        }

        // Delegate 401 challenges and successful outcomes to the default handler
        await DefaultHandler.HandleAsync(next, context, policy, authorizeResult);
    }
}
