<?php
/**
 * Toolbar Data API
 *
 * REST API endpoints for WordPress Admin Bar / Toolbar data
 * Provides hierarchical toolbar structure with standardized fields
 *
 * @package FleekDash\API
 * @since V2.2
 */

namespace FleekDash\API;

use WP_REST_Request;
use WP_REST_Response;
use WP_Error;
use FleekDash\Admin\Menu\RouteConverter;
use FleekDash\Admin\Menu\ToolbarCaptureService;
use FleekDash\Core\AuthMiddleware;

/**
 * Toolbar Data API
 *
 * Handles WordPress Admin Bar data retrieval and formatting
 * Uses WP_Admin_Bar class and admin_bar_menu hooks
 *
 * V2.2: Now uses RouteConverter for consistent URL formatting with MenuDataAPI
 *
 * @package FleekDash\API
 * @since V2.2
 */
class ToolbarDataAPI
{
    private const API_NAMESPACE = 'fleekdash/v1';
    private const MSG_NOT_AUTHENTICATED = 'Not authenticated';

    /**
     * @var RouteConverter
     */
    private $routeConverter;

    /**
     * @var ToolbarCaptureService
     */
    private $toolbarCapture;

    /**
     * @var ToolbarHierarchyFormatter
     */
    private $toolbarFormatter;

    /**
     * Constructor
     */
    public function __construct()
    {
        $this->routeConverter = new RouteConverter();
        $this->toolbarCapture = new ToolbarCaptureService();
        $this->toolbarFormatter = new ToolbarHierarchyFormatter($this->routeConverter);
    }

    /**
     * Register REST API routes
     */
    public function registerRoutes(): void
    {
        \register_rest_route(self::API_NAMESPACE, '/toolbar', [
            'methods' => 'GET',
            'callback' => [$this, 'getToolbar'],
            'permission_callback' => [AuthMiddleware::class, 'createAuthenticatedPermissionCallback'],
        ]);

        // Get toolbar for current logged-in user (recommended for FleekDash app)
        // Uses unified permission callback pattern (always true) and graceful fallback inside handler.
        \register_rest_route(self::API_NAMESPACE, '/toolbar/me', [
            'methods' => 'GET',
            'callback' => [$this, 'getToolbarForCurrentUser'],
            'permission_callback' => [AuthMiddleware::class, 'createAuthenticatedPermissionCallback'],
        ]);

        // Get toolbar data by role - Public access for role simulation
        \register_rest_route(self::API_NAMESPACE, '/toolbar/(?P<role>[a-zA-Z0-9_-]+)', [
            'methods' => 'GET',
            'callback' => [$this, 'getToolbarByRole'],
            'permission_callback' => [AuthMiddleware::class, 'createAuthenticatedPermissionCallback'],
            'args' => [
                'role' => [
                    'required' => true,
                    'type' => 'string',
                    'description' => 'WordPress role slug',
                    'sanitize_callback' => 'sanitize_text_field'
                ]
            ]
        ]);

        // Refresh toolbar - Authenticated only
        \register_rest_route(self::API_NAMESPACE, '/toolbar/refresh', [
            'methods' => 'POST',
            'callback' => [$this, 'refreshToolbar'],
            'permission_callback' => [AuthMiddleware::class, 'createAuthenticatedPermissionCallback'],
        ]);

        // Invalidate toolbar snapshots - Authenticated only
        \register_rest_route(self::API_NAMESPACE, '/toolbar/invalidate-snapshots', [
            'methods' => 'POST',
            'callback' => [$this, 'invalidateAllSnapshots'],
            'permission_callback' => [AuthMiddleware::class, 'createAuthenticatedPermissionCallback'],
        ]);
    }

    /**
     * Permission callback (unified pattern)
     *
     * Always return true and let AuthMiddleware handle authentication inside handlers.
     *
     * @return bool
     */
    public function checkPermissions(): bool
    {
        return true;
    }

