<?php

use App\Enums\AppStatus;
use App\Http\Middleware\AllowSubdomainCors;
use App\Http\Middleware\ForceWwwRedirect;
use App\Http\Middleware\CheckPermission;
use App\Http\Middleware\RecordOperationLog;
use App\Http\Middleware\SubdomainSession;
use App\Http\Responses\ApiResponse;
use App\Models\AppModel;
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\Validation\ValidationException;
use Symfony\Component\HttpKernel\Exception\HttpException;
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;

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->alias([
            'permission' => CheckPermission::class,
            'operation_log' => RecordOperationLog::class,
            'subdomain.session' => SubdomainSession::class,
        ]);

        $middleware->redirectGuestsTo(function (\Illuminate\Http\Request $request): string {
            if (str_starts_with($request->path(), 'user')) {
                return '/user/login';
            }

            return '/admin/login';
        });

        $middleware->prepend(AllowSubdomainCors::class);
        // ForceWwwRedirect 后 prepend，使其位于栈顶，最先执行
        // 开启后未绑定应用的子域名与根域名 301 跳转到 www 主域名
        $middleware->prepend(ForceWwwRedirect::class);

        $middleware->validateCsrfTokens(except: [
            'api/user/*',
            'api/comment/*',
            'admin/*/api/*',
            'api/v1/*',
            'api/lmarena/*',
        ]);
    })
    ->withExceptions(function (Exceptions $exceptions): void {
        $exceptions->render(function (ValidationException $e, $request) {
            if ($request->expectsJson()) {
                return response()->json(
                    ApiResponse::error(40201, '请求参数不合法', $e->errors()),
                    422
                );
            }

            return redirect()->back()->withInput()->withErrors($e->errors());
        });

        $exceptions->render(function (AuthenticationException $e, $request) {
            if ($request->expectsJson()) {
                return response()->json(
                    ApiResponse::error(40003, '登录已过期，请重新登录'),
                    401
                );
            }

            return redirect()->guest(
                (str_starts_with($request->path(), 'user') || str_starts_with($request->path(), 'boxcode')) ? '/user/login' : route('admin.login')
            );
        });

        $exceptions->render(function (AuthorizationException $e, $request) {
            if ($request->expectsJson()) {
                return response()->json(
                    ApiResponse::error(40101, '无访问权限'),
                    403
                );
            }

            return response()->view('errors.403', [], 403);
        });

        $exceptions->render(function (ModelNotFoundException $e, $request) {
            if ($request->expectsJson()) {
                return response()->json(
                    ApiResponse::error(40401, '请求的资源不存在'),
                    404
                );
            }

            return response()->view('errors.404', [], 200);
        });

        $exceptions->render(function (NotFoundHttpException $e, $request) {
            $path = $request->path();
            $segments = explode('/', $path);

            if (isset($segments[1]) && ($segments[0] === 'admin' || $segments[0] === 'user')) {
                try {
                    $app = AppModel::where('app_id', $segments[1])->first();

                    if ($app && $app->status !== AppStatus::ENABLED) {
                        if ($request->expectsJson()) {
                            return response()->json(
                                ApiResponse::error(40301, "应用「{$app->name}」未启用，无法访问"),
                                403
                            );
                        }

                        $view = $segments[0] === 'user'
                            ? 'errors.user-app-disabled'
                            : 'errors.app-disabled';

                        return response()->view($view, ['appName' => $app->name], 403);
                    }
                } catch (\Throwable) {
                }
            }

            if ($request->expectsJson()) {
                return response()->json(
                    ApiResponse::error(40401, '请求的资源不存在'),
                    404
                );
            }

            return response()->view('errors.404', [], 200);
        });

        // CSRF Token 过期或失效（Laravel prepareException 会将 TokenMismatchException 转为 HttpException(419)）
        $exceptions->render(function (HttpException $e, $request) {
            if ($e->getStatusCode() !== 419) {
                return;
            }

            if ($request->expectsJson()) {
                return response()->json(
                    ApiResponse::error(41901, '页面已过期，请刷新后重试'),
                    419
                );
            }

            // 登录页 CSRF 过期时直接重定向到登录路由，确保获取新 session 和 token
            if ($request->is('admin/login') || $request->is('user/login')) {
                $route = $request->is('user/login') ? '/user/login' : '/admin/login';
                return redirect($route)->with('error', '页面已过期，请刷新后重试');
            }

            return redirect()->back()->with('error', '页面已过期，请刷新后重试');
        });

        $exceptions->render(function (Throwable $e, $request) {
            if ($request->expectsJson()) {
                $data = null;
                if (config('app.debug')) {
                    $data = [
                        'exception' => get_class($e),
                        'message' => $e->getMessage(),
                        'file' => $e->getFile(),
                        'line' => $e->getLine(),
                    ];
                }

                return response()->json(
                    ApiResponse::error(50001, '服务器内部错误', $data),
                    500
                );
            }

            if (config('app.debug')) {
                return response()->view('errors.debug', [
                    'exception' => get_class($e),
                    'message' => $e->getMessage(),
                    'file' => $e->getFile(),
                    'line' => $e->getLine(),
                    'trace' => collect($e->getTrace())->map(fn ($frame) => [
                        'file' => $frame['file'] ?? 'internal',
                        'line' => $frame['line'] ?? '',
                        'function' => $frame['function'] ?? '',
                    ])->take(20),
                ], 500);
            }

            return response('服务器内部错误', 500);
        });
    })->create();
