<?php

use Illuminate\Auth\Access\AuthorizationException;
use Illuminate\Auth\AuthenticationException;
use Illuminate\Database\Eloquent\ModelNotFoundException;
use Illuminate\Foundation\Application;
use Illuminate\Foundation\Configuration\Exceptions;
use Illuminate\Foundation\Configuration\Middleware;
use Illuminate\Http\Exceptions\HttpResponseException;
use Illuminate\Http\Request;
use Illuminate\Validation\ValidationException;
use Modules\Identity\Http\Middleware\AuthenticateSanctumOrFastApiJwt;
use Modules\Identity\Http\Middleware\EnsureFastApiAgent;
use Symfony\Component\HttpFoundation\Request as SymfonyRequest;
use Symfony\Component\HttpKernel\Exception\HttpExceptionInterface;
use Symfony\Component\HttpKernel\Exception\MethodNotAllowedHttpException;
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
use Symfony\Component\HttpKernel\Exception\TooManyRequestsHttpException;

return Application::configure(basePath: dirname(__DIR__))
    ->withRouting(
        web: __DIR__.'/../routes/web.php',
        api: __DIR__.'/../routes/api.php',
        commands: __DIR__.'/../routes/console.php',
        health: '/up',
    )
    ->withMiddleware(function (Middleware $middleware): void {
        // Staging/production sit behind a reverse proxy/load balancer that
        // terminates SSL — without this, Laravel never sees the original
        // request as HTTPS, so it generates http:// asset URLs, which
        // browsers then block as mixed content on the https:// page (e.g.
        // Filament's file-upload.js failing to load, breaking that field's
        // JS-enhanced dropzone). Trusting '*' is the standard Laravel
        // pattern when the proxy's IP isn't fixed/known in advance.
        $middleware->trustProxies(
            at: '*',
            headers: SymfonyRequest::HEADER_X_FORWARDED_FOR
                | SymfonyRequest::HEADER_X_FORWARDED_HOST
                | SymfonyRequest::HEADER_X_FORWARDED_PORT
                | SymfonyRequest::HEADER_X_FORWARDED_PROTO
                | SymfonyRequest::HEADER_X_FORWARDED_AWS_ELB,
        );

        $middleware->alias([
            'fastapi.agent' => EnsureFastApiAgent::class,
            'api.auth' => AuthenticateSanctumOrFastApiJwt::class,
        ]);
    })
    ->withExceptions(function (Exceptions $exceptions): void {
        // api/* always gets a JSON error envelope regardless of the
        // client's Accept header (T6.3) — module exceptions that define
        // their own render() (app-modules/*/src/Exceptions) still win,
        // since Laravel checks those before these fallback callbacks.
        $exceptions->shouldRenderJsonWhen(fn (Request $request, Throwable $e) => $request->is('api/*') || $request->expectsJson());

        $exceptions->render(function (AuthenticationException $e, Request $request) {
            if ($request->is('api/*')) {
                return response()->json(['message' => 'Unauthenticated.'], 401);
            }
        });

        $exceptions->render(function (AuthorizationException $e, Request $request) {
            if ($request->is('api/*')) {
                return response()->json(['message' => $e->getMessage() ?: 'This action is unauthorized.'], 403);
            }
        });

        $exceptions->render(function (ModelNotFoundException $e, Request $request) {
            if ($request->is('api/*')) {
                return response()->json(['message' => 'The requested resource was not found.'], 404);
            }
        });

        $exceptions->render(function (NotFoundHttpException $e, Request $request) {
            if ($request->is('api/*')) {
                return response()->json(['message' => 'The requested resource was not found.'], 404);
            }
        });

        $exceptions->render(function (MethodNotAllowedHttpException $e, Request $request) {
            if ($request->is('api/*')) {
                return response()->json(['message' => 'This method is not allowed for the requested route.'], 405);
            }
        });

        $exceptions->render(function (TooManyRequestsHttpException $e, Request $request) {
            if ($request->is('api/*')) {
                return response()->json(['message' => 'Too many requests.'], 429);
            }
        });

        // Last-resort fallback: anything reaching here on api/* is an
        // exception with no render() of its own and no more specific
        // handler above — never let it leak a raw trace or fall through to
        // a bare, unenveloped 500 (T6.3). ValidationException/
        // HttpResponseException are excluded — Laravel's default handling
        // of those (after renderable callbacks run) already produces the
        // right JSON envelope, this fallback would only get in the way.
        $exceptions->render(function (Throwable $e, Request $request) {
            if (! $request->is('api/*')
                || $e instanceof HttpExceptionInterface
                || $e instanceof ValidationException
                || $e instanceof HttpResponseException) {
                return null;
            }

            return response()->json([
                'message' => app()->hasDebugModeEnabled() ? $e->getMessage() : 'Server Error',
            ], 500);
        });
    })->create();
