<?php

namespace App\Core;

class Router {
    private $routes = [];

    public function add($method, $path, $handler) {
        // Convert path parameters {id} to regex named groups (?P<id>[^/]+)
        $pathRegex = preg_replace('/\{([a-zA-Z0-9_]+)\}/', '(?P<$1>[^/]+)', $path);
        $this->routes[] = [
            'method' => $method,
            'path' => '#^' . $pathRegex . '$#',
            'handler' => $handler
        ];
    }

    public function get($path, $handler) {
        $this->add('GET', $path, $handler);
    }

    public function post($path, $handler) {
        $this->add('POST', $path, $handler);
    }

    public function put($path, $handler) {
        $this->add('PUT', $path, $handler);
    }

    public function delete($path, $handler) {
        $this->add('DELETE', $path, $handler);
    }

    public function dispatch($method, $uri) {
        // Remove query string
        $uri = explode('?', $uri)[0];
        // Remove trailing slash if not root
        if ($uri !== '/' && substr($uri, -1) === '/') {
            $uri = substr($uri, 0, -1);
        }

        foreach ($this->routes as $route) {
            if ($route['method'] === $method && preg_match($route['path'], $uri, $matches)) {
                // Filter numeric keys from matches
                $params = array_filter($matches, function($key) {
                    return !is_numeric($key);
                }, ARRAY_FILTER_USE_KEY);

                return $this->callHandler($route['handler'], $params);
            }
        }

        http_response_code(404);
        echo json_encode([
            'error' => 'Not Found', 
            'debug' => [
                'method' => $method,
                'path' => $uri
            ]
        ]);
    }

    private function callHandler($handler, $params) {
        if (is_array($handler) && count($handler) === 2) {
            $controllerName = $handler[0];
            $methodName = $handler[1];
            $controller = new $controllerName();
            return call_user_func_array([$controller, $methodName], $params);
        }

        if (is_callable($handler)) {
             return call_user_func_array($handler, $params);
        }
    }
}
