<?php
/**
 * Plugin Helper
 *
 * Provides safe loading of WordPress plugin.php file to prevent
 * conflicts with other plugins that may be loaded multiple times.
 *
 * This helper prevents "Cannot redeclare function" errors
 * by ensuring plugin.php is only loaded once and at the right time.
 *
 * @package FleekDash\Core
 * @since 2.2.5
 */

namespace FleekDash\Core;

defined('ABSPATH') || exit;

class PluginHelper
{
    /**
     * Track if plugin.php has been loaded
     *
     * @var bool
     */
    private static bool $pluginPhpLoaded = false;

    /**
     * Track if we're in the process of loading plugin.php
     * Prevents infinite loops if plugin.php triggers hooks that call this again
     *
     * @var bool
     */
    private static bool $loadingPluginPhp = false;

    /**
     * Require wp-admin/includes/plugin.php and update loaded flags.
     */
    private static function requirePluginPhpFile(): bool
    {
        $pluginFile = ABSPATH . 'wp-admin/includes/plugin.php';
        if (!\file_exists($pluginFile)) {
            return false;
        }

        self::$loadingPluginPhp = true;
        $loaded = false;

        try {
            require_once $pluginFile;
            if (\function_exists('get_plugins')) {
                self::$pluginPhpLoaded = true;
                $loaded = true;
            }
        } catch (\Throwable $e) {
            if (\function_exists('fleekdash_log_error')) {
                \fleekdash_log_error('FleekDash PluginHelper: Error loading plugin.php - ' . $e->getMessage());
            } elseif (\defined('WP_DEBUG') && WP_DEBUG) {
                \error_log('FleekDash PluginHelper: Error loading plugin.php - ' . $e->getMessage());
            }
            $loaded = false;
        } finally {
            self::$loadingPluginPhp = false;
        }

        return $loaded;
    }

    /**
     * Safely load wp-admin/includes/plugin.php
     *
     * This method ensures plugin.php is only loaded once, preventing
     * "Cannot redeclare function" errors from other plugins.
     *
     * Only loads when:
     * 1. Function doesn't exist yet
     * 2. We're in admin context (or explicitly allowed)
     * 3. File exists
     * 4. Not already loaded
     * 5. Not currently loading (prevents loops)
     *
     * @param bool $forceAdminContext If true, only loads in admin context
     */
    public static function loadPluginFunctions(bool $forceAdminContext = true): bool
    {
        if (self::$loadingPluginPhp) {
            return false;
        }

        $success = false;
        if (self::$pluginPhpLoaded || \function_exists('get_plugins')) {
            self::$pluginPhpLoaded = true;
            $success = true;
        } elseif (!$forceAdminContext || \is_admin()) {
            $success = self::requirePluginPhpFile();
        }

        return $success;
    }

    /**
     * Ensure wp-admin/includes/plugin.php is loaded (REST, cron, CLI safe).
     *
     * {@see loadPluginFunctions()} with {@code $forceAdminContext === true} skips loading when
     * {@see is_admin()} is false, so REST callbacks must use this (or {@code loadPluginFunctions(false)}
     * plus {@code require_once}) before {@see get_plugins()}, {@see get_plugin_data()},
     * {@see activate_plugin()}, etc.
     */
    public static function ensurePluginApiLoaded(): void
    {
        if (\function_exists('get_plugins')) {
            return;
        }
        self::loadPluginFunctions(false);
        if (!\function_exists('get_plugins')) {
            $pluginFile = ABSPATH . 'wp-admin/includes/plugin.php';
            if (\file_exists($pluginFile)) {
                require_once $pluginFile;
            }
        }
    }

    /**
     * Check if plugin functions are available
     */
    public static function hasPluginFunctions(): bool
    {
        return \function_exists('get_plugins');
    }

    /**
     * Reset the loaded state (for testing purposes only)
     *
     * @internal
     */
    public static function reset(): void
    {
        self::$pluginPhpLoaded = false;
        self::$loadingPluginPhp = false;
    }
}
