<?php

/**
 * Advanced Settings Module
 *
 * Applies advanced settings for debug, security, and WordPress features
 *
 * @package ProRank\SEO\Modules\Core
 * @since   1.0.0
 */

declare(strict_types=1);

namespace ProRank\SEO\Modules\Core;

use ProRank\SEO\Modules\BaseModule;

if ( ! defined( 'ABSPATH' ) ) {
    exit;
}


/**
 * AdvancedSettingsModule class
 */


class AdvancedSettingsModule extends BaseModule {
    
    /**
     * Module slug
     */
    protected string $slug = 'advanced-settings';
    
    /**
     * Module name
     */
    protected string $name = 'Advanced Settings';
    
    /**
     * Module description
     */
    protected string $description = 'Advanced configuration options for power users';
    
    /**
     * Required feature tier
     */
    protected string $feature_tier = 'free';

    /**
     * Attach to the support/account parent context so the module manager
     * treats this standalone free module as enabled by default.
     */
    protected ?string $parent_slug = 'support';
    
    /**
     * Settings cache
     */
    private ?array $settings = null;

    /**
     * Prevent duplicate runtime registration.
     */
    private bool $settings_applied = false;

    /**
     * Prevent duplicate early setting registration.
     */
    private bool $early_settings_applied = false;
    
    /**
     * Initialize module
     */
    public function init(): void {
        // Register immediately during module bootstrap so frontend callbacks are
        // present on the current request, then keep lightweight hook fallbacks
        // for any later bootstrap edge cases.
        $this->apply_early_settings();
        $this->apply_settings();

        add_action('init', [$this, 'apply_settings'], 1);
        add_action('plugins_loaded', [$this, 'apply_early_settings'], 1);
    }
    
    /**
     * Initialize hooks
     * Required by ModuleInterface
     */
    public function init_hooks(): void {
        // All hooks are initialized in init() method
        $this->init();
    }
    
    /**
     * Apply settings that need to run early
     */
    public function apply_early_settings(): void {
        if ($this->early_settings_applied) {
            return;
        }
        $this->early_settings_applied = true;

        $settings = $this->get_settings();
        
        // Debug mode — only activate when WP_DEBUG is already enabled in wp-config.php
        if ($settings['debug_mode'] && defined('WP_DEBUG') && WP_DEBUG) {
            $this->enable_debug_mode($settings['log_level']);
        }
        
        // Disable file editing (needs to be set early)
        if ($settings['disable_file_editing']) {
            // Enforce file editor lock via WP filter instead of redefining constants at runtime.
            add_filter('file_mod_allowed', function($allowed, $context) {
                if ($context === 'file_edit') {
                    return false;
                }
                return $allowed;
            }, 10, 2);
        }
    }
    
    /**
     * Apply all settings
     */
    public function apply_settings(): void {
        if ($this->settings_applied) {
            return;
        }
        $this->settings_applied = true;

        $settings = $this->get_settings();
        
        // Performance settings
        if (!empty($settings['api_timeout'])) {
            add_filter('http_request_timeout', function() use ($settings) {
                return intval($settings['api_timeout']);
            });
            
            // Also apply to WordPress HTTP API
            add_filter('http_request_args', function($args) use ($settings) {
                $args['timeout'] = intval($settings['api_timeout']);
                return $args;
            });
        }
        
        // Security features
        if ($settings['disable_xmlrpc']) {
            $this->disable_xmlrpc();
        }
        
        if ($settings['disable_rest_api_public']) {
            $this->restrict_rest_api();
        }
        
        if ($settings['remove_version_strings']) {
            $this->remove_version_strings();
        }
        
        // WordPress features
        if ($settings['disable_emojis']) {
            $this->disable_emojis();
        }

        if ($settings['disable_gutenberg']) {
            $this->disable_gutenberg();
        }

        if ($settings['disable_dashicons']) {
            $this->disable_dashicons();
        }

        if ($settings['remove_global_styles']) {
            $this->remove_global_styles();
        }

        if ($settings['disable_password_strength_meter']) {
            $this->disable_password_strength_meter();
        }

        if ($settings['disable_woocommerce_scripts']) {
            $this->disable_woocommerce_scripts();
        }

        if ($settings['disable_woocommerce_cart_fragments']) {
            $this->disable_woocommerce_cart_fragments();
        }

        if ($settings['disable_woocommerce_widgets']) {
            $this->disable_woocommerce_widgets();
        }

        if ($settings['disable_woocommerce_status_meta_box']) {
            $this->disable_woocommerce_status_meta_box();
        }

        if ($settings['disable_google_maps']) {
            $this->disable_google_maps($settings['disable_google_maps_exclusions'] ?? '');
        }
    }

    /**
     * Enable debug mode
     */
    private function enable_debug_mode(string $log_level): void {
        // WP_DEBUG must already be defined in wp-config.php — a plugin should never define it at runtime

        // Create custom error handler for ProRank
        set_error_handler([$this, 'custom_error_handler'], $this->get_error_level($log_level));

        // Log that debug mode is active
        $this->log('Debug mode activated with level: ' . $log_level, 'info');
    }
    
