<?php
/**
 * Classic Mode Handler
 *
 * Manages WordPress classic admin mode toggling and persistence.
 * Handles URL parameters, cookies, and localStorage sync for seamless
 * switching between FleekDash and classic WordPress admin.
 *
 * @package FleekDash V2
 * @since 2.2.0
 */

namespace FleekDash\Core;

defined('ABSPATH') || exit;

// Load debug helpers
if (!function_exists('fleekdash_log_debug')) {
    require_once FLEEKDASH_PLUGIN_DIR . 'includes/Core/debug-helpers.php';
}

class ClassicModeHandler
{
    /**
     * FleekDash plugin file reference used for emergency disable handling.
     */
    private const PLUGIN_FILE = 'fleekdash/fleekdash.php';

    /** Cookie path scoped to wp-admin (literal centralized for Sonar S1192). */
    private const ADMIN_COOKIE_PATH = '/wp-admin/';

    private const COOKIE_CLASSIC_ADMIN = 'fleekdash_classic_admin';

    /**
     * Prevent handling the emergency disable flow more than once per request.
     */
    private static bool $emergencyDisableHandled = false;

    /**
     * Whether the request is the emergency-disable query (?fleekdash=disable).
     */
    private static function isEmergencyDisableQuery(): bool
    {
        return isset($_GET['fleekdash']) && $_GET['fleekdash'] === 'disable';
    }

    /**
     * Contexts where FleekDash must stay active (SPA, iframe, referer from app).
     */
    private static function isFleekdashUiProtectedRequest(): bool
    {
        $referer = isset($_SERVER['HTTP_REFERER']) ? (string) $_SERVER['HTTP_REFERER'] : '';
        $fetchDest = isset($_SERVER['HTTP_SEC_FETCH_DEST']) ? (string) $_SERVER['HTTP_SEC_FETCH_DEST'] : '';

        return (\is_admin() && isset($_GET['page']) && $_GET['page'] === 'fleekdash')
            || (isset($_GET['fleekdash-frame']) && $_GET['fleekdash-frame'] === '1')
            || ($fetchDest !== '' && $fetchDest === 'iframe')
            || ($referer !== '' && \strpos($referer, 'page=fleekdash') !== false)
            || (isset($_GET['parent_is_fleekdash']) && $_GET['parent_is_fleekdash'] === '1');
    }

    private static function queryHasClassicEnableIntent(): bool
    {
        $pairs = array(
            'fleekdash' => 'on',
            'fleek-enable' => '1',
            'classic-wp' => '0',
        );
        foreach ($pairs as $param => $value) {
            if (isset($_GET[$param]) && $_GET[$param] === $value) {
                return true;
            }
        }

        return false;
    }

    private static function queryHasClassicDisableIntent(): bool
    {
        $pairs = array(
            'fleekdash' => 'off',
            'fleek-disable' => '1',
            'classic-wp' => '1',
        );
        foreach ($pairs as $param => $value) {
            if (isset($_GET[$param]) && $_GET[$param] === $value) {
                return true;
            }
        }

        return false;
    }

    private static function hasClassicPersistenceSignals(): bool
    {
        $classicAdmin = isset($_COOKIE[self::COOKIE_CLASSIC_ADMIN]) && $_COOKIE[self::COOKIE_CLASSIC_ADMIN] === '1';
        $tabId = isset($_GET['tab_id']) ? \sanitize_text_field(\wp_unslash($_GET['tab_id'])) : '';
        $tabFromUrl = $tabId !== '';

        return $classicAdmin
            || $tabFromUrl
            || (isset($_GET['fleekdash_classic_mode']) && $_GET['fleekdash_classic_mode'] === '1')
            || (isset($_POST['fleekdash_classic_mode']) && $_POST['fleekdash_classic_mode'] === '1');
    }

    private static function evalClassicModeFromParamsAndCookies(): bool
    {
        $disabled = false;
        if (self::queryHasClassicEnableIntent()) {
            $disabled = false;
        } elseif (self::queryHasClassicDisableIntent()) {
            $disabled = true;
        } else {
            $disabled = self::hasClassicPersistenceSignals();
        }

        return $disabled;
    }

