<?php
namespace App\Core;

class Router
{
    private array $routes = [];
    /** @var callable[] */
    private array $groupMiddleware = [];

    public function get(string $path, $handler, array $middleware = []): void { $this->add('GET', $path, $handler, $middleware); }
    public function post(string $path, $handler, array $middleware = []): void { $this->add('POST', $path, $handler, $middleware); }

    private function add(string $method, string $path, $handler, array $middleware): void
    {
        $pattern = preg_replace('#\{[a-zA-Z_]+\}#', '([^/]+)', $path);
        $pattern = '#^' . $pattern . '$#';
        preg_match_all('#\{([a-zA-Z_]+)\}#', $path, $paramNames);
        $this->routes[] = [
            'method' => $method,
            'pattern' => $pattern,
            'params' => $paramNames[1],
            'handler' => $handler,
            'middleware' => array_merge($this->groupMiddleware, $middleware),
        ];
    }

    public function group(array $middleware, callable $callback): void
    {
        $prev = $this->groupMiddleware;
        $this->groupMiddleware = array_merge($this->groupMiddleware, $middleware);
        $callback($this);
        $this->groupMiddleware = $prev;
    }

    public function dispatch(): void
    {
        $method = Request::method();
        $path = Request::path();

        foreach ($this->routes as $route) {
            if ($route['method'] !== $method) continue;
            if (!preg_match($route['pattern'], $path, $matches)) continue;

            array_shift($matches);
            $args = array_combine($route['params'], $matches);

            foreach ($route['middleware'] as $mw) {
                $result = $mw();
                if ($result === false) return; // middleware handled the response (e.g. redirect)
            }

            [$controllerClass, $action] = $route['handler'];
            $controller = new $controllerClass();
            call_user_func_array([$controller, $action], $args);
            return;
        }

        http_response_code(404);
        echo '<!doctype html><html><head><title>404</title></head><body style="font-family:sans-serif;padding:40px"><h1>404</h1><p>Page not found.</p><p><a href="' . Request::basePath() . '/">Home</a></p></body></html>';
    }
}