    /**
     * Custom error handler for ProRank
     */
    public function custom_error_handler($errno, $errstr, $errfile, $errline) {
        // Only log ProRank-related errors
        if (strpos($errfile, 'prorank-seo') === false) {
            return false; // Let WordPress handle it
        }
        
        $error_types = [
            E_ERROR => 'ERROR',
            E_WARNING => 'WARNING',
            E_PARSE => 'PARSE',
            E_NOTICE => 'NOTICE',
            E_CORE_ERROR => 'CORE_ERROR',
            E_CORE_WARNING => 'CORE_WARNING',
            E_USER_ERROR => 'USER_ERROR',
            E_USER_WARNING => 'USER_WARNING',
            E_USER_NOTICE => 'USER_NOTICE',
            E_STRICT => 'STRICT',
            E_RECOVERABLE_ERROR => 'RECOVERABLE_ERROR',
            E_DEPRECATED => 'DEPRECATED',
            E_USER_DEPRECATED => 'USER_DEPRECATED',
        ];
        
        $type = $error_types[$errno] ?? 'UNKNOWN';
        $message = sprintf('[ProRank SEO %s] %s in %s on line %d', $type, $errstr, $errfile, $errline);
        
        $this->log($message, strtolower($type));
        
        // Don't execute PHP internal error handler
        return true;
    }
    
    /**
     * Get error level based on log level setting
     */
    private function get_error_level(string $log_level): int {
        switch ($log_level) {
            case 'debug':
                return E_ALL;
            case 'info':
                return E_ALL & ~E_NOTICE & ~E_STRICT & ~E_DEPRECATED;
            case 'warning':
                return E_ERROR | E_WARNING | E_PARSE;
            case 'error':
            default:
                return E_ERROR | E_PARSE;
        }
    }
    
    /**
     * Log message
     */
    private function log(string $message, string $level = 'info'): void {
        if (!$this->should_log($level)) {
            return;
        }
        
        $log_file = WP_CONTENT_DIR . '/prorank-seo-debug.log';
        $timestamp = wp_date('Y-m-d H:i:s');
        $formatted_message = sprintf("[%s] [%s] %s\n", $timestamp, strtoupper($level), $message);
        
        prorank_log($formatted_message, 3, $log_file);
    }
    
    /**
     * Check if should log based on level
     */
    private function should_log(string $level): bool {
        $settings = $this->get_settings();
        $log_level = $settings['log_level'] ?? 'error';
        
        $levels = [
            'debug' => 4,
            'info' => 3,
            'warning' => 2,
            'error' => 1,
        ];
        
        $current_level = $levels[$log_level] ?? 1;
        $message_level = $levels[$level] ?? 1;
        
        return $message_level <= $current_level;
    }
    
    /**
     * Disable XML-RPC
     */
    private function disable_xmlrpc(): void {
        add_filter('xmlrpc_enabled', '__return_false');
        
        // Remove XML-RPC methods
        add_filter('xmlrpc_methods', function($methods) {
            return [];
        });
        
        // Block XML-RPC requests
        add_action('init', function() {
            if (defined('XMLRPC_REQUEST') && XMLRPC_REQUEST) {
                wp_die(
                    esc_html__('XML-RPC is disabled on this site.', 'prorank-seo'),
                    esc_html__('XML-RPC Disabled', 'prorank-seo'),
                    ['response' => 403]
                );
            }
        });
        
        // Remove XML-RPC headers
        remove_action('wp_head', 'rsd_link');
        remove_action('wp_head', 'wlwmanifest_link');
        
        // Remove X-Pingback header
        add_filter('wp_headers', function($headers) {
            unset($headers['X-Pingback']);
            return $headers;
        });
    }
    
    /**
     * Restrict REST API to authenticated users
     */
    private function restrict_rest_api(): void {
        add_filter('rest_authentication_errors', function($result) {
            // Allow access to authentication endpoints
            if (!empty($GLOBALS['wp']->query_vars['rest_route'])) {
                $route = $GLOBALS['wp']->query_vars['rest_route'];
                
                // Allow specific public routes
                $public_routes = [
                    '/wp/v2/types',
                    '/wp/v2/taxonomies',
                    '/oembed/',
                ];
                
                foreach ($public_routes as $public_route) {
                    if (strpos($route, $public_route) !== false) {
                        return $result;
                    }
                }
            }
            
            // Require authentication for all other routes
            if (!is_user_logged_in()) {
                return new \WP_Error(
                    'rest_forbidden',
                    __('REST API access restricted to authenticated users.', 'prorank-seo'),
                    ['status' => 401]
                );
            }
            
            return $result;
        }, 20);
    }
    
