<?php

namespace WPSN\Core;

defined('ABSPATH') || exit;

/**
 * Admin Footprint Guard
 *
 * Goal: when "Minimize admin footprint" is enabled, ensure we do not accidentally
 * enqueue WP SEO Next assets on unrelated wp-admin screens.
 *
 * This is a defensive layer: modules should already gate their enqueues by $hook.
 * If a regression happens, this guard prevents wp-admin from being slowed down.
 */
final class AdminFootprintGuard
{
    private static bool $initialized = false;

    private static ?Settings $settings = null;

    /** @var string[] */
    private static array $removedScripts = [];

    /** @var string[] */
    private static array $removedStyles = [];

    /** @var string[] */
    private static array $scriptsEnqueued = [];

    /** @var string[] */
    private static array $stylesEnqueued = [];

    private static string $lastHook = '';
    private static string $lastScreenBase = '';

    public static function init(Settings $settings): void
    {
        if (self::$initialized) {
            return;
        }
        self::$initialized = true;
        self::$settings = $settings;

        if (!is_admin()) {
            return;
        }

        // Run late so we can remove anything enqueued earlier.
        add_action('admin_enqueue_scripts', [self::class, 'guard'], 9999);
    }

    public static function guard(string $hook): void
    {
        self::$lastHook = $hook;
        self::$removedScripts = [];
        self::$removedStyles = [];

        $screen = function_exists('get_current_screen') ? get_current_screen() : null;
        self::$lastScreenBase = ($screen && isset($screen->base)) ? (string) $screen->base : '';

        if (!self::$settings) {
            return;
        }

        $footprintEnabled = (bool) self::$settings->get('performance.admin.minimize_admin_footprint', false);

        // Global AJAX live mode switch (admin-ajax.php).
        // When disabled, remove AJAX-heavy scripts even on WPSN screens.
        $ajaxEnabled = \WPSN\Core\AjaxMode::isEnabled(self::$settings);
        if (!$ajaxEnabled) {
            self::removeAjaxScripts();
        }

        if (!$footprintEnabled) {
            // Still collect snapshot for diagnostics.
            self::refreshEnqueued();
            return;
        }

        if (self::isAllowedScreen($hook, $screen)) {
            self::refreshEnqueued();
            return;
        }

        // Remove any WPSN assets that might have slipped in.
        $scripts = self::collectWpsnScripts();
        $styles  = self::collectWpsnStyles();

        foreach ($scripts as $h) {
            wp_dequeue_script($h);
            wp_deregister_script($h);
            self::$removedScripts[] = $h;
        }

        foreach ($styles as $h) {
            wp_dequeue_style($h);
            wp_deregister_style($h);
            self::$removedStyles[] = $h;
        }

        self::refreshEnqueued();
    }

    /**
     * @return array<string,mixed>
     */
    public static function snapshot(): array
    {
        return [
            'enabled' => self::$settings ? (bool) self::$settings->get('performance.admin.minimize_admin_footprint', false) : false,
            'ajax_enabled' => self::$settings ? \WPSN\Core\AjaxMode::isEnabled(self::$settings) : false,
            'last_hook' => self::$lastHook,
            'last_screen_base' => self::$lastScreenBase,
            'scripts_enqueued' => self::$scriptsEnqueued,
            'styles_enqueued' => self::$stylesEnqueued,
            'removed_scripts' => self::$removedScripts,
            'removed_styles' => self::$removedStyles,
        ];
    }

    private static function refreshEnqueued(): void
    {
        self::$scriptsEnqueued = self::collectWpsnScripts();
        self::$stylesEnqueued  = self::collectWpsnStyles();
    }



    private static function removeAjaxScripts(): void
    {
        foreach (\WPSN\Core\AjaxMode::ajaxScriptHandles() as $h) {
            if (!is_string($h) || $h === '') {
                continue;
            }

            // Dequeue/deregister defensively; these are optional live-mode scripts.
            wp_dequeue_script($h);
            wp_deregister_script($h);

            if (!in_array($h, self::$removedScripts, true)) {
                self::$removedScripts[] = $h;
            }
        }
    }
    /**
     * @return string[]
     */
    private static function collectWpsnScripts(): array
    {
        global $wp_scripts;
        if (!isset($wp_scripts) || !is_object($wp_scripts) || !isset($wp_scripts->queue) || !is_array($wp_scripts->queue)) {
            return [];
        }
        return self::filterWpsnHandles($wp_scripts->queue);
    }

    /**
     * @return string[]
     */
    private static function collectWpsnStyles(): array
    {
        global $wp_styles;
        if (!isset($wp_styles) || !is_object($wp_styles) || !isset($wp_styles->queue) || !is_array($wp_styles->queue)) {
            return [];
        }
        return self::filterWpsnHandles($wp_styles->queue);
    }

    /**
     * @param array<int,mixed> $handles
     * @return string[]
     */
    private static function filterWpsnHandles(array $handles): array
    {
        $out = [];
        foreach ($handles as $h) {
            if (!is_string($h)) {
                continue;
            }
            // All our assets use the "wpsn-" prefix.
            if (strpos($h, 'wpsn-') === 0) {
                $out[] = $h;
            }
        }
        $out = array_values(array_unique($out));
        sort($out);
        return $out;
    }

    /**
     * Decide if WPSN admin assets are allowed on this screen.
     *
     * @param object|null $screen
     */
    private static function isAllowedScreen(string $hook, $screen): bool
    {
        // WP SEO Next hub + submenus.
        if ($hook === 'toplevel_page_wpsn' || strpos($hook, 'wpsn_page_') === 0) {
            return true;
        }

        // Settings page.
        if ($hook === 'settings_page_wp-seo-next') {
            return true;
        }

        // Tools pages (our pages use tools_page_wpsn-...)
        if (strpos($hook, 'tools_page_wpsn') === 0) {
            return true;
        }

        // User profile pages (Author SEO fields).
        if (in_array($hook, ['profile.php', 'user-edit.php'], true)) {
            return true;
        }

        // Post/term editing (Social fields, term meta).
        if ($screen && is_object($screen) && isset($screen->base)) {
            $base = (string) $screen->base;
            if (in_array($base, ['post', 'edit-tags', 'term'], true)) {
                return true;
            }
        }

        return false;
    }
}
