<?php
/**
 * AJAX Route Handler
 *
 * @package Licenzo\Framework\Http
 */

namespace Licenzo\Framework\Http;

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

/**
 * AJAX Route Handler Class
 */
class Ajax {

    /**
     * Application instance
     *
     * @var \Licenzo\Framework\Foundation\Application
     */
    private static $app;

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

    /**
     * Current route being registered
     *
     * @var array
     */
    private static $currentRoute;

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

    /**
     * Register an AJAX route
     *
     * @param string $action
     * @param string|callable $callback
     * @return static::
     */
    public static function register($action, $callback) {

        static::$currentRoute = [
            'action' => $action,
            'callback' => $callback,
            'secure' => false,
            'public' => true
        ];

        return new static();
    }

    /**
     * Make the route secure (logged-in users only)
     *
     * @return static::
     */
    public function secure() {

        if (static::$currentRoute) {
            static::$currentRoute['secure'] = true;
            static::$currentRoute['public'] = false;
        }

        static::registerRoute();
        return $this;
    }

    /**
     * Make the route public (both logged-in and non-logged-in users)
     *
     * @return static
     */
    public function public() {

        if (static::$currentRoute) {
            static::$currentRoute['secure'] = false;
            static::$currentRoute['public'] = true;
        }

        static::registerRoute();
        return $this;
    }

    /**
     * Register the current route with WordPress
     */
    private static function registerRoute() {

        if (!static::$currentRoute) {
            return;
        }

        $route = static::$currentRoute;
        $action = $route['action'];
        $callback = $route['callback'];

        // Create the WordPress callback that captures the application instance
        $app = static::$app;
        $wpCallback = function() use ($callback, $app, $action) {
            // Set request type for proper response handling
            $app->setRequestType('ajax');
            static::handleAjaxRequestThroughPipeline($action, $callback, $app);
        };

        // Register with WordPress AJAX hooks
        if ($route['secure']) {
            // Only for logged-in users
            add_action("wp_ajax_{$action}", $wpCallback);
        } else {
            // For both logged-in and non-logged-in users
            add_action("wp_ajax_{$action}", $wpCallback);
            add_action("wp_ajax_nopriv_{$action}", $wpCallback);
        }

        // Store the route
        static::$routes[$action] = $route;

        // Clear the current route
        static::$currentRoute = null;
    }

    /**
     * Handle AJAX request through unified pipeline
     *
     * @param string $action
     * @param string|callable $callback
     * @param \Licenzo\Framework\Foundation\Application $app
     */
    private static function handleAjaxRequestThroughPipeline($action, $callback, $app) {
        try {
            static::handleAjaxRequest($callback, $app);

        } catch (\Throwable $e) {
            // Fallback to legacy handling
            static::handleAjaxRequest($callback, $app);
        }
    }

    /**
     * Handle AJAX request (legacy method for backward compatibility)
     *
     * @param string|callable $callback
     * @param \Licenzo\Framework\Foundation\Application $app
     */
    private static function handleAjaxRequest($callback, $app) {
        try {

            if (is_string($callback) && strpos($callback, '@') !== false) {
                // Handle Controller@method format
                list($controller, $method) = explode('@', $callback);

                // Resolve controller through application container
                $controllerInstance = $app->make($controller);

                if (!method_exists($controllerInstance, $method)) {
                    wp_die("Method {$method} not found in {$controller}", 'Method Not Found', ['response' => 404]);
                }

                // Call the method
                call_user_func([$controllerInstance, $method]);

            } elseif (is_callable($callback)) {
                // Handle direct callable - pass app instance
                call_user_func($callback, $app);

            } else {
                wp_die('Invalid callback format', 'Invalid Callback', ['response' => 500]);
            }

        } catch (\Throwable $e) {
            // Handle exceptions for AJAX requests
            $status = 500;
            $message = 'Internal server error';

            // Check for specific exception types
            if ($e instanceof \Licenzo\Framework\Exceptions\HttpException) {
                $status = $e->getCode() ?: 500;
                $message = $e->getMessage();
            } elseif ($e instanceof \Licenzo\Exception\ConfigurationException) {
                $status = 400;
                $message = $e->getMessage();
            } elseif ($e instanceof \Licenzo\Exception\ValidationException) {
                $status = 422;
                $message = $e->getMessage();
            }

            // Send JSON error response
            wp_send_json_error([
                'message' => $message,
                'error' => WP_DEBUG ? $e->getMessage() : 'An error occurred',
                'trace' => WP_DEBUG ? $e->getTraceAsString() : null
            ], $status);
        }
    }

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

    /**
     * Clear all routes
     */
    public static function clearRoutes() {
        static::$routes = [];
        static::$currentRoute = null;
    }

    /**
     * Check if the route exists
     *
     * @param string $action
     * @return bool
     */
    public static function hasRoute($action) {
        return isset(static::$routes[$action]);
    }

    /**
     * Get route by action
     *
     * @param string $action
     * @return array|null
     */
    public static function getRoute($action) {
        return static::$routes[$action] ?? null;
    }
}
