<?php
class Router
{
    private array $routes = [];

    public function addRoute(string $method, string $pattern, $handler, ?string $permission = null, ?string $moduleName = null, array $middleware = []): void
    {
        $this->routes[] = [
            'method'     => strtoupper($method),
            'pattern'    => $pattern,
            'handler'    => $handler,
            'permission' => $permission,
            'module'     => $moduleName,
            'middleware'  => $middleware,
        ];
    }

    public function dispatch(Request $request): void
    {
        $method = $request->method();
        $uri = $request->uri();

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

            $params = $this->matchPattern($route['pattern'], $uri);
            if ($params === false) continue;

            $request->setRouteParams($params);

            // Run middleware
            foreach ($route['middleware'] as $mw) {
                $this->runMiddleware($mw, $request);
            }

            // Check permission
            if ($route['permission']) {
                if (!Auth::check()) {
                    if ($request->isAjax()) {
                        Response::json(['success' => false, 'message' => 'Unauthorized'], 401);
                    }
                    Response::redirect('/login');
                    return;
                }
                Gate::authorize($route['permission']);
            }

            // Resolve handler
            $this->callHandler($route['handler'], $request, $route['module']);
            return;
        }

        // 404
        http_response_code(404);
        if ($request->isAjax()) {
            Response::json(['success' => false, 'message' => 'Not found'], 404);
        }
        $viewFile = ROOT_PATH . '/views/errors/404.php';
        if (file_exists($viewFile)) {
            $data = ['code' => 404, 'message' => 'Page not found'];
            $view = View::getInstance();
            $layout = Auth::check() ? 'app' : 'auth';
            $view->render('errors/404', $data, $layout);
        } else {
            echo '<h1>404 Not Found</h1>';
        }
        exit;
    }

    private function matchPattern(string $pattern, string $uri)
    {
        // Convert {param} to regex groups
        $regex = preg_replace('/\{([a-zA-Z_]+)\}/', '(?P<$1>[^/]+)', $pattern);
        $regex = '#^' . $regex . '$#';

        if (preg_match($regex, $uri, $matches)) {
            $params = [];
            foreach ($matches as $key => $value) {
                if (is_string($key)) {
                    $params[$key] = $value;
                }
            }
            return $params;
        }

        return false;
    }

    private function runMiddleware(string $middlewareClass, Request $request): void
    {
        if (class_exists($middlewareClass)) {
            $mw = new $middlewareClass();
            $mw->handle($request);
        }
    }

    private function callHandler($handler, Request $request, ?string $moduleName): void
    {
        if (is_callable($handler)) {
            call_user_func($handler, $request);
            return;
        }

        if (is_string($handler) && str_contains($handler, '@')) {
            [$controllerName, $methodName] = explode('@', $handler);

            // Try to load from module
            if ($moduleName) {
                $controllerFile = ROOT_PATH . '/modules/' . $moduleName . '/Controllers/' . $controllerName . '.php';
                if (file_exists($controllerFile)) {
                    require_once $controllerFile;
                }
            }

            // Try core controllers
            if (!class_exists($controllerName)) {
                $coreControllerFile = ROOT_PATH . '/core/' . $controllerName . '.php';
                if (file_exists($coreControllerFile)) {
                    require_once $coreControllerFile;
                }
            }

            if (!class_exists($controllerName)) {
                throw new \RuntimeException("Controller not found: {$controllerName}");
            }

            $controller = new $controllerName();
            if ($controller instanceof Controller) {
                $controller->setRequest($request);
                if ($moduleName) {
                    $controller->setModuleName($moduleName);
                }
            }

            if (!method_exists($controller, $methodName)) {
                throw new \RuntimeException("Method not found: {$controllerName}@{$methodName}");
            }

            $controller->$methodName($request);
        }
    }
}