    /**
     * Check authenticated permissions using AuthMiddleware
     *
     * Security (v2.2): Toolbar requires authentication for refresh
     */
    public function checkAuthenticatedPermissions(): bool
    {
        try {
            if (!class_exists('FleekDash\\Core\\AuthMiddleware')) {
                require_once dirname(__DIR__, 1) . '/Core/AuthMiddleware.php';
            }

            $auth = \FleekDash\Core\AuthMiddleware::check('authenticated');

            if (!$auth['authenticated']) {
                if (defined('WP_DEBUG') && WP_DEBUG && defined('WP_DEBUG_LOG') && WP_DEBUG_LOG) {
                    error_log(sprintf(
                        'FleekDash Security: Unauthorized toolbar access - IP: %s, Reason: %s',
                        $_SERVER['REMOTE_ADDR'] ?? 'unknown',
                        $auth['reason'] ?? 'unknown'
                    ));
                }
                return false;
            }

            return true;
        } catch (\Exception $e) {
            error_log('FleekDash Security: Auth check failed - ' . $e->getMessage());
            return false;
        }
    }

    /**
     * Get toolbar data
     *
     * Prioritizes user_meta snapshots captured during real wp-admin requests
     * for 100% reliability. Falls back to building from scratch if no snapshot exists.
     *
     */
    public function getToolbar(WP_REST_Request $request)
    {
        $request->get_method(); // Use param - required by WordPress REST callback
        $this->toolbarCapture->ensureToolbarCaptured();
        $nodes_array = $this->toolbarCapture->getStoredToolbarNodes();

        if ($nodes_array === null || empty($nodes_array)) {
            // No toolbar available - return empty
            return new WP_REST_Response([
                'items' => [],
                'updateCount' => 0,
                'commentCount' => 0,
                'timestamp' => time(),
                'source' => 'ToolbarDataAPI',
                'debug' => [
                    'total_nodes' => 0,
                    'formatted_items' => 0,
                    'last_source' => $this->toolbarCapture->getLastSource()
                ]
            ], 200);
        }

        // Convert array format back to WP_Admin_Bar node format for compatibility
        $nodes = [];
        foreach ($nodes_array as $node_data) {
            $node = new \stdClass();
            $node->id = $node_data['id'];
            $node->title = $node_data['title'];
            $node->href = $node_data['href'] ?? '';
            $node->parent = $node_data['parent'] ?? false;
            $node->group = $node_data['group'] ?? '';
            $node->meta = $node_data['meta'] ?? [];
            $nodes[$node->id] = $node;
        }

        // Format toolbar items with hierarchy
        $toolbar_items = $this->toolbarFormatter->format($nodes);

        // Get stats for backward compatibility
        $update_count = 0;
        $updates = wp_get_update_data();
        if (isset($updates['counts'])) {
            $update_count = $updates['counts']['total'];
        }

        $comment_count = 0;
        $comment_count_obj = wp_count_comments();
        if ($comment_count_obj) {
            $comment_count = $comment_count_obj->moderated;
        }

        return new WP_REST_Response([
            'items' => $toolbar_items,
            'updateCount' => $update_count,
            'commentCount' => $comment_count,
            'timestamp' => time(),
            'source' => 'ToolbarDataAPI',
            'debug' => [
                'total_nodes' => count($nodes),
                'formatted_items' => count($toolbar_items),
                'last_source' => $this->toolbarCapture->getLastSource()
            ]
        ], 200);
    }

    /**
     * Get toolbar for the current logged-in user (FleekDash app)
     *
     * This avoids role-based simulation and ensures the toolbar matches the real user session.
     * Implements graceful fallback (never throws 403 WP_Error).
     */
    public function getToolbarForCurrentUser(WP_REST_Request $request)
    {
        $request->get_method(); // Use param to satisfy Sonar - required by WordPress REST callback
        $unauthResponse = [
            'success' => false,
            'message' => self::MSG_NOT_AUTHENTICATED,
            'items' => [],
            'updateCount' => 0,
            'commentCount' => 0,
            'timestamp' => time(),
            'source' => 'ToolbarDataAPI',
        ];

        try {
            $auth = AuthMiddleware::check('authenticated');
            $canProceed = !empty($auth['authenticated']) || \is_user_logged_in();
        } catch (\Throwable $e) {
            $canProceed = \is_user_logged_in();
            $unauthResponse = array_merge($unauthResponse, ['message' => 'Authentication error']);
        }

        $userId = (int) \get_current_user_id();
        if (!$canProceed || $userId <= 0) {
            return \rest_ensure_response($unauthResponse);
        }
        return $this->generateToolbarForUser($userId, null);
    }

