<?php

use Illuminate\Foundation\Application;
use Illuminate\Foundation\Configuration\Exceptions;
use Illuminate\Foundation\Configuration\Middleware;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Log;
use Illuminate\Support\Str;
use Symfony\Component\HttpKernel\Exception\HttpExceptionInterface;

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 {
        $middleware->trustProxies(at: '*');
        $middleware->redirectGuestsTo('/login');
        $middleware->redirectUsersTo('/dashboard');
        // Order matters: SetCurrentAcademy binds `current_academy`, which
        // ResolveBranchContext needs to know which branches exist, and
        // RequireBranchSelection needs a resolved context to judge.
        $middleware->web(append: [
            \App\Http\Middleware\SetCurrentAcademy::class,
            \App\Http\Middleware\ResolveBranchContext::class,
            \App\Http\Middleware\RequireBranchSelection::class,
        ]);
        $middleware->api(append: [
            \App\Http\Middleware\SetCurrentAcademy::class,
            \App\Http\Middleware\ApiResponseHeaders::class,
        ]);
        $middleware->alias([
            'permission' => \App\Http\Middleware\CheckPermission::class,
            'super_admin' => \App\Http\Middleware\EnsureSuperAdmin::class,
            'branch' => \App\Http\Middleware\RequireBranchSelection::class,
        ]);
    })
    ->withExceptions(function (Exceptions $exceptions): void {
        $exceptions->shouldRenderJsonWhen(
            fn (Request $request) => $request->is('api/*') || $request->expectsJson(),
        );

        $exceptions->respond(function (\Symfony\Component\HttpFoundation\Response $response, \Throwable $e, Request $request) {
            $statusCode = $response->getStatusCode();

            if ($request->is('api/*') || $request->expectsJson()) {
                $errorId = Str::uuid()->toString();

                Log::error('[' . $errorId . '] API Error', [
                    'error_id' => $errorId,
                    'exception' => get_class($e),
                    'message' => $e->getMessage(),
                    'file' => $e->getFile(),
                    'line' => $e->getLine(),
                    'url' => $request->fullUrl(),
                    'method' => $request->method(),
                    'input' => $request->except(['password', 'password_confirmation', '_token']),
                    'user_id' => $request->user()?->id,
                ]);

                $code = $statusCode >= 400 ? $statusCode : 500;

                $body = [
                    'error' => true,
                    'error_id' => $errorId,
                    'message' => $code >= 500 && !config('app.debug')
                        ? 'حدث خطأ في النظام، يرجى المحاولة لاحقاً'
                        : $e->getMessage(),
                    'timestamp' => now()->toIso8601String(),
                ];

                if (config('app.debug')) {
                    $body['exception'] = get_class($e);
                    $body['file'] = $e->getFile();
                    $body['line'] = $e->getLine();
                    $body['trace'] = collect($e->getTrace())->take(20)->map(fn ($frame) => [
                        'file' => $frame['file'] ?? null,
                        'line' => $frame['line'] ?? null,
                        'function' => ($frame['class'] ?? '') . ($frame['type'] ?? '') . ($frame['function'] ?? ''),
                    ])->toArray();
                }

                return response()->json($body, $code);
            }

            if ($statusCode === 500 || (!$e instanceof HttpExceptionInterface && $statusCode >= 500)) {
                $errorId = Str::uuid()->toString();

                $queries = [];
                try {
                    $queryLog = DB::getQueryLog();
                    $queries = collect($queryLog)->takeRight(10)->map(fn ($q) => [
                        'query' => $q['query'] ?? '',
                        'time' => $q['time'] ?? null,
                    ])->toArray();
                } catch (\Throwable $ignored) {
                }

                $trace = collect($e->getTrace())->take(30)->map(fn ($frame) => [
                    'file' => $frame['file'] ?? '(internal)',
                    'line' => $frame['line'] ?? null,
                    'class' => $frame['class'] ?? '',
                    'type' => $frame['type'] ?? '',
                    'function' => $frame['function'] ?? '',
                ])->toArray();

                $inputData = '';
                try {
                    $filtered = $request->except(['password', 'password_confirmation', '_token']);
                    $inputData = !empty($filtered) ? json_encode($filtered, JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE) : '';
                } catch (\Throwable $ignored) {
                }

                $headers = '';
                try {
                    $headerBag = $request->headers->all();
                    unset($headerBag['cookie'], $headerBag['authorization']);
                    $headers = json_encode($headerBag, JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE);
                } catch (\Throwable $ignored) {
                }

                $sessionData = '';
                try {
                    if ($request->hasSession()) {
                        $sess = $request->session()->all();
                        unset($sess['_token'], $sess['_previous'], $sess['_flash']);
                        $sessionData = !empty($sess) ? json_encode($sess, JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE) : '';
                    }
                } catch (\Throwable $ignored) {
                }

                Log::error('[' . $errorId . '] Unhandled Exception', [
                    'error_id' => $errorId,
                    'exception' => get_class($e),
                    'message' => $e->getMessage(),
                    'file' => $e->getFile(),
                    'line' => $e->getLine(),
                    'url' => $request->fullUrl(),
                    'method' => $request->method(),
                    'route' => $request->route()?->getName(),
                    'input' => $request->except(['password', 'password_confirmation', '_token']),
                    'user_id' => $request->user()?->id,
                    'user_email' => $request->user()?->email,
                    'ip' => $request->ip(),
                    'user_agent' => $request->userAgent(),
                    'trace' => $e->getTraceAsString(),
                ]);

                return response()->view('errors.500', [
                    'errorId' => $errorId,
                    'exceptionClass' => get_class($e),
                    'message' => $e->getMessage(),
                    'file' => $e->getFile(),
                    'line' => $e->getLine(),
                    'url' => $request->fullUrl(),
                    'method' => $request->method(),
                    'routeName' => $request->route()?->getName() ?? $request->route()?->uri(),
                    'userName' => $request->user()?->name_ar ?? $request->user()?->name,
                    'userId' => $request->user()?->id,
                    'ip' => $request->ip(),
                    'trace' => $trace,
                    'inputData' => $inputData,
                    'headers' => $headers,
                    'sessionData' => $sessionData,
                    'queries' => $queries,
                ], 500);
            }

            return $response;
        });
    })->create();