    /**
     * Remove version strings
     */
    private function remove_version_strings(): void {
        // Remove version from scripts and styles
        add_filter('style_loader_src', [$this, 'remove_version_from_url'], 9999);
        add_filter('script_loader_src', [$this, 'remove_version_from_url'], 9999);
        
        // Remove WordPress version
        remove_action('wp_head', 'wp_generator');
        add_filter('the_generator', '__return_empty_string');
        
        // Remove version from RSS feeds
        add_filter('the_generator', '__return_empty_string');
        
        // Remove WooCommerce version
        remove_action('wp_head', 'wc_generator_tag');
        
        // Remove version from admin footer
        add_filter('admin_footer_text', '__return_empty_string', 11);
        add_filter('update_footer', '__return_empty_string', 11);
    }
    
    /**
     * Remove version from URL
     */
    public function remove_version_from_url($src) {
        if (is_string($src) && $this->is_prorank_build_asset_url($src)) {
            return $src;
        }
        if ($src && (strpos($src, '?ver=') !== false || strpos($src, '&ver=') !== false)) {
            $src = remove_query_arg('ver', $src);
        }
        return $src;
    }

    /**
     * Keep version query strings for assets that are updated in-place.
     * This avoids stale caches on long-lived immutable cache policies.
     *
     * @param string $url
     * @return bool
     */
    private function is_prorank_build_asset_url(string $url): bool {
        $path = (string) wp_parse_url($url, PHP_URL_PATH);
        if ($path === '') {
            return false;
        }

        return strpos($path, '/wp-content/plugins/prorank-seo/build/') !== false
            || strpos($path, '/wp-content/plugins/prorank-seo/build/') !== false
            || strpos($path, '/wp-content/uploads/elementor/css/') !== false;
    }
    
    /**
     * Disable WordPress emojis
     */
    private function disable_emojis(): void {
        // Remove emoji detection scripts
        remove_action('wp_head', 'print_emoji_detection_script', 7);
        remove_action('admin_print_scripts', 'print_emoji_detection_script');
        
        // Remove emoji styles
        remove_action('wp_print_styles', 'print_emoji_styles');
        remove_action('admin_print_styles', 'print_emoji_styles');
        
        // Remove emoji from feeds
        remove_filter('the_content_feed', 'wp_staticize_emoji');
        remove_filter('comment_text_rss', 'wp_staticize_emoji');
        
        // Remove emoji from emails
        remove_filter('wp_mail', 'wp_staticize_emoji_for_email');
        
        // Remove from TinyMCE
        add_filter('tiny_mce_plugins', function($plugins) {
            if (is_array($plugins)) {
                return array_diff($plugins, ['wpemoji']);
            }
            return [];
        });
        
        // Remove emoji CDN hostname from DNS prefetching hints
        add_filter('wp_resource_hints', function($urls, $relation_type) {
            if ('dns-prefetch' === $relation_type) {
                $emoji_svg_url = apply_filters('emoji_svg_url', 'https://s.w.org/images/core/emoji/');
                $urls = array_values(array_diff($urls, [$emoji_svg_url]));
            }
            return $urls;
        }, 10, 2);
        
        // Remove emoji from JavaScript variables
        add_filter('emoji_svg_url', '__return_false');
    }
    
    /**
     * Disable Gutenberg block editor
     */
    private function disable_gutenberg(): void {
        // Disable for posts
        add_filter('use_block_editor_for_post', '__return_false', 10);
        
        // Disable for post types
        add_filter('use_block_editor_for_post_type', '__return_false', 10);
        
        // Remove Gutenberg styles
        add_action('wp_print_styles', function() {
            wp_dequeue_style('wp-block-library');
            wp_dequeue_style('wp-block-library-theme');
            wp_dequeue_style('wc-block-style');
            wp_dequeue_style('global-styles');
            wp_dequeue_style('classic-theme-styles');
            wp_dequeue_style('wp-editor-font');
        }, 100);
        
        // Remove Gutenberg scripts
        add_action('wp_print_scripts', function() {
            wp_dequeue_script('wp-blocks');
            wp_dequeue_script('wp-block-library');
            wp_dequeue_script('wp-block-library-theme');
        }, 100);
        
        // Remove inline global styles
        remove_action('wp_enqueue_scripts', 'wp_enqueue_global_styles');
        remove_action('wp_body_open', 'wp_global_styles_render_svg_filters');
    }

    /**
     * Disable front-end Dashicons for logged-out visitors.
     */
    private function disable_dashicons(): void {
        $remove_dashicons = function() {
            if (is_user_logged_in()) {
                return;
            }

            wp_dequeue_style('dashicons');
            wp_deregister_style('dashicons');
        };

        add_action('wp_enqueue_scripts', $remove_dashicons, 100);
        add_action('wp_print_styles', $remove_dashicons, 100);
    }