    /**
     * Get toolbar data by role
     *
     * @param WP_REST_Request $request Request with 'role' parameter
     * @return WP_REST_Response|WP_Error
     */
    public function getToolbarByRole(WP_REST_Request $request)
    {
        $role = $request->get_param('role');

        // Validate role exists
        if (!AdminDataFormatter::isValidRole($role)) {
            return AdminDataFormatter::buildInvalidRoleError($role, AdminDataFormatter::getAvailableRoles());
        }

        // Get first user with this role
        $user = AdminDataFormatter::getUserByRole($role);

        if (!$user) {
            return AdminDataFormatter::buildNoUsersError($role);
        }

        // Generate toolbar for this role
        return $this->generateToolbarForUser($user->ID, $role);
    }

    /**
     * Generate toolbar for specific user
     *
     * @param int $user_id User ID
     * @param string|null $role_name Optional role name for response
     * @return WP_REST_Response
     */
    private function generateToolbarForUser($user_id, $role_name = null)
    {
        global $wp_admin_bar, $hook_suffix, $pagenow, $current_screen;

        $original_user_id = \get_current_user_id();
        \wp_set_current_user($user_id);
        $target_user = \wp_get_current_user();

        $this->loadToolbarDependencies();
        $wp_admin_bar = new \WP_Admin_Bar();
        if (!\defined('WP_ADMIN')) {
            define('WP_ADMIN', true);
        }

        $previousScreen = $this->ensureScreenForToolbar($hook_suffix, $pagenow, $current_screen);
        $wp_admin_bar->initialize();

        // CRITICAL: Add WordPress native menu hooks
        $wp_admin_bar->add_menus();

        // Trigger admin_bar_menu hooks
        // current_screen must be set before this hook fires
        // WordPress core admin-bar.php accesses $current_screen->base in hook callbacks
        \do_action('admin_bar_menu', array(&$wp_admin_bar));

        // Get nodes
        $nodes = $wp_admin_bar->get_nodes();

        // Format toolbar
        $toolbar_items = $this->toolbarFormatter->format($nodes);

        // Get stats
        $update_count = 0;
        $updates = wp_get_update_data();
        if (isset($updates['counts'])) {
            $update_count = $updates['counts']['total'];
        }

        $comment_count = 0;
        $comment_count_obj = wp_count_comments();
        if ($comment_count_obj) {
            $comment_count = $comment_count_obj->moderated;
        }

        // Restore original user (always; 0 = unauthenticated, must still restore)
        \wp_set_current_user($original_user_id);

        $this->restoreScreenGlobals($previousScreen, $hook_suffix, $pagenow, $current_screen);

        return new WP_REST_Response([
            'items' => $toolbar_items,
            'updateCount' => $update_count,
            'commentCount' => $comment_count,
            'timestamp' => time(),
            'source' => 'ToolbarDataAPI',
            'role' => $role_name,
            'user_id' => $user_id,
            'capabilities' => array_keys($target_user->allcaps),
            'debug' => [
                'total_nodes' => $nodes !== null ? count($nodes) : 0,
                'formatted_items' => count($toolbar_items)
            ]
        ], 200);
    }

    /**
     * Refresh toolbar (clear cache and return fresh data)
     *
     * Validates authentication using AuthMiddleware since permission_callback bypasses nonce validation
     */
    public function refreshToolbar(WP_REST_Request $request)
    {
        $auth = AuthMiddleware::check('authenticated');
        if (empty($auth['authenticated'])) {
            return new WP_REST_Response([
                'success' => false,
                'message' => self::MSG_NOT_AUTHENTICATED,
                'fallback_data' => ['refreshed' => false],
            ], 200);
        }

        \delete_transient('fleekdash_toolbar_cache');
        if (\class_exists('\FleekDash\Admin\Menu\ToolbarCaptureService')) {
            \FleekDash\Admin\Menu\ToolbarCaptureService::deleteAllSnapshots();
            $this->toolbarCapture->clearInMemoryCache();
        }

        return $this->getToolbar($request);
    }

