<?php
/**
 * Central Router
 * Handles clean URL routing, parameter extraction, middleware pipeline, and exception safety
 */

require_once __DIR__ . '/ErrorHandler.php';
require_once __DIR__ . '/../Helpers/Security.php';
require_once __DIR__ . '/Exceptions/NotFoundException.php';

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

    public function __construct() {
        $this->middlewareMap = [
            'auth'       => 'AuthMiddleware',
            'guest'      => 'GuestMiddleware',
            'csrf'       => 'CsrfMiddleware',
            'seller'     => 'SellerMiddleware',
            'admin'      => 'AdminMiddleware',
            'rate_limit' => 'RateLimitMiddleware',
        ];
    }

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

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

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

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

    private function addRoute(string $method, string $path, $handler, array $middlewares): void {
        $this->routes[] = [
            'method'      => $method,
            'path'        => '/' . trim($path, '/'),
            'handler'     => $handler,
            'middlewares' => $middlewares
        ];
    }

    public function dispatch(string $uri, string $requestMethod): void {
        // Apply Global Security Headers
        Security::applySecurityHeaders();

        $config = require __DIR__ . '/../../config/app.php';
        $basePath = rtrim($config['base_path'] ?? '', '/');

        // Clean URI
        $parsedUrl = parse_url($uri);
        $path = $parsedUrl['path'] ?? '/';

        // Strip base path (e.g. /CARGOO)
        if ($basePath !== '' && strpos($path, $basePath) === 0) {
            $path = substr($path, strlen($basePath));
        }

        // Normalize /index.php to /
        if ($path === '/index.php') {
            $path = '/';
        }

        $path = '/' . trim($path, '/');
        if ($path === '') {
            $path = '/';
        }

        // Support _method override in forms
        if ($requestMethod === 'POST' && isset($_POST['_method'])) {
            $requestMethod = strtoupper($_POST['_method']);
        }

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

            $pattern = $this->convertPathToRegex($route['path']);
            if (preg_match($pattern, $path, $matches)) {
                array_shift($matches); // Remove full match

                // Execute Middlewares
                foreach ($route['middlewares'] as $mw) {
                    $mwClass = $this->middlewareMap[$mw] ?? $mw;
                    $mwFile = __DIR__ . '/../Middleware/' . $mwClass . '.php';
                    if (file_exists($mwFile)) {
                        require_once $mwFile;
                        $middleware = new $mwClass();
                        if (method_exists($middleware, 'handle')) {
                            $middleware->handle();
                        }
                    }
                }

                // Execute Handler
                $this->executeHandler($route['handler'], $matches);
                return;
            }
        }

        // Route not found -> throw NotFoundException
        throw new NotFoundException("ไม่พบหน้าที่คุณต้องการ ({$path})");
    }

    private function convertPathToRegex(string $path): string {
        if ($path === '/') {
            return '#^/$#';
        }
        // Convert {param} to ([^/]+)
        $pattern = preg_replace('#\{[a-zA-Z0-9_]+\}#', '([^/]+)', $path);
        return '#^' . $pattern . '$#';
    }

    private function executeHandler($handler, array $params): void {
        if (is_array($handler) && count($handler) === 2) {
            [$controllerClass, $method] = $handler;
            $controllerFile = __DIR__ . '/../Controllers/' . $controllerClass . '.php';

            if (file_exists($controllerFile)) {
                require_once $controllerFile;
            }

            if (class_exists($controllerClass)) {
                $controller = new $controllerClass();
                if (method_exists($controller, $method)) {
                    call_user_func_array([$controller, $method], $params);
                    return;
                }
            }
        }

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

        throw new NotFoundException("ไม่พบคอนโทรลเลอร์หรือเมธอดที่รองรับคำขอนี้");
    }
}
