<?php

class Router {
    private array $routes = [];

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

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

    private function addRoute(string $method, string $path, $handler, array $middlewares): void {
        $regex = preg_replace('/\{([a-zA-Z0-9_]+)\}/', '(?P<\1>[a-zA-Z0-9_\-]+)', $path);
        $regex = '#^' . $regex . '$#';

        $this->routes[] = [
            'method'      => $method,
            'path'        => $path,
            'regex'       => $regex,
            'handler'     => $handler,
            'middlewares' => $middlewares
        ];
    }

    public function dispatch(string $uri, string $method): void {
        // Strip query string
        $path = parse_url($uri, PHP_URL_PATH) ?? '/';
        $path = urldecode($path);

        // Get the directory of index.php relative to web root
        $scriptName = $_SERVER['SCRIPT_NAME'] ?? '';
        $scriptDir = str_replace('\\', '/', dirname($scriptName));
        if ($scriptDir !== '/' && $scriptDir !== '.' && !empty($scriptDir)) {
            if (strpos($path, $scriptDir) === 0) {
                $path = substr($path, strlen($scriptDir));
            }
        }

        $path = '/' . trim($path, '/');
        if ($path === '') {
            $path = '/';
        }

        foreach ($this->routes as $route) {
            if ($route['method'] === $method && preg_match($route['regex'], $path, $matches)) {
                // Execute Middlewares
                foreach ($route['middlewares'] as $middleware) {
                    call_user_func($middleware);
                }

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

                // Execute Controller action
                if (is_array($route['handler'])) {
                    [$controllerClass, $methodName] = $route['handler'];
                    if (class_exists($controllerClass)) {
                        $controller = new $controllerClass();
                        if (method_exists($controller, $methodName)) {
                            call_user_func_array([$controller, $methodName], $params);
                            return;
                        }
                    }
                } elseif (is_callable($route['handler'])) {
                    call_user_func_array($route['handler'], $params);
                    return;
                }
            }
        }

        // 404 Handler
        http_response_code(404);
        require_once SITE_ROOT . '/app/Views/errors/404.php';
        exit;
    }
}
