<?php
/**
 * BOAFO Router
 * Front Controller Pattern — maps URI to Controller@method
 */
class Router {
    private array $routes = [];
    private array $middlewares = [];

    public function get(string $uri, string $action, array $middleware = []): void {
        $this->addRoute('GET', $uri, $action, $middleware);
    }

    public function post(string $uri, string $action, array $middleware = []): void {
        $this->addRoute('POST', $uri, $action, $middleware);
    }

    private function addRoute(string $method, string $uri, string $action, array $middleware): void {
        $this->routes[] = [
            'method'     => $method,
            'uri'        => $uri,
            'action'     => $action,
            'middleware' => $middleware,
        ];
    }

    public function dispatch(string $requestUri, string $requestMethod): void {
        // Strip query string
        $uri = parse_url($requestUri, PHP_URL_PATH);

        // Strip base path for XAMPP subdirectory
        $basePath = '/BOAFO/public';
        if (str_starts_with($uri, $basePath)) {
            $uri = substr($uri, strlen($basePath));
        }
        $uri = '/' . trim($uri, '/');
        if ($uri === '/') $uri = '/';

        foreach ($this->routes as $route) {
            $pattern = $this->buildPattern($route['uri']);
            if ($route['method'] === $requestMethod && preg_match($pattern, $uri, $matches)) {
                // Run middleware
                foreach ($route['middleware'] as $mw) {
                    Middleware::run($mw);
                }

                // Extract named params
                $params = array_filter($matches, 'is_string', ARRAY_FILTER_USE_KEY);

                // Dispatch controller
                [$controllerName, $method] = explode('@', $route['action']);
                $controllerFile = APP_PATH . '/Controllers/' . $controllerName . '.php';
                if (!file_exists($controllerFile)) {
                    $this->abort(500, "Controller not found: {$controllerName}");
                }
                require_once $controllerFile;
                $controller = new $controllerName();
                $controller->$method(...array_values($params));
                return;
            }
        }
        $this->abort(404);
    }

    private function buildPattern(string $uri): string {
        $pattern = preg_replace('/\{([a-zA-Z0-9_]+)\}/', '(?P<$1>[^/]+)', $uri);
        return '#^' . $pattern . '$#';
    }

    public function abort(int $code, string $message = ''): void {
        http_response_code($code);
        $messages = [404 => 'Page Not Found', 403 => 'Forbidden', 500 => 'Server Error'];
        $title = $messages[$code] ?? 'Error';
        require APP_PATH . '/Views/errors/error.php';
        exit;
    }
}
