<?php

use Illuminate\Foundation\Application;
use Illuminate\Foundation\Configuration\Exceptions;
use Illuminate\Foundation\Configuration\Middleware;
use Modules\Auth\Http\Middleware\CheckPasswordChanged;
use Modules\Auth\Http\Middleware\HandleJwtExceptions;
use Illuminate\Http\Response;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
use Illuminate\Auth\AuthenticationException;
use Symfony\Component\HttpKernel\Exception\AccessDeniedHttpException;
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
use Symfony\Component\HttpKernel\Exception\MethodNotAllowedHttpException;
use Symfony\Component\Routing\Exception\RouteNotFoundException;
use Illuminate\Validation\ValidationException;
use Symfony\Component\HttpKernel\Exception\HttpException;
use Illuminate\Database\Eloquent\ModelNotFoundException;
use Illuminate\Support\Facades\Log;
use PHPOpenSourceSaver\JWTAuth\Exceptions\JWTException;
use PHPOpenSourceSaver\JWTAuth\Exceptions\TokenExpiredException;
use PHPOpenSourceSaver\JWTAuth\Exceptions\TokenInvalidException;
use PHPOpenSourceSaver\JWTAuth\Http\Middleware\Authenticate;

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->group('api.auth', [
            HandleJwtExceptions::class,
            Authenticate::class,
            CheckPasswordChanged::class,
        ]);
    })
    ->withExceptions(function (Exceptions $exceptions): void {
        // Unauthorized Access
        $exceptions->render(function (AuthenticationException $e, Request $request) {
            return $request->is('api/*')
                ? response()->json(['status' => false, 'message' => 'Unauthorized access. Please log in.'], 401)
                : redirect()->route('login')->with('error', 'Unauthorized access. Please log in.');
        });

        // JWT Token Expired
        $exceptions->render(function (TokenExpiredException $e, Request $request) {
            return $request->is('api/*')
                ? response()->json([
                    'status' => false,
                    'message' => 'Your session has expired. Please log in again.',
                ], 401)
                : redirect()->route('login')->with('error', 'Your session has expired. Please log in again.');
        });

        // JWT Token Invalid
        $exceptions->render(function (TokenInvalidException $e, Request $request) {
            return $request->is('api/*')
                ? response()->json([
                    'status' => false,
                    'message' => 'Your token is invalid.',
                ], 401)
                : redirect()->route('login')->with('error', 'Your token is invalid.');
        });

        // Token Not Provided or Cannot Be Parsed
        $exceptions->render(function (JWTException $e, Request $request) {
            return $request->is('api/*')
                ? response()->json([
                    'status' => false,
                    'message' => 'Token is missing or could not be parsed.',
                ], 401)
                : redirect()->route('login')->with('error', 'Token is missing or could not be parsed.');
        });

        // Forbidden Access
        $exceptions->render(function (AccessDeniedHttpException $e, Request $request) {
            return $request->is('api/*')
                ? response()->json(['status' => false, 'message' => 'You do not have permission to perform this action.'], 403)
                : back()->with('error', 'You do not have permission to perform this action.');
        });

        // Not Found
        $exceptions->render(function (NotFoundHttpException|ModelNotFoundException $e, Request $request) {
            return $request->is('api/*')
                ? response()->json(['status' => false, 'message' => 'Resource not found.'], 404)
                : abort(404, 'Resource not found.');
        });

        // Method Not Allowed
        $exceptions->render(function (MethodNotAllowedHttpException $e, Request $request) {
            return $request->is('api/*')
                ? response()->json(['status' => false, 'message' => 'HTTP method not allowed for this route.'], 405)
                : abort(405, 'HTTP method not allowed.');
        });

        // Route Not Found
        $exceptions->render(function (RouteNotFoundException $e, Request $request) {
            return $request->is('api/*')
                ? response()->json(['status' => false, 'message' => 'Route not found.'], 404)
                : abort(404, 'Route not found.');
        });

        // Validation Exception
        $exceptions->render(function (ValidationException $e, Request $request) {
            return $request->is('api/*')
                ? response()->json([
                    'status'  => false,
                    'message' => 'Validation failed.',
                    'errors'  => $e->errors(),
                ], 422)
                : back()->withErrors($e->errors())->withInput();
        });

        // General HTTP Exceptions
        $exceptions->render(function (HttpException $e, Request $request) {
            return $request->is('api/*')
                ? response()->json([
                    'status'  => false,
                    'message' => $e->getMessage(),
                ], $e->getStatusCode())
                : abort($e->getStatusCode(), $e->getMessage());
        });

        // General Error Handling (500 Errors)
        $exceptions->render(function (\Throwable $e, Request $request) {
            Log::error($e); // Logs the error for debugging

            return $request->is('api/*')
                ? response()->json([
                    'status'  => false,
                    'message' => 'Something went wrong. Please try again later.',
                ], 500)
                : abort(500, 'Something went wrong. Please try again later.');
        });

        // Response Handling
        $exceptions->respond(function ($response) {
            if (!($response instanceof Response) && !($response instanceof JsonResponse)) {
                return $response;
            }

            $errorMessages = [
                401 => 'You must be logged in to access this page.',
                403 => 'You do not have permission to access this page.',
                404 => 'The page you are looking for could not be found.',
                405 => 'The method used is not allowed on this page.',
                419 => 'The page expired, please try again.',
                500 => 'An internal server error occurred.',
            ];

            $status = $response->getStatusCode();
            $request = request(); // Retrieve the current request instance

            // API Response
            if ($request->is('api/*')) {
                return response()->json([
                    'status'  => false,
                    'message' => $errorMessages[$status] ?? 'An error occurred.',
                ], $status);
            }

            // Web Response
            return back()->with([
                'message' => $errorMessages[$status] ?? 'An error occurred.',
            ]);
        });
    })->create();
