<?php

namespace App\Core;

/**
 * Roteador simples baseado em URI.
 * Suporta rotas GET e POST com parâmetros dinâmicos (:param).
 */
class Router
{
    /** @var array<string, array<string, callable|array>> */
    private array $routes = [];

    /** @var callable|null Ação executada quando nenhuma rota é encontrada */
    private $notFound = null;

    // -------------------------------------------------------------------------
    // Registro de rotas
    // -------------------------------------------------------------------------

    public function get(string $uri, callable|array $action): void
    {
        $this->addRoute('GET', $uri, $action);
    }

    public function post(string $uri, callable|array $action): void
    {
        $this->addRoute('POST', $uri, $action);
    }

    private function addRoute(string $method, string $uri, callable|array $action): void
    {
        // Converte :param em grupos de captura nomeados
        $pattern = preg_replace('#:([a-zA-Z_]+)#', '(?P<$1>[^/]+)', $uri);
        $this->routes[$method][$pattern] = $action;
    }

    // -------------------------------------------------------------------------
    // Resolução da rota atual
    // -------------------------------------------------------------------------

    public function resolve(): void
    {
        $method = $_SERVER['REQUEST_METHOD'] ?? 'GET';
        $uri    = parse_url($_SERVER['REQUEST_URI'] ?? '/', PHP_URL_PATH);

        foreach ($this->routes[$method] ?? [] as $pattern => $action) {
            if (preg_match("#^{$pattern}$#", $uri, $matches)) {
                // Filtra apenas os parâmetros nomeados (remove índices numéricos)
                $params = array_filter(
                    $matches,
                    fn($k) => !is_int($k),
                    ARRAY_FILTER_USE_KEY
                );

                $this->dispatch($action, $params);
                return;
            }
        }

        $this->handleNotFound();
    }

    // -------------------------------------------------------------------------
    // Despacho da ação
    // -------------------------------------------------------------------------

    private function dispatch(callable|array $action, array $params): void
    {
        if (is_callable($action)) {
            call_user_func_array($action, $params);
            return;
        }

        // Formato: [NomeController::class, 'nomeMetodo']
        [$controllerClass, $method] = $action;

        if (!class_exists($controllerClass)) {
            throw new \RuntimeException("Controller não encontrado: {$controllerClass}");
        }

        $controller = new $controllerClass();

        if (!method_exists($controller, $method)) {
            throw new \RuntimeException("Método não encontrado: {$controllerClass}::{$method}");
        }

        call_user_func_array([$controller, $method], $params);
    }

    // -------------------------------------------------------------------------
    // 404
    // -------------------------------------------------------------------------

    public function setNotFound(callable $callback): void
    {
        $this->notFound = $callback;
    }

    private function handleNotFound(): void
    {
        http_response_code(404);

        if ($this->notFound) {
            call_user_func($this->notFound);
            return;
        }

        echo '<h1>404 — Página não encontrada</h1>';
    }
}