    /**
     * Invalidate all toolbar snapshots
     *
     * Used when plugins/themes change to force fresh snapshots
     *
     * Validates authentication using AuthMiddleware since permission_callback bypasses nonce validation
     */
    public function invalidateAllSnapshots(WP_REST_Request $request)
    {
        $request->get_method(); // Use param - required by WordPress REST callback
        $auth = AuthMiddleware::check('authenticated');
        if (empty($auth['authenticated'])) {
            return new WP_REST_Response([
                'success' => false,
                'message' => self::MSG_NOT_AUTHENTICATED,
                'fallback_data' => ['invalidated' => false],
            ], 200);
        }

        $deleted = 0;
        if (\class_exists('\FleekDash\Admin\Menu\ToolbarCaptureService')) {
            $deleted = \FleekDash\Admin\Menu\ToolbarCaptureService::deleteAllSnapshots();
            $this->toolbarCapture->clearInMemoryCache();
        }

        return new WP_REST_Response([
            'success' => true,
            'deleted_snapshots' => $deleted,
            'message' => 'Toolbar snapshots invalidated successfully'
        ], 200);
    }

    private function loadToolbarDependencies(): void
    {
        if (!\class_exists('WP_Admin_Bar')) {
            require_once ABSPATH . WPINC . '/class-wp-admin-bar.php';
        }
        if (!\function_exists('get_current_screen')) {
            require_once ABSPATH . 'wp-admin/includes/screen.php';
        }
        if (!\function_exists('get_plugin_updates')) {
            require_once ABSPATH . 'wp-admin/includes/update.php';
        }
    }

    /**
     * Ensure current_screen is set before toolbar processing (WordPress admin-bar.php requires it)
     *
     * @return array{hook_suffix: string|null, pagenow: string|null, screen: \WP_Screen|object|null}
     */
    private function ensureScreenForToolbar(?string &$hook_suffix, ?string &$pagenow, mixed &$current_screen): array
    {
        $previous = ['hook_suffix' => $hook_suffix ?? null, 'pagenow' => $pagenow ?? null, 'screen' => $current_screen ?? null];

        try {
            $hook_suffix = 'index.php';
            $pagenow = 'index.php';
            if (!\class_exists('WP_Screen')) {
                require_once ABSPATH . 'wp-admin/includes/class-wp-screen.php';
            }
            if (\function_exists('set_current_screen')) {
                \set_current_screen('dashboard');
            }
            $current_screen = $this->tryGetWpScreenInstance($current_screen);
        } catch (\Throwable $e) {
            $current_screen = $this->tryGetWpScreenInstance($current_screen ?? null);
            if (\defined('WP_DEBUG') && WP_DEBUG) {
                \error_log('[FleekDash ToolbarDataAPI] Screen emulation warning: ' . $e->getMessage());
            }
        }
        return $previous;
    }

    private function tryGetWpScreenInstance(mixed $currentScreen): object
    {
        if ($currentScreen instanceof \WP_Screen) {
            return $currentScreen;
        }
        if (\class_exists('WP_Screen')) {
            try {
                $screen = \WP_Screen::get('dashboard');
                if ($screen instanceof \WP_Screen) {
                    return $screen;
                }
            } catch (\Throwable $e) {
                // Fall through to wrapper
            }
        }
        return $this->createDashboardScreenWrapper();
    }

    private function restoreScreenGlobals(array $previous, ?string &$hookSuffix, ?string &$pagenow, mixed &$currentScreen): void
    {
        $hookSuffix = $previous['hook_suffix'];
        $pagenow = $previous['pagenow'];
        $currentScreen = $previous['screen'];
    }

    /**
     * Create a dashboard screen wrapper for REST context (WordPress core expects WP_Screen)
     *
     * @return object Wrapper with in_admin, is_network, is_user methods
     */
    private function createDashboardScreenWrapper(): object
    {
        $screen = new class extends \stdClass {
            public function in_admin(): bool
            {
                return true;
            }
            public function is_network(): bool
            {
                return false;
            }
            public function is_user(): bool
            {
                return $this->is_network();
            }
        };
        $screen->id = 'dashboard';
        $screen->base = 'dashboard';
        $screen->action = '';
        $screen->post_type = '';
        $screen->taxonomy = '';
        return $screen;
    }

}