    /**
     * Remove front-end global styles output while keeping the block editor intact.
     */
    private function remove_global_styles(): void {
        $blocked_handles = ['global-styles', 'classic-theme-styles', 'wp-block-library-theme'];

        $prevent_core_global_styles = function() {
            remove_action('wp_enqueue_scripts', 'wp_enqueue_global_styles', 1);
            remove_action('wp_enqueue_scripts', 'wp_enqueue_global_styles', 10);
            remove_action('wp_footer', 'wp_enqueue_global_styles', 1);
            remove_action('wp_enqueue_scripts', 'wp_enqueue_classic_theme_styles', 1);
            remove_action('wp_enqueue_scripts', 'wp_enqueue_classic_theme_styles', 10);
            remove_action('enqueue_block_assets', 'wp_enqueue_classic_theme_styles', 1);
            remove_action('enqueue_block_assets', 'wp_enqueue_classic_theme_styles', 10);
        };

        $remove_global_styles = function() use ($blocked_handles) {
            global $wp_styles;

            foreach ($blocked_handles as $handle) {
                wp_dequeue_style($handle);
                wp_deregister_style($handle);
            }

            if ($wp_styles instanceof \WP_Styles) {
                foreach (['queue', 'to_do', 'done'] as $prop) {
                    if (isset($wp_styles->$prop) && is_array($wp_styles->$prop)) {
                        $wp_styles->$prop = array_values(array_diff($wp_styles->$prop, $blocked_handles));
                    }
                }

                foreach ($blocked_handles as $handle) {
                    if (isset($wp_styles->registered[$handle])) {
                        $wp_styles->registered[$handle]->extra['after'] = [];
                    }
                }
            }
        };

        add_action('after_setup_theme', $prevent_core_global_styles, 100);
        add_action('init', $prevent_core_global_styles, 0);
        add_action('wp_enqueue_scripts', $prevent_core_global_styles, 0);
        add_action('wp_enqueue_scripts', $remove_global_styles, 100);
        add_action('enqueue_block_assets', $prevent_core_global_styles, 0);
        add_action('enqueue_block_assets', $remove_global_styles, 100);
        add_action('wp_head', $remove_global_styles, 0);
        add_action('wp_print_styles', $remove_global_styles, 100);
        add_filter('print_styles_array', function($handles) use ($blocked_handles) {
            if (!is_array($handles)) {
                return $handles;
            }

            return array_values(array_diff($handles, $blocked_handles));
        });
        add_filter('style_loader_tag', function($html, $handle) use ($blocked_handles) {
            if (in_array($handle, $blocked_handles, true)) {
                return '';
            }

            return $html;
        }, 100, 2);

        $prevent_core_global_styles();
        remove_action('wp_body_open', 'wp_global_styles_render_svg_filters');

        if ($this->can_buffer_frontend_html()) {
            ob_start(function($html) use ($remove_global_styles) {
                if (!is_string($html) || $html === '') {
                    return $html;
                }

                $remove_global_styles();

                $patterns = [
                    '#<style[^>]+id=[\'"]classic-theme-styles-inline-css[\'"][^>]*>.*?</style>#is',
                    '#<style[^>]+id=[\'"]global-styles-inline-css[\'"][^>]*>.*?</style>#is',
                    '#<style[^>]+id=[\'"]wp-block-library-theme-inline-css[\'"][^>]*>.*?</style>#is',
                    '#<link[^>]+id=[\'"]global-styles-css[\'"][^>]*>#is',
                    '#<link[^>]+id=[\'"]classic-theme-styles-css[\'"][^>]*>#is',
                    '#<link[^>]+id=[\'"]wp-block-library-theme-css[\'"][^>]*>#is',
                ];

                return preg_replace($patterns, '', $html) ?? $html;
            });
        }
    }

    /**
     * Disable WooCommerce password strength meter scripts on the front end.
     */
    private function disable_password_strength_meter(): void {
        $remove_password_meter = function() {
            if (is_admin()) {
                return;
            }

            foreach (['wc-password-strength-meter', 'zxcvbn-async', 'zxcvbn'] as $handle) {
                wp_dequeue_script($handle);
                wp_deregister_script($handle);
            }
        };

        add_action('wp_enqueue_scripts', $remove_password_meter, 100);
        add_action('wp_print_scripts', $remove_password_meter, 100);
        add_action('wp_print_footer_scripts', $remove_password_meter, 100);
    }