    /**
     * Check if plugin should be temporarily disabled
     * Uses both URL parameters and a special localStorage-sync mechanism
     *
     * @return bool True if classic mode is active, false otherwise
     */
    public static function isTemporarilyDisabled(): bool
    {
        $disabled = false;
        if (self::isEmergencyDisableQuery()) {
            $disabled = true;
        } elseif (self::isFleekdashUiProtectedRequest()) {
            $disabled = false;
        } else {
            $disabled = self::evalClassicModeFromParamsAndCookies();
        }

        return $disabled;
    }

    private static function cookieSecureFlag(): bool
    {
        return \function_exists('is_ssl') && \is_ssl();
    }

    /**
     * @return array{turn_off: bool, turn_on: bool}|null
     */
    private static function resolveClassicToggleIntent(): ?array
    {
        $turnOff = (isset($_GET['fleekdash']) && \in_array($_GET['fleekdash'], array('off', 'disable'), true))
            || (isset($_GET['fleek-disable']) && $_GET['fleek-disable'] === '1')
            || (isset($_GET['classic-wp']) && $_GET['classic-wp'] === '1');
        $turnOn = (isset($_GET['fleekdash']) && $_GET['fleekdash'] === 'on')
            || (isset($_GET['fleek-enable']) && $_GET['fleek-enable'] === '1')
            || (isset($_GET['classic-wp']) && $_GET['classic-wp'] === '0');

        if (!$turnOff && !$turnOn) {
            return null;
        }

        return array('turn_off' => $turnOff, 'turn_on' => $turnOn);
    }

    /**
     * @param array{turn_off: bool, turn_on: bool} $intent
     */
    private static function syncClassicCookieAndRedirect(array $intent): void
    {
        $cookieName = self::COOKIE_CLASSIC_ADMIN;
        $cookieExists = isset($_COOKIE[$cookieName]) && $_COOKIE[$cookieName] === '1';
        $turnOff = $intent['turn_off'];
        $turnOn = $intent['turn_on'];

        if (($turnOff && $cookieExists) || ($turnOn && !$cookieExists)) {
            return;
        }

        $secure = self::cookieSecureFlag();
        if ($turnOff) {
            if (PHP_VERSION_ID >= 70300) {
                \setcookie($cookieName, '1', array(
                    'path' => self::ADMIN_COOKIE_PATH,
                    'httponly' => false,
                    'samesite' => 'Lax',
                    'secure' => $secure,
                ));
            } else {
                \setcookie($cookieName, '1', 0, self::ADMIN_COOKIE_PATH, '', $secure, false);
            }
        } elseif (PHP_VERSION_ID >= 70300) {
            \setcookie($cookieName, '0', array(
                'expires' => \time() - 3600,
                'path' => self::ADMIN_COOKIE_PATH,
                'httponly' => false,
                'samesite' => 'Lax',
                'secure' => $secure,
            ));
        } else {
            \setcookie($cookieName, '0', \time() - 3600, self::ADMIN_COOKIE_PATH, '', $secure, false);
        }

        $cleanParams = array('fleek-disable', 'fleek-enable', 'classic-wp', 'fleekdash_classic_mode', 'tab_id');
        $redirectUrl = \remove_query_arg($cleanParams);
        if ($redirectUrl === '' || $redirectUrl === null) {
            $redirectUrl = \admin_url();
        }
        if ($turnOff) {
            $redirectUrl = \add_query_arg('fleekdash', 'off', $redirectUrl);
        }

        \wp_safe_redirect($redirectUrl);
        exit;
    }

    /**
     * Handle classic mode toggling via URL and persist using a session cookie.
     * Runs very early to ensure subsequent logic respects the mode.
     */
    public static function handleToggle(): void
    {
        self::maybeHandleEmergencyDisable();
        $intent = self::resolveClassicToggleIntent();
        if ($intent === null) {
            return;
        }
        self::syncClassicCookieAndRedirect($intent);
    }

    private static function isEmergencyDisableAdminRequest(): bool
    {
        return (\is_admin() || \is_network_admin())
            && isset($_GET['fleekdash'])
            && $_GET['fleekdash'] === 'disable';
    }

    private static function deactivatePluginForEmergency(string $pluginFile, bool $isNetworkActive): void
    {
        $siteActive = \function_exists('is_plugin_active') && \is_plugin_active($pluginFile);
        if (!$siteActive && !$isNetworkActive) {
            return;
        }
        try {
            \deactivate_plugins($pluginFile, false, $isNetworkActive);
        } catch (\Throwable $exception) {
            fleekdash_log_debug('FleekDash: Failed to deactivate during emergency disable - ' . $exception->getMessage());
        }
    }

