<?php

use App\Domains\Auth\Exceptions\AccountLockedException;
use App\Domains\Catalog\Exceptions\StockReservationExpiredException;
use App\Domains\Purchase\Exceptions\InsufficientStockException;
use App\Domains\Purchase\Exceptions\PurchaseExpiredException;
use App\Domains\Purchase\Exceptions\PurchaseLimitExceededException;
use App\Domains\Ticket\Exceptions\TicketNotAvailableException;
use App\Http\Middleware\EnsureAdminAppTenant;
use App\Http\Middleware\EnsureScannerTenant;
use App\Http\Middleware\EnsureTenantHasMenu;
use App\Http\Middleware\SetApiLocale;
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\Request;
use Symfony\Component\HttpKernel\Exception\MethodNotAllowedHttpException;
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([
            'adminapp.tenant' => EnsureAdminAppTenant::class,
            'scanner.tenant' => EnsureScannerTenant::class,
            'tenant.menu' => EnsureTenantHasMenu::class,
        ]);
        $middleware->encryptCookies(except: [
            'guest_token',
        ]);
        $middleware->prepend(SetApiLocale::class);
    })
    ->withExceptions(function (Exceptions $exceptions): void {
        $exceptions->shouldRenderJsonWhen(
            fn (Request $request) => $request->is('api/*'),
        );
        $exceptions->render(function (AuthenticationException $exception, Request $request) {
            if (! $request->is('api/*')) {
                return null;
            }

            return response()->json([
                'code' => 'auth.unauthenticated',
                'message' => __('api.auth.unauthenticated'),
            ], 401);
        });
        $exceptions->render(function (AccountLockedException $exception, Request $request) {
            if (! $request->is('api/*')) {
                return null;
            }

            $retryAfter = $exception->retryAfterSeconds();

            return response()->json([
                'code' => 'auth.account_locked',
                'message' => __('api.auth.account_locked'),
                'retry_after' => $retryAfter,
                'locked_until' => $exception->lockedUntil->toIso8601String(),
            ], 429, [
                'Retry-After' => (string) $retryAfter,
            ]);
        });
        $exceptions->render(function (AuthorizationException $exception, Request $request) {
            if (! $request->is('api/*')) {
                return null;
            }

            return response()->json([
                'code' => 'errors.forbidden',
                'message' => __('api.errors.forbidden'),
            ], 403);
        });
        $exceptions->render(function (InsufficientStockException $exception, Request $request) {
            if (! $request->is('api/*')) {
                return null;
            }

            return response()->json([
                'code' => 'purchase.insufficient_stock',
                'message' => $exception->getMessage(),
                'errors' => $exception->errors(),
                'unavailable_items' => $exception->unavailableItems,
            ], 422);
        });
        $exceptions->render(function (PurchaseLimitExceededException $exception, Request $request) {
            if (! $request->is('api/*')) {
                return null;
            }

            return response()->json([
                'code' => 'purchase.limit_exceeded',
                'message' => $exception->getMessage(),
                'errors' => $exception->errors(),
                'catalog_item_id' => $exception->catalogItemId,
                'catalog_item_name' => $exception->catalogItemName,
                'maximum_addable_quantity' => $exception->maximumAddableQuantity,
            ], 422);
        });
        $exceptions->render(function (PurchaseExpiredException $exception, Request $request) {
            if (! $request->is('api/*')) {
                return null;
            }

            return response()->json([
                'code' => 'purchase.expired',
                'message' => $exception->getMessage(),
            ], 422);
        });
        $exceptions->render(function (StockReservationExpiredException $exception, Request $request) {
            if (! $request->is('api/*')) {
                return null;
            }

            return response()->json([
                'code' => 'stock_reservation.expired',
                'message' => $exception->getMessage(),
            ], 422);
        });
        $exceptions->render(function (ModelNotFoundException $exception, Request $request) {
            if (! $request->is('api/*')) {
                return null;
            }

            return response()->json([
                'code' => 'errors.not_found',
                'message' => __('api.errors.not_found'),
            ], 404);
        });
        $exceptions->render(function (TicketNotAvailableException $exception, Request $request) {
            if (! $request->is('api/*')) {
                return null;
            }

            return response()->json([
                'code' => 'ticket.not_available',
                'message' => __('api.ticket.not_available'),
            ], 404);
        });
        $exceptions->render(function (NotFoundHttpException $exception, Request $request) {
            if (! $request->is('api/*')) {
                return null;
            }

            return response()->json([
                'code' => 'errors.not_found',
                'message' => __('api.errors.not_found'),
            ], 404);
        });
        $exceptions->render(function (MethodNotAllowedHttpException $exception, Request $request) {
            if (! $request->is('api/*')) {
                return null;
            }

            return response()->json([
                'code' => 'errors.method_not_allowed',
                'message' => __('api.errors.method_not_allowed'),
            ], 405, $exception->getHeaders());
        });
    })->create();
