<?php

declare(strict_types=1);

namespace FleekDash\Admin\Menu;

/**
 * Toolbar Capture Service
 *
 * Captures WordPress admin toolbar during real wp-admin requests
 * and persists per-user snapshots. REST endpoints prioritize snapshots over
 * partial rebuilds to ensure 100% reliability.
 *
 * Priority in REST context:
 * 1. user_meta snapshot (most reliable - captured from real wp-admin)
 * 2. Built from scratch (fallback)
 *
 * @package FleekDash\Admin\Menu
 */
class ToolbarCaptureService
{
    private const META_TOOLBAR_SNAPSHOT = '_fleekdash_admin_toolbar_snapshot_v1';
    private const META_TOOLBAR_SNAPSHOT_HASH = '_fleekdash_admin_toolbar_snapshot_hash_v1';
    private const META_TOOLBAR_SNAPSHOT_UPDATED_AT = '_fleekdash_admin_toolbar_snapshot_updated_at_v1';

    /**
     * Stored toolbar nodes (in-memory only, per request)
     *
     * @var array|null
     */
    private $storedToolbarNodes = null;

    /**
     * Where the currently stored toolbar came from.
     *
     * Values:
     * - globals: captured from WordPress admin bar in a real admin request
     * - user_meta_snapshot: loaded from persisted snapshot captured in wp-admin
     * - user_meta_snapshot_stale: loaded from snapshot marked stale (fallback after plugin/theme change)
     * - none: not captured yet
     *
     * @var string
     */
    private string $lastSource = 'none';

    /**
     * Capture the complete WordPress toolbar after all plugins have registered their items
     *
     * @param \WP_Admin_Bar|null $wp_admin_bar WordPress admin bar instance
     * @return void
     */
    public function captureAdminToolbar($wp_admin_bar = null)
    {
        // Use provided admin bar or get from global
        if ($wp_admin_bar === null) {
            global $wp_admin_bar;
        }

        // If admin bar is not initialized, try to get it
        if (!$wp_admin_bar || !($wp_admin_bar instanceof \WP_Admin_Bar)) {
            // Try to get from global
            if (isset($GLOBALS['wp_admin_bar']) && $GLOBALS['wp_admin_bar'] instanceof \WP_Admin_Bar) {
                $wp_admin_bar = $GLOBALS['wp_admin_bar'];
            } else {
                // Admin bar not available yet
                return;
            }
        }

        // Get all nodes from admin bar
        $nodes = $wp_admin_bar->get_nodes();

        if ($nodes !== null && is_array($nodes)) {
            // Convert nodes to array format for storage
            $nodes_array = [];
            foreach ($nodes as $node) {
                $nodes_array[$node->id] = [
                    'id' => $node->id,
                    'title' => $node->title,
                    'href' => $node->href ?? '',
                    'parent' => $node->parent ?? false,
                    'group' => $node->group ?? '',
                    'meta' => $node->meta ?? [],
                ];
            }

            $this->storedToolbarNodes = $nodes_array;
            $this->lastSource = 'globals';
        }
    }

    /**
     * Ensure toolbar is captured before use
     *
     * Priority logic:
     * - REST context: Try user_meta snapshot first, then build from scratch
     * - Admin context: Use WordPress admin bar directly (always fresh)
     *
     * No longer clears cache on every call - only clears when necessary
     * to prevent unnecessary reloads when accessing iframe.
     *
     * @return void
     */
    public function ensureToolbarCaptured()
    {
        if ($this->storedToolbarNodes !== null && !empty($this->storedToolbarNodes)) {
            return;
        }

        if (\defined('REST_REQUEST') && REST_REQUEST) {
            $this->ensureToolbarCapturedInRestContext();
            return;
        }
        $this->ensureToolbarCapturedInAdminContext();
    }

    private function ensureToolbarCapturedInRestContext(): void
    {
        $user_id = (int) \get_current_user_id();
        if ($user_id > 0 && ($this->loadSnapshotForUser($user_id) || $this->loadSnapshotForUser($user_id, true))) {
            return;
        }
        $this->storedToolbarNodes = [];
        $this->lastSource = 'no_snapshot_available';
    }

    private function ensureToolbarCapturedInAdminContext(): void
    {
        if ($this->tryCaptureFromAdminBar()) {
            return;
        }
        $user_id = (int) \get_current_user_id();
        if ($user_id > 0 && ($this->loadSnapshotForUser($user_id) || $this->loadSnapshotForUser($user_id, true))) {
            return;
        }
        $this->storedToolbarNodes = [];
        $this->lastSource = 'no_snapshot_available';
    }

    private function tryCaptureFromAdminBar(): bool
    {
        global $wp_admin_bar;
        if (!$wp_admin_bar instanceof \WP_Admin_Bar) {
            return false;
        }
        $nodes = $wp_admin_bar->get_nodes();
        if ($nodes === null || !\is_array($nodes)) {
            return false;
        }
        $nodes_array = [];
        foreach ($nodes as $node) {
            $nodes_array[$node->id] = [
                'id' => $node->id,
                'title' => $node->title,
                'href' => $node->href ?? '',
                'parent' => $node->parent ?? false,
                'group' => $node->group ?? '',
                'meta' => $node->meta ?? [],
            ];
        }
        $this->storedToolbarNodes = $nodes_array;
        $this->lastSource = 'globals';
        return true;
    }

