<?php
/**
 * SalonPro X - Router
 * URL routing and dispatching to controllers
 */

namespace core;

class Router
{
    private array $routes = [];
    private array $globalMiddleware = [];
    private array $patterns = [
        ':any' => '([^/]+)',
        ':num' => '([0-9]+)',
        ':alpha' => '([a-zA-Z]+)',
        ':slug' => '([a-z0-9\-]+)',
    ];

    /**
     * Register a GET route
     */
    public function get(string $pattern, string $handler): void
    {
        $this->addRoute('GET', $pattern, $handler);
    }

    /**
     * Register a POST route
     */
    public function post(string $pattern, string $handler): void
    {
        $this->addRoute('POST', $pattern, $handler);
    }

    /**
     * Register a PUT route
     */
    public function put(string $pattern, string $handler): void
    {
        $this->addRoute('PUT', $pattern, $handler);
    }

    /**
     * Register a DELETE route
     */
    public function delete(string $pattern, string $handler): void
    {
        $this->addRoute('DELETE', $pattern, $handler);
    }

    /**
     * Register a route that accepts multiple methods
     */
    public function match(array $methods, string $pattern, string $handler): void
    {
        foreach ($methods as $method) {
            $this->addRoute(strtoupper($method), $pattern, $handler);
        }
    }

    /**
     * Register a route for any HTTP method
     */
    public function any(string $pattern, string $handler): void
    {
        $this->addRoute('GET|POST|PUT|DELETE|PATCH', $pattern, $handler);
    }

    /**
     * Add a route to the collection
     */
    private function addRoute(string $method, string $pattern, string $handler): void
    {
        // Convert curly-brace placeholders to colon-prefix placeholders
        $pattern = preg_replace('/\{id\}/', ':num', $pattern);
        $pattern = preg_replace('/\{(\w+)\}/', ':any', $pattern);

        // Convert pattern placeholders to regex
        $pattern = str_replace(array_keys($this->patterns), array_values($this->patterns), $pattern);
        $pattern = '#^' . $pattern . '$#';

        $this->routes[] = [
            'method' => $method,
            'pattern' => $pattern,
            'handler' => $handler,
        ];
    }

    /**
     * Add global middleware
     */
    public function addGlobalMiddleware(string $middlewareClass): void
    {
        $this->globalMiddleware[] = $middlewareClass;
    }

    /**
     * Dispatch the current request to the appropriate controller
     */
    public function dispatch(Request $request): void
    {
        $method = $request->method();
        $url = $request->url();
        $url = rtrim($url, '/') ?: '/';

        // Run global middleware
        foreach ($this->globalMiddleware as $mwClass) {
            $mw = new $mwClass();
            $mw->handle($request);
        }

        // Find matching route
        foreach ($this->routes as $route) {
            $routeMethods = explode('|', $route['method']);
            if (!in_array($method, $routeMethods)) {
                continue;
            }

            if (preg_match($route['pattern'], $url, $matches)) {
                array_shift($matches);
                $this->executeHandler($route['handler'], $matches);
                return;
            }
        }

        // No route matched - 404
        http_response_code(404);
        $this->executeHandler('ErrorController@notFound');
    }

    /**
     * Execute a controller@action handler with parameters
     */
    private function executeHandler(string $handler, array $params = []): void
    {
        $parts = explode('@', $handler);
        $controllerName = $parts[0];
        $action = $parts[1] ?? 'index';

        // Determine module namespace
        $controllerClass = $this->resolveControllerClass($controllerName);

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

        $controller = new $controllerClass();

        // Check middleware permissions
        if ($controller instanceof Controller) {
            $controller->runMiddleware($action);
        }

        // Call the action with parameters
        call_user_func_array([$controller, $action], $params);
    }

    /**
     * Resolve full controller class name from short name
     */
    private function resolveControllerClass(string $name): string
    {
        // Check if it's a fully qualified class name with namespace
        if (str_contains($name, '\\')) {
            return $name;
        }

        // Try to find the controller in modules
        $moduleName = $this->getModuleFromName($name);

        if ($moduleName) {
            return "Modules\\{$moduleName}\\Controllers\\{$name}";
        }

        return "Modules\\{$name}";
    }

    /**
     * Extract module name from controller name
     * Eg: DashboardController -> Dashboard
     * Eg: CustomerController -> Customers
     */
    private function getModuleFromName(string $controllerName): ?string
    {
        // Remove 'Controller' suffix
        $name = preg_replace('/Controller$/', '', $controllerName);

        // Module name mappings for plural/singular differences
        $mappings = [
            'Dashboard' => 'Dashboard',
            'Auth' => 'Authentication',
            'Role' => 'Roles',
            'Branch' => 'Branches',
            'Customer' => 'Customers',
            'Appointment' => 'Appointments',
            'Calendar' => 'Appointments',
            'Service' => 'Services',
            'Category' => 'Services',
            'Package' => 'Services',
            'POS' => 'POS',
            'Invoice' => 'POS',
            'Payment' => 'POS',
            'Refund' => 'POS',
            'Employee' => 'Employees',
            'Attendance' => 'Employees',
            'Commission' => 'Employees',
            'Salary' => 'Employees',
            'Performance' => 'Employees',
            'Product' => 'Inventory',
            'Supplier' => 'Inventory',
            'Purchase' => 'Inventory',
            'Stock' => 'Inventory',
            'Expense' => 'Accounting',
            'Income' => 'Accounting',
            'CashBook' => 'Accounting',
            'BankBook' => 'Accounting',
            'PettyCash' => 'Accounting',
            'Loyalty' => 'Loyalty',
            'GiftCard' => 'Loyalty',
            'Membership' => 'Loyalty',
            'Marketing' => 'Marketing',
            'Notification' => 'Notifications',
            'Report' => 'Reports',
            'Setting' => 'Settings',
            'Audit' => 'Audit',
            'Backup' => 'Settings',
            'Profile' => 'Authentication',
            'User' => 'Users',
            'Error' => 'Dashboard',
        ];

        return $mappings[$name] ?? null;
    }
}