    /**
     * Disable WooCommerce front-end assets on non-store pages.
     */
    private function disable_woocommerce_scripts(): void {
        if (!class_exists('\WooCommerce')) {
            return;
        }

        add_action('wp_enqueue_scripts', function() {
            if (is_admin() || $this->should_keep_woocommerce_assets()) {
                return;
            }

            $this->remove_woocommerce_frontend_assets();
            add_filter('body_class', function(array $classes): array {
                remove_action('wp_footer', 'wc_no_js');
                return array_values(array_diff($classes, ['woocommerce-no-js']));
            }, 10, 1);
        }, 9999);

        // Some theme/plugin Woo styles enqueue late enough to miss the normal
        // dequeue pass. Keep this style-only to avoid destabilizing scripts.
        add_action('wp_print_styles', function() {
            if (is_admin() || $this->should_keep_woocommerce_assets()) {
                return;
            }

            $this->remove_woocommerce_frontend_assets();
        }, 9999);

        add_filter('style_loader_tag', function(string $tag, string $handle, string $href, string $media) : string {
            if (is_admin() || $this->should_keep_woocommerce_assets()) {
                return $tag;
            }

            return $this->is_woocommerce_frontend_asset($handle, $href, 'style') ? '' : $tag;
        }, 9999, 4);

        add_action('wp_enqueue_scripts', function() {
            if (is_admin() || $this->should_keep_woocommerce_tracking_assets()) {
                return;
            }

            $this->remove_woocommerce_tracking_assets();
        }, 10000);
    }

    /**
     * Disable WooCommerce cart fragments globally.
     */
    private function disable_woocommerce_cart_fragments(): void {
        if (!class_exists('\WooCommerce')) {
            return;
        }

        add_filter('woocommerce_cart_fragments_enabled', '__return_false', 100);
        add_filter('woocommerce_get_script_data', function($data, $handle) {
            if ($handle === 'wc-cart-fragments') {
                return null;
            }

            return $data;
        }, 100, 2);
        add_filter('woocommerce_add_to_cart_fragments', '__return_empty_array', 100);

        add_action('wp_enqueue_scripts', function() {
            if (is_admin()) {
                return;
            }

            wp_dequeue_script('wc-cart-fragments');
            wp_deregister_script('wc-cart-fragments');
        }, 9999);
    }

    /**
     * Disable classic WooCommerce widgets.
     */
    private function disable_woocommerce_widgets(): void {
        if (!class_exists('\WooCommerce')) {
            return;
        }

        add_action('widgets_init', function() {
            $widget_classes = [
                'WC_Widget_Cart',
                'WC_Widget_Layered_Nav',
                'WC_Widget_Layered_Nav_Filters',
                'WC_Widget_Price_Filter',
                'WC_Widget_Product_Categories',
                'WC_Widget_Product_Search',
                'WC_Widget_Product_Tag_Cloud',
                'WC_Widget_Products',
                'WC_Widget_Recently_Viewed',
                'WC_Widget_Top_Rated_Products',
                'WC_Widget_Recent_Reviews',
                'WC_Widget_Rating_Filter',
                'WC_Widget_Onsale',
                'WC_Widget_Featured_Products',
                'WC_Widget_Recent_Products',
            ];

            foreach ($widget_classes as $widget_class) {
                if (class_exists($widget_class)) {
                    unregister_widget($widget_class);
                }
            }
        }, 100);
    }

    /**
     * Disable the WooCommerce dashboard status widgets.
     */
    private function disable_woocommerce_status_meta_box(): void {
        if (!class_exists('\WooCommerce')) {
            return;
        }

        add_action('wp_dashboard_setup', function() {
            remove_meta_box('woocommerce_dashboard_status', 'dashboard', 'normal');
            remove_meta_box('woocommerce_dashboard_recent_reviews', 'dashboard', 'normal');
            remove_meta_box('woocommerce_network_orders', 'dashboard', 'normal');
        }, 100);
    }

    /**
     * Disable Google Maps API scripts on the frontend.
     *
     * Blocks scripts whose URL contains maps.googleapis.com or maps.google.com.
     * Supports a comma-separated exclusion list of post IDs, slugs, or URL
     * substrings where Maps should remain loaded.
     *
     * @param string $exclusions Comma-separated exclusion patterns.
     */
    private function disable_google_maps(string $exclusions = ''): void {
        $exclusion_list = array_filter(array_map('trim', explode(',', $exclusions)));

        add_action('wp_enqueue_scripts', function () use ($exclusion_list) {
            if (is_admin()) {
                return;
            }

            if (!empty($exclusion_list) && $this->is_google_maps_excluded($exclusion_list)) {
                return;
            }

            global $wp_scripts;
            if (!($wp_scripts instanceof \WP_Scripts)) {
                return;
            }

            foreach ($wp_scripts->registered as $handle => $script) {
                $src = $script->src ?? null;
                if (is_string($src) && $src !== '' && $this->is_google_maps_src($src)) {
                    wp_dequeue_script($handle);
                    wp_deregister_script($handle);
                }
            }
        }, 9999);

        add_filter('script_loader_tag', function (string $tag, string $handle, string $src) use ($exclusion_list): string {
            if (is_admin()) {
                return $tag;
            }

            if (!empty($exclusion_list) && $this->is_google_maps_excluded($exclusion_list)) {
                return $tag;
            }

            if ($this->is_google_maps_src($src)) {
                return '';
            }

            return $tag;
        }, 9999, 3);
    }

