<?php
/**
 * Route Class - Laravel-inspired routing
 *
 * @package ZenoChatbot\Http
 */

namespace ZenoChatbot\Framework\Http;

// Prevent direct access
if (!defined('ABSPATH')) {
    exit;
}

/**
 * Route registration class
 */
class Route
{

    /**
     * Registered routes
     *
     * @var array
     */
    private static $routes = [];

    /**
     * Current route group attributes
     *
     * @var array
     */
    private static $groupStack = [];

    /**
     * Application instance
     *
     * @var \ZenoChatbot\Framework\Foundation\Application
     */
    private static $app = null;

    /**
     * Register GET route
     *
     * @param string $uri
     * @param mixed $action
     * @return void
     */
    public static function get($uri, $action)
    {
        static::addRoute('GET', $uri, $action);
    }

    /**
     * Register POST route
     *
     * @param string $uri
     * @param mixed $action
     * @return void
     */
    public static function post($uri, $action)
    {
        static::addRoute('POST', $uri, $action);
    }

    /**
     * Register PUT route
     *
     * @param string $uri
     * @param mixed $action
     * @return void
     */
    public static function put($uri, $action)
    {
        static::addRoute('PUT', $uri, $action);
    }

    /**
     * Register DELETE route
     *
     * @param string $uri
     * @param mixed $action
     * @return void
     */
    public static function delete($uri, $action)
    {
        static::addRoute('DELETE', $uri, $action);
    }

    /**
     * Register PATCH route
     *
     * @param string $uri
     * @param mixed $action
     * @return void
     */
    public static function patch($uri, $action)
    {
        static::addRoute('PATCH', $uri, $action);
    }

    /**
     * Create route group
     *
     * @param array $attributes
     * @param callable $callback
     * @return void
     */
    public static function group($attributes, $callback)
    {
        static::$groupStack[] = $attributes;

        call_user_func($callback);

        array_pop(static::$groupStack);
    }

    /**
     * Add route to collection
     *
     * @param string $method
     * @param string $uri
     * @param mixed $action
     * @return void
     */
    private static function addRoute($method, $uri, $action)
    {
        // Apply group attributes
        $attributes = static::mergeGroupAttributes();

        // Build full URI with prefix
        $fullUri = static::buildUri($uri, $attributes);

        // Store route
        static::$routes[] = [
            'method'     => $method,
            'uri'        => $fullUri,
            'action'     => $action,
            'middleware' => $attributes['middleware'] ?? []
        ];
    }

    /**
     * Merge group attributes
     *
     * @return array
     */
    private static function mergeGroupAttributes()
    {
        $attributes = [
            'prefix'     => '',
            'middleware' => []
        ];

        foreach (static::$groupStack as $group) {
            if (isset($group['prefix'])) {
                $attributes['prefix'] .= '/' . trim($group['prefix'], '/');
            }

            if (isset($group['middleware'])) {
                $middleware = is_array($group['middleware']) ? $group['middleware'] : [$group['middleware']];
                $attributes['middleware'] = array_merge($attributes['middleware'], $middleware);
            }
        }

        return $attributes;
    }

    /**
     * Build full URI
     *
     * @param string $uri
     * @param array $attributes
     * @return string
     */
    private static function buildUri($uri, $attributes)
    {
        $prefix = trim($attributes['prefix'], '/');
        $uri = trim($uri, '/');

        if ($prefix && $uri) {
            return $prefix . '/' . $uri;
        }

        return $prefix ?: $uri;
    }

    /**
     * Get all registered routes
     *
     * @return array
     */
    public static function getRoutes()
    {
        return static::$routes;
    }

    /**
     * Clear all routes (for testing)
     *
     * @return void
     */
    public static function clearRoutes()
    {
        static::$routes = [];
        static::$groupStack = [];
    }

    /**
     * Set application instance
     *
     * @param \ZenoChatbot\Framework\Foundation\Application $app
     * @return void
     */
    public static function setApp($app)
    {
        static::$app = $app;
    }

    /**
     * Convert route to WordPress REST API format
     *
     * @param array $route
     * @return array
     */
    public static function toWordPressRoute($route)
    {
        return [
            'methods'             => $route['method'],
            'callback'            => static::resolveCallback($route['action']),
            'permission_callback' => static::resolvePermissions($route['middleware']),
            'args'                => static::resolveArgs($route['uri'])
        ];
    }

    /**
     * Resolve callback from action
     *
     * @param mixed $action
     * @return callable
     */
    private static function resolveCallback($action)
    {
        $app = static::$app;
        return function ($request) use ($action, $app) {
            return $app->handleRestRequest($action, $request);
        };
    }

    /**
     * Resolve permissions from middleware
     *
     * @param array $middleware
     * @return callable
     */
    private static function resolvePermissions($middleware)
    {
        if (in_array('auth', $middleware)) {
            return function () {
                return current_user_can('manage_options');
            };
        }

        if (in_array('logged_in', $middleware)) {
            return function () {
                return is_user_logged_in();
            };
        }

        return '__return_true';
    }

    /**
     * Resolve route arguments from URI
     *
     * @param string $uri
     * @return array
     */
    private static function resolveArgs($uri)
    {
        $args = [];

        // Extract route parameters like {id}
        if (preg_match_all('/\{([^}]+)\}/', $uri, $matches)) {
            foreach ($matches[1] as $param) {
                $args[$param] = [
                    'required'          => true,
                    'validate_callback' => function ($param, $request, $key) {
                        return !empty($param);
                    }
                ];
            }
        }

        return $args;
    }

    /**
     * Resolve the REST namespace/version from the active app config.
     * Falls back to the historical free-plugin namespace for backward compatibility.
     *
     * @return string
     */
    private static function resolveRestNamespace()
    {
        $namespace = 'zeno-chatbot-ai';
        $version = 'v1';

        if (static::$app && method_exists(static::$app, 'config')) {
            try {
                $configuredNamespace = static::$app->config('app.rest.namespace', $namespace);
                $configuredVersion = static::$app->config('app.rest.version', $version);

                if (is_string($configuredNamespace) && trim($configuredNamespace, '/') !== '') {
                    $namespace = trim($configuredNamespace, '/');
                }

                if (is_string($configuredVersion) && trim($configuredVersion, '/') !== '') {
                    $version = trim($configuredVersion, '/');
                }
            } catch (\Throwable $e) {
                // Keep fallback namespace when app config is unavailable/misconfigured.
            }
        }

        return $namespace . '/' . $version;
    }

    public static function registerRestRoutes()
    {
        static::clearRoutes();
        $routeConfig = static::$app->getRouteConfig();
        $namespace = static::resolveRestNamespace();

        if (isset($routeConfig['api'])) {
            $routeFile = static::$app->basePath($routeConfig['api']);

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

        foreach (Route::getRoutes() as $route) {
            $wordpress_route = Route::toWordPressRoute($route);

            // Convert {id} parameters to WordPress REST API format
            $wordpress_uri = '/' . ltrim($route['uri'], '/');
            $wordpress_uri = preg_replace('/\{([^}]+)\}/', '(?P<$1>[^/]+)', $wordpress_uri);

            register_rest_route(
                $namespace,
                $wordpress_uri,
                $wordpress_route
            );
        }
    }
}
