<?php
declare(strict_types=1);

namespace App\Core;

use App\Http\Request;
use App\Http\HttpException;

class Router
{
    /**
     * @var array<string, array<int, array{pattern:string, handler:mixed}>>
     */
    private array $routes = [];

    /**
     * Registrar una ruta
     *
     * @param string $method  GET, POST, etc.
     * @param string $pattern /api/v1/documentos
     * @param mixed  $handler Puede ser closure o [Clase::class, 'método']
     */
    public function add(string $method, string $pattern, $handler): void
    {
        $method = strtoupper($method);
        $this->routes[$method][] = [
            'pattern' => rtrim($pattern, '/') ?: '/',
            'handler' => $handler,
        ];
    }

    /**
     * Despachar la petición actual
     *
     * @throws HttpException
     */
    public function dispatch(): void
    {
        $request = new Request();

        $method = $request->getMethod();
        $path   = $request->getPath();

        $methodRoutes = $this->routes[$method] ?? [];

        foreach ($methodRoutes as $route) {
            if ($route['pattern'] === $path) {
                $handler = $route['handler'];

                // Si el handler es [Clase, 'método'], instanciamos la clase
                if (is_array($handler) && is_string($handler[0])) {
                    $className  = $handler[0];
                    $methodName = $handler[1];
                    $controller = new $className();
                    $handler    = [$controller, $methodName];
                }

                if (!is_callable($handler)) {
                    throw new HttpException('Handler no invocable', 500);
                }

                // Ejecutar el handler con el Request
                $handler($request);
                return;
            }
        }

        throw new HttpException('Ruta no encontrada', 404);
    }
}