    /**
     * Check whether a script source is a Google Maps URL.
     *
     * @param mixed $src Script source — may be false for virtual handles.
     */
    private function is_google_maps_src(mixed $src): bool {
        if (!is_string($src) || $src === '') {
            return false;
        }
        return (bool) preg_match('/maps\.(googleapis|google)\.com/i', $src);
    }

    /**
     * Check whether the current page matches a Google Maps exclusion.
     */
    private function is_google_maps_excluded(array $exclusion_list): bool {
        $post_id = (string) get_the_ID();
        $uri = $_SERVER['REQUEST_URI'] ?? '';
        $slug = '';

        $post = get_post();
        if ($post) {
            $slug = $post->post_name;
        }

        foreach ($exclusion_list as $pattern) {
            if ($pattern === $post_id) {
                return true;
            }
            if ($pattern !== '' && $slug !== '' && $pattern === $slug) {
                return true;
            }
            if ($pattern !== '' && stripos($uri, $pattern) !== false) {
                return true;
            }
        }

        return false;
    }

    /**
     * Decide whether the current request needs WooCommerce assets.
     */
    private function should_keep_woocommerce_assets(): bool {
        foreach (['is_woocommerce', 'is_cart', 'is_checkout', 'is_account_page', 'is_product', 'is_shop', 'is_product_category', 'is_product_tag'] as $fn) {
            if (function_exists($fn) && $fn()) {
                return true;
            }
        }

        if (!is_singular()) {
            return false;
        }

        $post = get_post();
        if (!$post instanceof \WP_Post) {
            return false;
        }

        return $this->content_contains_any_woocommerce_hint(
            $this->get_singular_woocommerce_hint_sources($post),
            [
                '[woocommerce_',
                '[products',
                '[product_page',
                '[add_to_cart',
                '[featured_products',
                '[sale_products',
                '[best_selling_products',
                '[recent_products',
                '[product_category',
                '[product_categories',
                '"widgettype":"loop-grid"',
                '"widgettype":"products"',
                '"widgettype":"menu-cart"',
                '"widgettype":"woocommerce',
            ]
        );
    }

    /**
     * Keep WooCommerce tracking/attribution scripts only on real transactional/store contexts.
     */
    private function should_keep_woocommerce_tracking_assets(): bool {
        foreach (['is_cart', 'is_checkout', 'is_account_page'] as $fn) {
            if (function_exists($fn) && $fn()) {
                return true;
            }
        }

        if (!is_singular()) {
            return false;
        }

        $post = get_post();
        if (!$post instanceof \WP_Post) {
            return false;
        }

        return $this->content_contains_any_woocommerce_hint(
            $this->get_singular_woocommerce_hint_sources($post),
            [
                '[woocommerce_cart',
                '[woocommerce_checkout',
                '[woocommerce_my_account',
                '"widgettype":"woocommerce-cart"',
                '"widgettype":"woocommerce-checkout"',
                '"widgettype":"woocommerce-my-account"',
                'cart_page_url',
                'checkout_page_url',
            ]
        );
    }

    /**
     * Collect singular-content sources that may declare WooCommerce dependencies.
     *
     * @param \WP_Post $post
     * @return array<int, string>
     */
    private function get_singular_woocommerce_hint_sources(\WP_Post $post): array {
        $sources = [];

        if ($post->post_content !== '') {
            $sources[] = (string) $post->post_content;
        }

        foreach (['_elementor_data', '_elementor_element_cache'] as $meta_key) {
            $meta = get_post_meta($post->ID, $meta_key, true);
            if (is_string($meta) && $meta !== '') {
                $sources[] = $meta;
            }
        }

        return $sources;
    }

    /**
     * Check whether any source contains WooCommerce-related hints.
     *
     * @param array<int, string> $sources
     * @param array<int, string> $needles
     * @return bool
     */
    private function content_contains_any_woocommerce_hint(array $sources, array $needles): bool {
        if (empty($sources) || empty($needles)) {
            return false;
        }

        $normalized_needles = array_map('strtolower', $needles);

        foreach ($sources as $source) {
            $haystack = strtolower((string) $source);
            if ($haystack === '') {
                continue;
            }

            foreach ($normalized_needles as $needle) {
                if ($needle !== '' && strpos($haystack, $needle) !== false) {
                    return true;
                }
            }
        }

        return false;
    }

    /**
     * Whether it is safe to start a frontend HTML output buffer on this request.
     */
    private function can_buffer_frontend_html(): bool {
        if (is_admin() || wp_doing_ajax()) {
            return false;
        }

        if ((defined('REST_REQUEST') && REST_REQUEST) || (defined('XMLRPC_REQUEST') && XMLRPC_REQUEST)) {
            return false;
        }

        if ((defined('DOING_CRON') && DOING_CRON) || (defined('WP_CLI') && WP_CLI)) {
            return false;
        }

        return true;
    }