    /**
     * Get stored toolbar nodes
     *
     * @return array|null
     */
    public function getStoredToolbarNodes()
    {
        return $this->storedToolbarNodes;
    }

    /**
     * Get last source
     *
     * @return string
     */
    public function getLastSource(): string
    {
        return $this->lastSource;
    }

    /**
     * Clear in-memory cache
     *
     * @return void
     */
    public function clearInMemoryCache(): void
    {
        $this->storedToolbarNodes = null;
        $this->lastSource = 'none';
    }

    /**
     * Persist current toolbar snapshot to user_meta
     *
     * @param int|null $user_id User ID (defaults to current user)
     * @return bool Success
     */
    public function persistSnapshotForCurrentUser(?int $user_id = null): bool
    {
        $userId = $user_id ?? (int) \get_current_user_id();
        $success = $userId > 0
            && $this->storedToolbarNodes !== null
            && !empty($this->storedToolbarNodes);

        if ($success) {
            $snapshotData = $this->storedToolbarNodes;
            $snapshotHash = \md5(\serialize($snapshotData));
            $existingHash = \get_user_meta($userId, self::META_TOOLBAR_SNAPSHOT_HASH, true);

            if ($existingHash !== $snapshotHash) {
                \update_user_meta($userId, self::META_TOOLBAR_SNAPSHOT, $snapshotData);
                \update_user_meta($userId, self::META_TOOLBAR_SNAPSHOT_HASH, $snapshotHash);
                \update_user_meta($userId, self::META_TOOLBAR_SNAPSHOT_UPDATED_AT, time());
            }
        }

        return $success;
    }

    /**
     * Load toolbar snapshot from user_meta
     *
     * @param int  $user_id     User ID
     * @param bool $allowStale  If true, load snapshot even when marked stale (updated_at = -1)
     * @return bool Success
     */
    public function loadSnapshotForUser(int $user_id, bool $allowStale = false): bool
    {
        $loaded = false;
        if ($user_id > 0) {
            $updatedAt = (int) \get_user_meta($user_id, self::META_TOOLBAR_SNAPSHOT_UPDATED_AT, true);
            $isStale = $updatedAt === -1;
            if ($isStale && !$allowStale) {
                $loaded = false;
            } else {
                $snapshot = \get_user_meta($user_id, self::META_TOOLBAR_SNAPSHOT, true);
                if (!empty($snapshot) && \is_array($snapshot)) {
                    $this->storedToolbarNodes = $snapshot;
                    $this->lastSource = $isStale ? 'user_meta_snapshot_stale' : 'user_meta_snapshot';
                    $loaded = true;
                }
            }
        }
        return $loaded;
    }

    /**
     * Soft-delete: mark toolbar snapshot as stale (preserves data for fallback).
     *
     * Aligned with MenuCaptureService so toolbar has fallback protection during plugin changes.
     */
    public function deleteSnapshotForUser(int $user_id): bool
    {
        if ($user_id <= 0) {
            return false;
        }

        \update_user_meta($user_id, self::META_TOOLBAR_SNAPSHOT_UPDATED_AT, -1); // -1 = stale
        return true;
    }

    /**
     * Hard delete snapshot for a specific user (use sparingly).
     */
    public function hardDeleteSnapshotForUser(int $user_id): bool
    {
        if ($user_id <= 0) {
            return false;
        }

        \delete_user_meta($user_id, self::META_TOOLBAR_SNAPSHOT);
        \delete_user_meta($user_id, self::META_TOOLBAR_SNAPSHOT_HASH);
        \delete_user_meta($user_id, self::META_TOOLBAR_SNAPSHOT_UPDATED_AT);
        return true;
    }

    /**
     * Soft-delete all toolbar snapshots by marking them as stale.
     *
     * Aligned with MenuCaptureService: preserves snapshot data for fallback in REST context
     * when plugins/themes change, instead of permanently deleting.
     *
     * @return int Number of rows updated
     */
    public static function deleteAllSnapshots(): int
    {
        global $wpdb;

        $result = $wpdb->query($wpdb->prepare(
            "UPDATE {$wpdb->usermeta} SET meta_value = %s WHERE meta_key = %s",
            '-1',
            self::META_TOOLBAR_SNAPSHOT_UPDATED_AT
        ));

        return $result !== false ? (int) $result : 0;
    }

    /**
     * Hard delete all toolbar snapshots (use sparingly).
     */
    public static function hardDeleteAllSnapshots(): void
    {
        \delete_metadata('user', 0, self::META_TOOLBAR_SNAPSHOT, '', true);
        \delete_metadata('user', 0, self::META_TOOLBAR_SNAPSHOT_HASH, '', true);
        \delete_metadata('user', 0, self::META_TOOLBAR_SNAPSHOT_UPDATED_AT, '', true);
    }
}
