<?php

namespace Modules\Identity\Http\Middleware;

use Closure;
use Firebase\JWT\JWT;
use Firebase\JWT\Key;
use Illuminate\Contracts\Auth\Middleware\AuthenticatesRequests;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\Log;
use Symfony\Component\HttpFoundation\Response;
use Throwable;

/**
 * Accepts either of two bearer schemes on the same routes:
 *
 * - A Sanctum personal access token, for real database users (mini app,
 *   mobile, web, admin) — resolved exactly as `auth:sanctum` would.
 * - A self-signed JWT minted by the FastAPI AI agent, carrying the real
 *   end-customer's identity in its `sub` claim. No Laravel `User` is
 *   created or attached for this path — the verified claim is stashed as
 *   the `fastapi_openid` request attribute for controllers to scope by
 *   (domain.md §8; the agent has no database identity of its own).
 *
 * Payment/refund routes deliberately keep plain `auth:sanctum` instead of
 * this middleware, so a JWT-authenticated request can never reach them.
 */
class AuthenticateSanctumOrFastApiJwt implements AuthenticatesRequests
{
    public function handle(Request $request, Closure $next): Response
    {
        if (Auth::guard('sanctum')->check()) {
            Auth::shouldUse('sanctum');

            return $next($request);
        }

        if ($token = $request->bearerToken()) {
            try {
                $payload = JWT::decode($token, new Key(
                    config('services.fastapi_agent.jwt_secret'),
                    config('services.fastapi_agent.jwt_algorithm'),
                ));

                $request->attributes->set('fastapi_openid', $payload->sub);

                return $next($request);
            } catch (Throwable $e) {
                // Expired/malformed/wrong-signature tokens are routine auth
                // failures, not application errors — log at debug level
                // only, never report() to the error tracker.
                Log::debug('FastAPI agent JWT rejected.', ['reason' => $e->getMessage()]);
            }
        }

        abort(401, 'Unauthenticated.');
    }
}