    /**
     * Remove queued WooCommerce front-end assets from the current request.
     */
    private function remove_woocommerce_frontend_assets(): void {
        global $wp_scripts, $wp_styles;

        if ($wp_scripts instanceof \WP_Scripts) {
            foreach ((array) $wp_scripts->queue as $handle) {
                $src = isset($wp_scripts->registered[$handle]) ? (string) ($wp_scripts->registered[$handle]->src ?? '') : '';
                if ($this->is_woocommerce_frontend_asset((string) $handle, $src, 'script')) {
                    wp_dequeue_script((string) $handle);
                    wp_deregister_script((string) $handle);
                }
            }
        }

        if ($wp_styles instanceof \WP_Styles) {
            foreach ((array) $wp_styles->queue as $handle) {
                $src = isset($wp_styles->registered[$handle]) ? (string) ($wp_styles->registered[$handle]->src ?? '') : '';
                if ($this->is_woocommerce_frontend_asset((string) $handle, $src, 'style')) {
                    wp_dequeue_style((string) $handle);
                    wp_deregister_style((string) $handle);
                }
            }
        }
    }

    /**
     * Remove only WooCommerce attribution/tracking scripts on non-transactional pages.
     */
    private function remove_woocommerce_tracking_assets(): void {
        global $wp_scripts;

        if (!($wp_scripts instanceof \WP_Scripts)) {
            return;
        }

        foreach ((array) $wp_scripts->queue as $handle) {
            $src = isset($wp_scripts->registered[$handle]) ? (string) ($wp_scripts->registered[$handle]->src ?? '') : '';
            if ($this->is_woocommerce_tracking_asset((string) $handle, $src)) {
                wp_dequeue_script((string) $handle);
                wp_deregister_script((string) $handle);
            }
        }
    }

    /**
     * Match known WooCommerce front-end asset handles and sources.
     */
    private function is_woocommerce_frontend_asset(string $handle, string $src, string $asset_type): bool {
        $handle = strtolower($handle);
        $src = strtolower($src);

        $known_scripts = [
            'woocommerce',
            'wc-add-to-cart',
            'wc-cart-fragments',
            'wc-checkout',
            'wc-add-to-cart-variation',
            'wc-single-product',
            'wc-country-select',
            'wc-address-i18n',
            'wc-credit-card-form',
            'wc-cart',
            'wc-chosen',
            'wc-order-attribution',
            'js-cookie',
            'sourcebuster-js',
            'wc-facebook-pixel-events',
            'facebook-capi-param-builder',
            'wcpay_assets',
        ];

        $known_styles = [
            'woocommerce-layout',
            'woocommerce-smallscreen',
            'woocommerce-general',
            'wc-block-style',
            'wc-blocks-style',
            'wc-blocks-vendors-style',
            'wc-blocks-packages-style',
            'wc-blocks-style-mini-cart',
            'neve-woocommerce',
            'sumup-checkout',
            'photoswipe',
            'photoswipe-default-skin',
            'select2',
            'woocommerce_prettyphoto_css',
        ];

        $known_handles = $asset_type === 'script' ? $known_scripts : $known_styles;
        if (in_array($handle, $known_handles, true)) {
            return true;
        }

        if (str_starts_with($handle, 'woocommerce') || str_starts_with($handle, 'wc-')) {
            return true;
        }

        foreach ([
            '/plugins/woocommerce/',
            '/plugins/woocommerce-blocks/',
            '/plugins/woo-gutenberg-products-block/',
            '/plugins/facebook-for-woocommerce/',
            '/plugins/woocommerce-payments/',
            '/plugins/sumup-payment-gateway-for-woocommerce/',
            '/themes/neve/assets/css/woocommerce',
        ] as $needle) {
            if ($src !== '' && strpos($src, $needle) !== false) {
                return true;
            }
        }

        if (
            str_starts_with($handle, 'wcpay') ||
            str_starts_with($handle, 'wc-facebook') ||
            str_starts_with($handle, 'sumup') ||
            str_starts_with($handle, 'neve-woocommerce')
        ) {
            return true;
        }

        return false;
    }

    /**
     * Match WooCommerce attribution / analytics scripts that should only load
     * on cart, checkout, account, or other explicitly transactional contexts.
     */
    private function is_woocommerce_tracking_asset(string $handle, string $src): bool {
        $handle = strtolower($handle);
        $src = strtolower($src);

        $tracking_handles = [
            'wc-order-attribution',
            'sourcebuster-js',
            'wc-facebook-pixel-events',
            'facebook-capi-param-builder',
            'googlesitekit-events-provider-woocommerce',
            'wcpay-frontend-tracks',
        ];

        if (in_array($handle, $tracking_handles, true)) {
            return true;
        }

        foreach ([
            '/plugins/woocommerce/assets/js/sourcebuster/',
            '/plugins/woocommerce/assets/js/frontend/order-attribution',
            'clientparambuilder.bundle.js',
            'googlesitekit-events-provider-woocommerce',
            '/plugins/woocommerce-payments/dist/frontend-tracks',
            '/plugins/facebook-for-woocommerce/',
        ] as $needle) {
            if ($src !== '' && strpos($src, $needle) !== false) {
                return true;
            }
        }

        return false;
    }

