<?php

namespace App\Core;

class Router
{
    private array $routes = [];
    private array $params = [];

    public function add(string $method, string $route, string $controller, string $action): self
    {
        $this->routes[] = [
            'method' => strtoupper($method),
            'route' => $route,
            'controller' => $controller,
            'action' => $action
        ];
        return $this;
    }

    public function get(string $route, string $controller, string $action): self
    {
        return $this->add('GET', $route, $controller, $action);
    }

    public function post(string $route, string $controller, string $action): self
    {
        return $this->add('POST', $route, $controller, $action);
    }

    public function match(string $url, string $method): ?array
    {
        $method = strtoupper($method);
        $url = $this->removeQueryString($url);
        $url = trim($url, '/');

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

            $pattern = $this->convertRouteToRegex($route['route']);
            
            if (preg_match($pattern, $url, $matches)) {
                $this->params = $this->extractParams($route['route'], $matches);
                
                return [
                    'controller' => $route['controller'],
                    'action' => $route['action'],
                    'params' => $this->params
                ];
            }
        }

        return null;
    }

    private function convertRouteToRegex(string $route): string
    {
        $route = trim($route, '/');
        $pattern = preg_replace('/\{([a-zA-Z_]+)\}/', '([^/]+)', $route);
        return '#^' . $pattern . '$#';
    }

    private function extractParams(string $route, array $matches): array
    {
        $params = [];
        preg_match_all('/\{([a-zA-Z_]+)\}/', $route, $paramNames);
        
        foreach ($paramNames[1] as $index => $name) {
            if (isset($matches[$index + 1])) {
                $params[$name] = $matches[$index + 1];
            }
        }
        
        return $params;
    }

    private function removeQueryString(string $url): string
    {
        if ($pos = strpos($url, '?')) {
            $url = substr($url, 0, $pos);
        }
        return $url;
    }

    public function getParams(): array
    {
        return $this->params;
    }

    public function dispatch(string $url, string $method): void
    {
        $match = $this->match($url, $method);

        if ($match === null) {
            http_response_code(404);
            echo View::render('errors/404', ['url' => $url], 'main');
            return;
        }

        $controllerClass = "App\\Controllers\\" . $match['controller'];
        $action = $match['action'];

        if (!class_exists($controllerClass)) {
            throw new \Exception("Контроллер {$controllerClass} не найден");
        }

        $controller = new $controllerClass();

        if (!method_exists($controller, $action)) {
            throw new \Exception("Метод {$action} не найден в контроллере {$controllerClass}");
        }

        call_user_func_array([$controller, $action], $match['params']);
    }
}
