<?php

namespace App\Core;

class Router
{
    private $routes = [];

    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);
    }

    private function add($method, $path, $handler)
    {
        $this->routes[] = [
            'method' => $method,
            'path' => $path,
            'handler' => $handler,
            'middleware' => []
        ];
    }

    public function addMiddleware($middleware)
    {
        // Add middleware to the last added route
        if (!empty($this->routes)) {
            $this->routes[count($this->routes) - 1]['middleware'][] = $middleware;
        }
    }

    public function dispatch($method, $uri)
    {
        $uri = parse_url($uri, PHP_URL_PATH);

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

            $pattern = preg_replace('/\{([a-zA-Z0-9_]+)\}/', '(?P<\1>[^/]+)', $route['path']);
            $pattern = '#^' . $pattern . '$#';

            if (preg_match($pattern, $uri, $matches)) {
                // Filter named matches
                $params = array_filter($matches, 'is_string', ARRAY_FILTER_USE_KEY);

                // Run Middlewares
                foreach ($route['middleware'] as $middleware) {
                    $middlewareInstance = new $middleware();
                    if (!$middlewareInstance->handle()) {
                        return; // Middleware blocked request
                    }
                }

                $handler = $route['handler'];
                if (is_array($handler)) {
                    $controller = new $handler[0]();
                    $method = $handler[1];
                    return call_user_func_array([$controller, $method], $params);
                }

                return call_user_func_array($handler, $params);
            }
        }

        http_response_code(404);
        echo "404 Not Found";
    }
}