    /**
     * Strip WooCommerce tracking / attribution scripts from final HTML.
     */
    private function strip_woocommerce_tracking_assets_from_html(string $html): string {
        $patterns = [
            '#<script\b[^>]*id=[\'"]sourcebuster-js-js[\'"][^>]*>.*?</script>#is',
            '#<script\b[^>]*id=[\'"]wc-order-attribution-js-extra[\'"][^>]*>.*?</script>#is',
            '#<script\b[^>]*id=[\'"]wc-order-attribution-js[\'"][^>]*>.*?</script>#is',
            '#<script\b[^>]*id=[\'"]wc-facebook-pixel-events-js[\'"][^>]*>.*?</script>#is',
            '#<script\b[^>]*id=[\'"]facebook-capi-param-builder-js[\'"][^>]*>.*?</script>#is',
            '#<script\b[^>]*id=[\'"]facebook-capi-param-builder-js-after[\'"][^>]*>.*?</script>#is',
            '#<script\b[^>]*id=[\'"]facebook-for-woocommerce-inline-js-after[\'"][^>]*>.*?</script>#is',
            '#<script\b[^>]*id=[\'"]googlesitekit-events-provider-woocommerce-js-before[\'"][^>]*>.*?</script>#is',
            '#<script\b[^>]*id=[\'"]googlesitekit-events-provider-woocommerce-js[\'"][^>]*>.*?</script>#is',
            '#<script\b[^>]*id=[\'"]wcpay-frontend-tracks-js[\'"][^>]*>.*?</script>#is',
            '#<script\b[^>]*src=[\'"][^\'"]*/plugins/woocommerce/assets/js/sourcebuster/[^\'"]*[\'"][^>]*>\s*</script>#is',
            '#<script\b[^>]*src=[\'"][^\'"]*/plugins/woocommerce/assets/js/frontend/order-attribution[^\'"]*[\'"][^>]*>\s*</script>#is',
            '#<script\b[^>]*src=[\'"][^\'"]*/cache/perfmatters/[^\'"]*pixel-events[^\'"]*[\'"][^>]*>\s*</script>#is',
            '#<script\b[^>]*src=[\'"][^\'"]*clientParamBuilder\.bundle\.js[^\'"]*[\'"][^>]*>\s*</script>#is',
            '#<script\b[^>]*src=[\'"][^\'"]*googlesitekit-events-provider-woocommerce[^\'"]*[\'"][^>]*>\s*</script>#is',
            '#<script\b[^>]*src=[\'"][^\'"]*/plugins/woocommerce-payments/dist/frontend-tracks[^\'"]*[\'"][^>]*>\s*</script>#is',
        ];

        return preg_replace($patterns, '', $html) ?? $html;
    }

    /**
     * Strip cart-fragment loaders from final HTML.
     */
    private function strip_woocommerce_cart_fragments_from_html(string $html): string {
        $patterns = [
            '#<script\b[^>]*id=[\'"]wc-cart-fragments-js-extra[\'"][^>]*>.*?</script>#is',
            '#<script\b[^>]*id=[\'"]wc-cart-fragments-js[\'"][^>]*>.*?</script>#is',
            '#<script\b[^>]*src=[\'"][^\'"]*cart-fragments\.min\.js[^\'"]*[\'"][^>]*>\s*</script>#is',
            '#<script\b[^>]*>\s*function\s+perfmatters_check_cart_fragments\s*\(.*?</script>#is',
        ];

        return preg_replace($patterns, '', $html) ?? $html;
    }
    
    /**
     * Get settings
     */
    private function get_settings(): array {
        if ($this->settings === null) {
            $defaults = [
                'debug_mode' => false,
                'disable_emojis' => false,
                'disable_gutenberg' => false,
                'disable_dashicons' => false,
                'remove_global_styles' => false,
                'disable_password_strength_meter' => false,
                'disable_woocommerce_scripts' => false,
                'disable_woocommerce_cart_fragments' => false,
                'disable_woocommerce_widgets' => false,
                'disable_woocommerce_status_meta_box' => false,
                'disable_google_maps' => false,
                'disable_google_maps_exclusions' => '',
                'disable_xmlrpc' => true,
                'disable_rest_api_public' => false,
                'remove_version_strings' => true,
                'disable_file_editing' => true,
                'structural_guard_enabled' => true,
                'performance_compatibility_mode' => true,
                'performance_auto_rollback' => true,
                'performance_profile' => 'safe',
                'api_timeout' => 30,
                'cache_duration' => 3600,
                'log_level' => 'error',
            ];
            
            $this->settings = wp_parse_args(
                get_option('prorank_seo_advanced_settings', []),
                $defaults
            );
        }
        
        return $this->settings;
    }
}