    private static function invalidateCachesAfterEmergencyDisable(): void
    {
        if (\function_exists('wp_clean_plugins_cache')) {
            \wp_clean_plugins_cache(true);
        } else {
            \delete_transient('plugin_slugs');
            \delete_transient('update_plugins');
        }
        \wp_cache_flush();
        \do_action('fleekdash_plugins_cache_invalidated');
    }

    private static function runEmergencyDisableFlow(): void
    {
        if (!\current_user_can('activate_plugins')) {
            fleekdash_log_debug('FleekDash: Emergency disable requested but user lacks activate_plugins capability.');

            return;
        }

        if (!\function_exists('deactivate_plugins')) {
            PluginHelper::ensurePluginApiLoaded();
        }

        $pluginFile = self::PLUGIN_FILE;
        $isNetworkAdmin = \is_network_admin();
        $isNetworkActive = \is_multisite()
            && \function_exists('is_plugin_active_for_network')
            && \is_plugin_active_for_network($pluginFile);

        if ($isNetworkActive && !$isNetworkAdmin) {
            $redirect = \network_admin_url('plugins.php?fleekdash=disable');
            fleekdash_log_debug('FleekDash: Redirecting emergency disable to network admin.');
            \wp_safe_redirect($redirect);
            exit;
        }

        if ($isNetworkAdmin && !\current_user_can('manage_network_plugins')) {
            fleekdash_log_debug('FleekDash: Emergency disable requested in network admin but user lacks manage_network_plugins capability.');

            return;
        }

        self::deactivatePluginForEmergency($pluginFile, $isNetworkActive);
        self::invalidateCachesAfterEmergencyDisable();
        fleekdash_log_debug('FleekDash: Plugin deactivated via emergency disable parameter.');
        \wp_safe_redirect(self::buildDisableRedirectUrl($isNetworkAdmin || $isNetworkActive));
        exit;
    }

    /**
     * Handle emergency disable command (?fleekdash=disable) to completely deactivate the plugin.
     */
    private static function maybeHandleEmergencyDisable(): void
    {
        $skip = self::$emergencyDisableHandled
            || (\defined('WP_CLI') && \WP_CLI)
            || !self::isEmergencyDisableAdminRequest();
        if ($skip) {
            return;
        }

        self::$emergencyDisableHandled = true;
        self::runEmergencyDisableFlow();
    }

    /**
     * Build the redirect URL after the plugin has been disabled.
     *
     * @param bool $networkContext Whether we should redirect to the network admin plugins page.
     */
    private static function buildDisableRedirectUrl(bool $networkContext = false): string
    {
        $baseUrl = $networkContext
            ? \network_admin_url('plugins.php')
            : \admin_url('plugins.php');

        $paramsToRemove = array(
            'fleekdash',
            'fleekdash-frame',
            'parent_is_fleekdash',
            'tab_id',
            'fleekdash_classic_mode',
            'fleekdash_auto',
        );

        $cleanBase = \remove_query_arg($paramsToRemove, $baseUrl);

        return \add_query_arg(
            array(
                'deactivate' => 'true',
                'plugin_status' => 'all',
                'paged' => '1',
                's' => '',
                'fleekdash' => 'disabled',
            ),
            $cleanBase
        );
    }

    /**
     * Clear the classic admin cookie
     * Reusable function for clearing the fleekdash_classic_admin cookie
     */
    public static function clearCookie(): void
    {
        $cookieName = self::COOKIE_CLASSIC_ADMIN;
        $secure = self::cookieSecureFlag();
        if (PHP_VERSION_ID >= 70300) {
            \setcookie($cookieName, '0', array(
                'expires' => \time() - 3600,
                'path' => self::ADMIN_COOKIE_PATH,
                'httponly' => false,
                'samesite' => 'Lax',
                'secure' => $secure,
            ));
        } else {
            \setcookie($cookieName, '0', \time() - 3600, self::ADMIN_COOKIE_PATH, '', $secure, false);
        }

        if (isset($_COOKIE[$cookieName])) {
            unset($_COOKIE[$cookieName]);
        }

        fleekdash_log_debug('FleekDash: Classic admin cookie cleared');
    }
}
