<?php
declare(strict_types=1);

namespace App\Core;

/**
 * RESTful Router with Middleware Support
 */
class Router
{
    private array $routes = [];

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

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

    public function put(string $path, string|callable $handler, array $middleware = []): void
    {
        $this->addRoute('PUT', $path, $handler, $middleware);
    }

    public function delete(string $path, string|callable $handler, array $middleware = []): void
    {
        $this->addRoute('DELETE', $path, $handler, $middleware);
    }

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

    public function resolve(string $requestedMethod, string $requestedUri): void
    {
        $requestedUri = explode('?', $requestedUri)[0];
        
        // Strip base path from APP_URL if present
        $baseUrl = APP_URL;
        $basePath = parse_url($baseUrl, PHP_URL_PATH) ?: '';
        if ($basePath && strpos($requestedUri, $basePath) === 0) {
            $requestedUri = substr($requestedUri, strlen($basePath));
        }

        // Handles /api/v1 legacy or explicit prefixing within the router logic
        $apiPrefix = '/v1';
        if (strpos($requestedUri, $apiPrefix) === 0) {
            $requestedUri = substr($requestedUri, strlen($apiPrefix));
        }

        // Ensure root / always matches /
        if ($requestedUri === "" || $requestedUri === false) {
            $requestedUri = "/";
        }

        foreach ($this->routes as $route) {
            if ($route['method'] === $requestedMethod && preg_match($route['path'], $requestedUri, $matches)) {
                $params = array_filter($matches, 'is_string', ARRAY_FILTER_USE_KEY);

                // Run Middlewares
                foreach ($route['middleware'] as $mwClass) {
                    $middleware = new $mwClass();
                    if (!$middleware->handle()) {
                        return; // Middleware already sent response
                    }
                }

                if (is_callable($route['handler'])) {
                    call_user_func_array($route['handler'], $params);
                    return;
                }

                list($controllerClass, $method) = explode('@', $route['handler']);
                $controllerClass = "App\\Controllers\\" . $controllerClass;

                if (!class_exists($controllerClass)) {
                    Response::error("Controller $controllerClass not found", [], 500);
                }

                $controller = new $controllerClass();
                if (!method_exists($controller, $method)) {
                    Response::error("Method $method not found in $controllerClass", [], 500);
                }

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

        Response::error("Route not found: $requestedMethod $requestedUri", [], 404);
    }
}
