<?php

use App\Models\Error;
use Illuminate\Foundation\Application;
use Illuminate\Foundation\Configuration\Exceptions;
use Illuminate\Foundation\Configuration\Middleware;
use Illuminate\Http\Exceptions\HttpResponseException;
use Illuminate\Http\Exceptions\ThrottleRequestsException;
use Illuminate\Http\Request;
use Illuminate\Session\TokenMismatchException;
use Illuminate\Validation\ValidationException;
use Symfony\Component\HttpKernel\Exception\HttpExceptionInterface;

return Application::configure(basePath: dirname(__DIR__))
    ->withRouting(
        web: __DIR__.'/../routes/web.php',
        commands: __DIR__.'/../routes/console.php',
        health: '/up',
    )
    ->withMiddleware(function (Middleware $middleware): void {
        $middleware->append(\App\Http\Middleware\SecurityHeaders::class);
    })
    ->withExceptions(function (Exceptions $exceptions): void {
        $exceptions->report(function (Throwable $exception): void {
            if ($exception instanceof ThrottleRequestsException
                || $exception instanceof ValidationException
                || $exception instanceof HttpResponseException) {
                return;
            }

            if ($exception instanceof HttpExceptionInterface
                && in_array($exception->getStatusCode(), [401, 403, 404, 419, 422, 429], true)) {
                return;
            }

            try {
                $codigo = (string) $exception->getCode();
                if ($codigo === '') {
                    $codigo = class_basename($exception);
                }

                $url = app()->runningInConsole()
                    ? 'console'
                    : (string) request()?->fullUrl();

                Error::query()->create([
                    'codigo' => mb_substr($codigo, 0, 255),
                    'mensaje' => mb_substr((string) ($exception->getMessage() ?: class_basename($exception)), 0, 65000),
                    'track_trace' => mb_substr($exception->getTraceAsString(), 0, 65000),
                    'url' => mb_substr($url !== '' ? $url : 'desconocida', 0, 255),
                    'fecha_hora' => now(),
                ]);
            } catch (Throwable $loggingException) {
                // Evita que un error al registrar el error rompa el flujo original.
            }
        });

        $exceptions->render(function (ThrottleRequestsException $exception, Request $request) {
            $retryAfter = (int) ($exception->getHeaders()['Retry-After'] ?? 60);
            $retryAfter = max($retryAfter, 1);

            $minutos = intdiv($retryAfter, 60);
            $segundos = $retryAfter % 60;
            $partesTiempo = [];

            if ($minutos > 0) {
                $partesTiempo[] = $minutos . ' minuto' . ($minutos === 1 ? '' : 's');
            }

            if ($segundos > 0 || empty($partesTiempo)) {
                $partesTiempo[] = $segundos . ' segundo' . ($segundos === 1 ? '' : 's');
            }

            $mensaje = 'Demasiados intentos. Esperá ' . implode(' y ', $partesTiempo) . ' antes de volver a intentar.';

            if ($request->expectsJson()) {
                return response()->json([
                    'message' => $mensaje,
                    'retry_after' => $retryAfter,
                ], 429, $exception->getHeaders());
            }

            $sessionKey = $request->is('login/*') ? 'login_error' : 'recuperar_error';

            return back()
                ->withInput($request->except([
                    'contra',
                    'contra_confirmation',
                    'contra_actual',
                    'contra_actual_secreta',
                ]))
                ->with($sessionKey, $mensaje);
        });

        $exceptions->render(function (TokenMismatchException $exception, Request $request) {
            $mensaje = 'La sesión cambió en otra pestaña o expiró. Recargá la página y volvé a intentar.';

            if ($request->expectsJson()) {
                return response()->json([
                    'message' => $mensaje,
                ], 419);
            }

            return back()
                ->withInput($request->except([
                    'contra',
                    'contra_confirmation',
                    'contra_actual',
                    'contra_actual_secreta',
                ]))
                ->withErrors(['csrf' => $mensaje]);
        });
    })->create();
