<?php
/**
 * Caching Controller
 *
 * Main controller for the caching module. Registers all cache-related hooks,
 * handles cache serving, invalidation, warmup, and WooCommerce integration.
 *
 * @package Mamba\Modules\Caching
 * @since   1.0.0
 */

namespace Mamba\Modules\Caching;

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

use Mamba\Modules\Caching\Services\PageCache;
use Mamba\Modules\Caching\Services\Invalidation;
use Mamba\Modules\Caching\Services\Preload\Preloader;
use Mamba\Modules\Caching\Services\Preload\BackgroundWarmup;
use Mamba\Modules\Caching\Services\Fragments\CartFragments;
use Mamba\Modules\Caching\Services\StatsBuffer;
use Mamba\Modules\Caching\Services\BrowserCachePolicy;
use Mamba\Modules\Caching\Admin\NginxHardening;

/**
 * Class Controller
 *
 * Caching controller that manages cache serving, invalidation hooks,
 * WooCommerce event handling, warmup scheduling, and admin bar actions.
 *
 * @since 1.0.0
 */
final class Controller {
    public function __construct(private $paths) {}
    public function registerHooks(): void {
        // Register custom cron schedules FIRST (before any scheduling)
        add_filter('cron_schedules', [$this, 'registerCronSchedules']);
        
        // Bootstrap invalidation hooks for settings changes
        Invalidation::bootstrap();
        
        add_action('template_redirect', [$this, 'maybeServe'], 0);

        // Invalidation hooks
        add_action('save_post', [Invalidation::class, 'smartClear'], 10, 1);
        add_action('woocommerce_update_product', [Invalidation::class, 'onProductUpdated'], 10, 1);
        add_action('woocommerce_product_set_stock_status', [Invalidation::class, 'onStockChanged']);
        add_action('woocommerce_variation_set_stock_status', [Invalidation::class, 'onStockChanged']);
        add_action('woocommerce_product_object_updated_props', [Invalidation::class, 'onProductPropsUpdated'], 10, 2);
        add_action('woocommerce_new_order', [Invalidation::class, 'onOrderCreated']);
        add_action('woocommerce_order_status_changed', [Invalidation::class, 'onOrderStatusChanged'], 10, 3);
        add_action('woocommerce_save_product_variation', [Invalidation::class, 'onVariationSaved'], 10, 1);
        add_action('mamba_deferred_wc_variation_clear', [Invalidation::class, 'runDeferredVariationClear'], 10, 1);
        add_action('woocommerce_product_set_stock', [Invalidation::class, 'onStockSet']);
        
        // Term relationship changes (products added/removed from categories/tags)
        add_action('set_object_terms', [Invalidation::class, 'onTermRelationshipChanged'], 10, 6);
        
        // HPOS order stock changes
        add_action('woocommerce_order_stock_reduced', [Invalidation::class, 'onOrderStockChanged']);
        add_action('woocommerce_order_stock_restored', [Invalidation::class, 'onOrderStockChanged']);
        
        // Bulk stock operations (order fulfillment/cancellation) - works in both HPOS and classic modes
        add_action('woocommerce_reduce_order_stock', [Invalidation::class, 'onBulkStockOps']);
        add_action('woocommerce_restore_order_stock', [Invalidation::class, 'onBulkStockOps']);

        // WooCommerce Cart Fragments Integration
        // Note: These are WooCommerce core hooks we're hooking INTO for cart fragment caching.
        // The 'woocommerce_' prefix is WooCommerce's own naming, not this plugin's prefix.
        add_filter('woocommerce_add_to_cart_fragments', [CartFragments::class, 'filterFragments']);
        add_action('wp_ajax_nopriv_woocommerce_get_cart_fragments', [CartFragments::class, 'ajax'], 1);
        // Add WC-AJAX hooks for modern WooCommerce installations (backward compatibility)
        add_action('wc_ajax_get_refreshed_fragments', [CartFragments::class, 'ajax'], 1);
        add_action('wc_ajax_nopriv_get_refreshed_fragments', [CartFragments::class, 'ajax'], 1);
        add_action('woocommerce_add_to_cart', [CartFragments::class, 'clear']);
        add_action('woocommerce_cart_item_removed', [CartFragments::class, 'clear']);
        // Also clear Store API cache on cart mutations
        add_action('woocommerce_add_to_cart', [Invalidation::class, 'clearStoreApi']);
        add_action('woocommerce_cart_item_removed', [Invalidation::class, 'clearStoreApi']);
        add_action('woocommerce_cart_emptied', [Invalidation::class, 'clearStoreApi']);
        add_action('woocommerce_checkout_order_processed', [Invalidation::class, 'clearStoreApi']);
        
        // Add CDN purge for cart fragment clearing
        add_action('woocommerce_add_to_cart', [__CLASS__, 'onCartFragmentClear']);
        add_action('woocommerce_cart_item_removed', [__CLASS__, 'onCartFragmentClear']);
        add_action('woocommerce_cart_emptied', [__CLASS__, 'onCartFragmentClear']);
        
        // Instant microcache purge on Store API mutations
        add_filter('rest_pre_dispatch', [$this, 'onStoreApiMutation'], 1, 3);

        // Preload
        add_action('mamba_cache_preload', [Preloader::class, 'run']);
        
        // Background warmup
        add_action('mamba_background_warmup', [BackgroundWarmup::class, 'processJob']);
        foreach (['publish_post','publish_page','publish_product','edited_product_cat','edited_category','woocommerce_update_product','woocommerce_update_product_variation'] as $hook) {
            add_action($hook, [Preloader::class, 'schedule'], 10, 1);
        }
        
        // Scheduled warmup (Premium feature)
        add_action('mamba_scheduled_warmup', [Preloader::class, 'runScheduledWarmup']);
        add_action('init', [Preloader::class, 'initScheduledWarmup'], 20);
        // Woo Blocks events (clear Store API + fragments)
        add_action('woocommerce_blocks_cart_update_order_from_request', [Invalidation::class, 'clearStoreApi']);
        add_action('woocommerce_blocks_checkout_update_order_meta', [Invalidation::class, 'clearStoreApi']);
        add_action('woocommerce_blocks_checkout_order_processed', [Invalidation::class, 'clearStoreApi']);

        // Elementor compatibility - trigger WooCommerce cache purge when Elementor templates change
        add_action('elementor/editor/after_save', [$this, 'onElementorEditorSave']);
        add_action('elementor/core/files/clear_cache', [$this, 'onElementorCacheClear']);

        // Breakdance compatibility - trigger WooCommerce cache purge when Breakdance documents change
        add_action('breakdance_after_save_document', [$this, 'onBreakdanceDocumentSave']);

        // Edge-case invalidations
        // Coupon changes - clear Store API and shop/homepage if coupons affect shop display
        add_action('woocommerce_coupon_options_save', [Invalidation::class, 'onCouponChanged']);
        add_action('woocommerce_coupon_options_usage_restriction_save', [Invalidation::class, 'onCouponChanged']);
        add_action('woocommerce_coupon_options_usage_limit_save', [Invalidation::class, 'onCouponChanged']);
        
        // Menu changes - clear shop/homepage if navigation contains dynamic product counts
        add_action('wp_update_nav_menu', [Invalidation::class, 'onMenuChanged']);

        // Cleanup
        if (!wp_next_scheduled('mamba_cache_cleanup')) {
            wp_schedule_event(time(), 'daily', 'mamba_cache_cleanup');
        }
        add_action('mamba_cache_cleanup', [Invalidation::class, 'dailyCleanup']);
        // Schedule a small priority warmup shortly after daily cleanup (opt-in via option)
        add_action('mamba_cache_cleanup', function(){
            if (!get_option('mamba_enable_page_cache', 0)) return;
            if (!get_option('mamba_enable_priority_warmup', 0)) return;
            // Schedule in ~5 minutes to avoid contention with cleanup
            if (!wp_next_scheduled('mamba_priority_warmup')) {
                wp_schedule_single_event(time() + 300, 'mamba_priority_warmup');
            }
        });
        
        // Stats buffering - ensure cron schedule is registered first
        add_action('init', [StatsBuffer::class, 'schedule'], 1);
        add_action('mamba_stats_flush', [StatsBuffer::class, 'flushNow']);
        add_action('admin_init', [StatsBuffer::class, 'flushNow']); // Fallback for disabled WP-Cron
        add_action('admin_init', [StatsBuffer::class, 'flushDailyStats']); // Emergency flush for admin pages
        
        // Add daily stats flush to the minute cron for more reliable persistence
        add_action('mamba_stats_flush', [StatsBuffer::class, 'flushDailyStats']);
        
        // Force immediate flush on dashboard access for real-time stats
        add_action('admin_init', function() {
            if (isset($_GET['page']) && sanitize_key(wp_unslash($_GET['page'])) === 'mamba-cache' && (!isset($_GET['tab']) || sanitize_key(wp_unslash($_GET['tab'])) === 'dashboard')) {
                if (class_exists('\Mamba\Modules\Caching\Services\StatsBuffer')) {
                    \Mamba\Modules\Caching\Services\StatsBuffer::flushNow();
                }
            }
        });
        
        // Display admin notifications
        add_action('admin_notices', [$this, 'displayNotifications']);
        
        // AJAX handler for clearing warmup notifications
        add_action('wp_ajax_mamba_clear_warmup_notification', [$this, 'clearWarmupNotification']);
        
        // Browser cache policy
        add_action('send_headers', [BrowserCachePolicy::class, 'applyHeaders'], 0);
        add_filter('rest_post_dispatch', [BrowserCachePolicy::class, 'applyRestHeaders'], 9, 3);
        
        // Object cache global groups are now registered via plugins_loaded hook for early availability
        // Single URL warmup after invalidation
        add_action('mamba_warmup_single_url', function($args){
            $url = '';
            if (is_array($args) && isset($args['url'])) {
                $url = $args['url'];
            } elseif (is_string($args)) {
                $url = $args;
            }
            if ($url) {
                \Mamba\Modules\Caching\Services\Preload\Preloader::warmOne($url);
            }
        }, 10, 1);
        // Sale boundary events
        add_action('mamba_product_sale_event', function($args){
            $pid = 0;
            $type = '';
            if (is_array($args)) {
                $pid = (int)($args['product_id'] ?? 0);
                $type = $args['type'] ?? '';
            }
            \Mamba\Modules\Caching\Services\Invalidation::handleSaleEvent($pid, $type);
        }, 10, 1);
        
        // Cron reliability check for missed sale events
        add_action('init', function() {
            \Mamba\Modules\Caching\Services\Invalidation::checkMissedSaleEvents();
        }, 5);

        // Admin bar actions (purge/warmup this page)
        add_action('admin_bar_menu', [$this, 'adminBarNodes'], 100);
        add_action('init', [$this, 'handleAdminBarActions']);

        // Frontend toast notices for admin bar actions
        add_action('wp_footer', [$this, 'renderFrontendNotice']);

        // Nginx hardening detect-only flow (no runtime behavior change)
        if (class_exists('\\Mamba\\Modules\\Caching\\Admin\\NginxHardening')) {
            (new NginxHardening())->register();
        }
        
        // Cache size monitoring to prevent future growth issues
        add_action('mamba_cache_size_check', [$this, 'checkCacheSize']);
        
        // Schedule cache size check (hourly)
        if (!wp_next_scheduled('mamba_cache_size_check')) {
            wp_schedule_event(time(), 'hourly', 'mamba_cache_size_check');
        }

        // Priority warmup handler (home, shop, selected categories/products)
        add_action('mamba_priority_warmup', [$this, 'runPriorityWarmup']);
    }
    
    /**
     * Register custom cron schedules
     */
    public function registerCronSchedules($schedules) {
        if (!isset($schedules['mamba_minutely'])) {
            $schedules['mamba_minutely'] = [
                'interval' => 60,
                'display' => __('Every Minute (Mamba)', 'mamba-cache-for-woocommerce')
            ];
        }
        return $schedules;
    }

    /**
     * Run a small, safe warmup of the most important pages
     */
    public function runPriorityWarmup(): void {
        if (!get_option('mamba_enable_page_cache', 0)) return;

        $urls = [];
        // Home
        $urls[] = home_url('/');
        // Shop
        if (function_exists('wc_get_page_permalink')) {
            $shop = wc_get_page_permalink('shop'); if ($shop) $urls[] = $shop;
        }
        // Top categories (by count)
        if (function_exists('get_terms')) {
            $cats = get_terms([
                'taxonomy' => 'product_cat',
                'hide_empty' => true,
                'orderby' => 'count',
                'order' => 'DESC',
                'number' => (int) apply_filters('mamba_priority_warmup_categories', 5),
            ]);
            if (!is_wp_error($cats) && $cats) {
                foreach ($cats as $c) {
                    $link = get_term_link($c);
                    if (!is_wp_error($link)) { $urls[] = $link; }
                }
            }
        }
        // Best sellers (top N simple products)
        if (function_exists('wc_get_products')) {
            $best = wc_get_products([
                'limit' => (int) apply_filters('mamba_priority_warmup_products', 10),
                'orderby' => 'total_sales',
                'order' => 'DESC',
                'status' => 'publish',
                'return' => 'ids',
            ]);
            if (is_array($best)) {
                foreach ($best as $pid) {
                    $p = get_permalink($pid); if ($p) $urls[] = $p;
                }
            }
        }

        // De-duplicate
        $urls = array_values(array_unique(array_filter($urls)));
        if (empty($urls)) return;

        // Warm with moderate concurrency (safe and quick)
        try {
            foreach ($urls as $u) {
                \Mamba\Modules\Caching\Services\Preload\Preloader::warmOne($u);
            }
        } catch (\Exception $e) {
            if (defined('WP_DEBUG') && WP_DEBUG) {
                error_log('Mamba priority warmup failed: ' . $e->getMessage());
            }
        }
    }
    
    public function maybeServe(): void { (new PageCache())->maybeServe(); }
    
    /**
     * Display admin notifications for background jobs and errors
     */
    public function displayNotifications(): void {
        if (!current_user_can('manage_options')) {
            return;
        }
        
        $notifications = get_option('mamba_admin_notifications', []);
        if (empty($notifications)) {
            return;
        }
        
        // Show only recent notifications (last 24 hours)
        $cutoff = time() - (24 * 60 * 60);
        $recentNotifications = array_filter($notifications, function($notification) use ($cutoff) {
            return ($notification['timestamp'] ?? 0) > $cutoff;
        });
        
        foreach ($recentNotifications as $notification) {
            $this->displayNotification($notification);
        }
        
        // Clean up old notifications
        if (count($notifications) !== count($recentNotifications)) {
            update_option('mamba_admin_notifications', array_values($recentNotifications));
        }
    }
    
    /**
     * Display a single notification
     */
    private function displayNotification(array $notification): void {
        $type = $notification['type'] ?? '';
        $noticeClass = 'notice-info';
        $messageHtml = '';
        
        switch ($type) {
            case 'warmup_completed':
                $success = (int)($notification['success'] ?? 0);
                $failed = (int)($notification['failed'] ?? 0);
                
                if ($failed === 0) {
                    $messageHtml = sprintf(
                        esc_html__('Background warmup completed successfully! %d URLs warmed.', 'mamba-cache-for-woocommerce'),
                        $success
                    );
                    $noticeClass = 'notice-success';
                } else {
                    $logLink = sprintf(
                        '<a href="#" class="mamba-view-warmup-log" data-job-id="%s">%s</a>', 
                        esc_attr($notification['job_id'] ?? ''),
                        esc_html__('View Log', 'mamba-cache-for-woocommerce')
                    );
                    $messageHtml = sprintf(
                        esc_html__('Background warmup completed with %1$d failures. %2$d URLs warmed, %3$d failed.', 'mamba-cache-for-woocommerce'),
                        $failed,
                        $success,
                        $failed
                    ) . ' ' . $logLink;
                    $noticeClass = 'notice-warning';
                }
                break;
                
            default:
                return; // Don't display unknown notification types
        }
        
        if ($messageHtml) {
            printf(
                '<div class="notice %s is-dismissible mamba-warmup-notice"><p>%s</p></div>',
                esc_attr($noticeClass),
                wp_kses($messageHtml, [
                    'a' => [
                        'href' => [],
                        'class' => [],
                        'data-job-id' => [],
                    ],
                ])
            );
        }
    }

    public function adminBarNodes($wp_admin_bar): void {
        if (!current_user_can('manage_options') || is_admin()) return;
        $isWoo = function_exists('is_product') && (is_product() || (function_exists('is_product_category') && is_product_category()) || (function_exists('is_product_tag') && is_product_tag()))
                 || (function_exists('is_shop') && is_shop());
        $isHome = function_exists('is_front_page') && (is_front_page() || is_home());
        if (!($isWoo || $isHome)) return;

        $currentUrl = esc_url_raw(home_url(sanitize_text_field(wp_unslash($_SERVER['REQUEST_URI'] ?? '/'))));
        // Context-aware labels
        $purgeLabel = __('Purge This Page','mamba-cache-for-woocommerce');
        $warmLabel  = __('Warmup This Page','mamba-cache-for-woocommerce');
        if (function_exists('is_product') && is_product()) { $purgeLabel = __('Purge This Product','mamba-cache-for-woocommerce'); $warmLabel = __('Warmup This Product','mamba-cache-for-woocommerce'); }
        elseif (function_exists('is_product_category') && is_product_category()) { $purgeLabel = __('Purge This Category','mamba-cache-for-woocommerce'); $warmLabel = __('Warmup This Category','mamba-cache-for-woocommerce'); }
        elseif (function_exists('is_product_tag') && is_product_tag()) { $purgeLabel = __('Purge This Tag','mamba-cache-for-woocommerce'); $warmLabel = __('Warmup This Tag','mamba-cache-for-woocommerce'); }
        elseif (function_exists('is_shop') && is_shop()) { $purgeLabel = __('Purge Shop Page','mamba-cache-for-woocommerce'); $warmLabel = __('Warmup Shop Page','mamba-cache-for-woocommerce'); }
        elseif (function_exists('is_front_page') && (is_front_page() || is_home())) { $purgeLabel = __('Purge Homepage','mamba-cache-for-woocommerce'); $warmLabel = __('Warmup Homepage','mamba-cache-for-woocommerce'); }
        // Parent dropdown
        $wp_admin_bar->add_node([
            'id'    => 'mamba-menu',
            'title' => __('Mamba','mamba-cache-for-woocommerce'),
            'href'  => false,
            'meta'  => ['class'=>'mamba-adminbar-parent']
        ]);
        // Context-aware combined action label
        $combinedLabel = __('Purge & Warm This Page','mamba-cache-for-woocommerce');
        if (function_exists('is_product') && is_product()) { $combinedLabel = __('Purge & Warm This Product','mamba-cache-for-woocommerce'); }
        elseif (function_exists('is_product_category') && is_product_category()) { $combinedLabel = __('Purge & Warm This Category','mamba-cache-for-woocommerce'); }
        elseif (function_exists('is_product_tag') && is_product_tag()) { $combinedLabel = __('Purge & Warm This Tag','mamba-cache-for-woocommerce'); }
        elseif (function_exists('is_shop') && is_shop()) { $combinedLabel = __('Purge & Warm Shop Page','mamba-cache-for-woocommerce'); }
        elseif (function_exists('is_front_page') && (is_front_page() || is_home())) { $combinedLabel = __('Purge & Warm Homepage','mamba-cache-for-woocommerce'); }
        
        // Primary combined action
        $wp_admin_bar->add_node([
            'id'     => 'mamba-purge-warm-this',
            'parent' => 'mamba-menu',
            'title'  => $combinedLabel,
            'href'   => wp_nonce_url(add_query_arg(['mamba_action'=>'purge_warm_this','mamba_url'=>$currentUrl]), 'mamba_adminbar_nonce'),
            'meta'   => ['class'=>'mamba-adminbar mamba-primary-action']
        ]);
        
        // Secondary actions (separate)
        $wp_admin_bar->add_node([
            'id'     => 'mamba-purge-this',
            'parent' => 'mamba-menu',
            'title'  => $purgeLabel,
            'href'   => wp_nonce_url(add_query_arg(['mamba_action'=>'purge_this','mamba_url'=>$currentUrl]), 'mamba_adminbar_nonce'),
            'meta'   => ['class'=>'mamba-adminbar']
        ]);
        $wp_admin_bar->add_node([
            'id'     => 'mamba-warmup-this',
            'parent' => 'mamba-menu',
            'title'  => $warmLabel,
            'href'   => wp_nonce_url(add_query_arg(['mamba_action'=>'warmup_this','mamba_url'=>$currentUrl]), 'mamba_adminbar_nonce'),
            'meta'   => ['class'=>'mamba-adminbar']
        ]);
    }
    public function handleAdminBarActions(): void {
        if (!is_user_logged_in() || !current_user_can('manage_options')) return;
        if (empty($_GET['mamba_action']) || empty($_GET['_wpnonce']) || !wp_verify_nonce(sanitize_text_field(wp_unslash($_GET['_wpnonce'])), 'mamba_adminbar_nonce')) return;
        $action = sanitize_key(wp_unslash($_GET['mamba_action']));
        $url = esc_url_raw(wp_unslash($_GET['mamba_url'] ?? ''));
        if (!$url || strlen($url) > 2000) return; // Length limit
        if (strpos($url, home_url()) !== 0) return; // Must be same site
        if ($action === 'purge_warm_this') {
            // Smart combined purge and warm action
            $this->handlePurgeWarmAction($url);
            $redirectUrl = remove_query_arg(['mamba_action','mamba_url','_wpnonce']);
            $redirectUrl = add_query_arg('mamba_notice', 'purged_warmed', $redirectUrl);
            wp_safe_redirect($redirectUrl);
            exit;
        } elseif ($action === 'purge_this') {
            \Mamba\Modules\Caching\Services\Invalidation::clearUrl($url);
            $redirectUrl = remove_query_arg(['mamba_action','mamba_url','_wpnonce']);
            $redirectUrl = add_query_arg('mamba_notice', 'purged', $redirectUrl);
            wp_safe_redirect($redirectUrl);
            exit;
        } elseif ($action === 'warmup_this') {
            \Mamba\Modules\Caching\Services\Preload\Preloader::warmOne($url);
            $redirectUrl = remove_query_arg(['mamba_action','mamba_url','_wpnonce']);
            $redirectUrl = add_query_arg('mamba_notice', 'warmed', $redirectUrl);
            wp_safe_redirect($redirectUrl);
            exit;
        }
    }
    
    /**
     * Smart combined purge and warm action with context-aware targeting
     */
    private function handlePurgeWarmAction(string $url): void {
        $urlsToWarm = [];
        
        // Parse the URL to determine context
        $parsedUrl = parse_url($url);
        $path = $parsedUrl['path'] ?? '';
        
        // Product page handling
        if (function_exists('is_product') && is_product()) {
            global $post;
            if ($post && $post->post_type === 'product') {
                // Use the same logic as clearRelatedProduct for consistency
                $productId = $post->ID;
                
                // Clear and warm product page
                \Mamba\Modules\Caching\Services\Invalidation::clearUrl($url);
                $urlsToWarm[] = $url;
                
                // Clear and warm category pages
                $cats = get_the_terms($productId, 'product_cat');
                if ($cats && !is_wp_error($cats)) {
                    foreach ($cats as $cat) {
                        $catUrl = get_term_link($cat);
                        if (!is_wp_error($catUrl)) {
                            \Mamba\Modules\Caching\Services\Invalidation::clearUrl($catUrl);
                            $urlsToWarm[] = $catUrl;
                        }
                    }
                }
                
                // Always clear and warm shop/homepage for any product update
                // This ensures price changes, stock changes, status changes, etc. are reflected immediately
                $shopUrl = wc_get_page_permalink('shop');
                $homeUrl = home_url('/');
                \Mamba\Modules\Caching\Services\Invalidation::clearUrl($shopUrl);
                \Mamba\Modules\Caching\Services\Invalidation::clearUrl($homeUrl);
                $urlsToWarm[] = $shopUrl;
                $urlsToWarm[] = $homeUrl;
                
                // Clear Store API cache
                \Mamba\Modules\Caching\Services\Invalidation::clearStoreApi();
            }
        }
        // Category page handling
        elseif (function_exists('is_product_category') && is_product_category()) {
            // Clear and warm the category page
            \Mamba\Modules\Caching\Services\Invalidation::clearUrl($url);
            $urlsToWarm[] = $url;
            
            // Clear Store API cache for category changes
            \Mamba\Modules\Caching\Services\Invalidation::clearStoreApi();
        }
        // Tag page handling
        elseif (function_exists('is_product_tag') && is_product_tag()) {
            // Clear and warm the tag page
            \Mamba\Modules\Caching\Services\Invalidation::clearUrl($url);
            $urlsToWarm[] = $url;
            
            // Clear Store API cache for tag changes
            \Mamba\Modules\Caching\Services\Invalidation::clearStoreApi();
        }
        // Shop page handling
        elseif (function_exists('is_shop') && is_shop()) {
            // Clear and warm shop page
            \Mamba\Modules\Caching\Services\Invalidation::clearUrl($url);
            $urlsToWarm[] = $url;
            
            // Clear Store API cache for shop changes
            \Mamba\Modules\Caching\Services\Invalidation::clearStoreApi();
        }
        // Homepage handling
        elseif (function_exists('is_front_page') && (is_front_page() || is_home())) {
            // Clear and warm homepage
            \Mamba\Modules\Caching\Services\Invalidation::clearUrl($url);
            $urlsToWarm[] = $url;
            
            // Clear Store API cache for homepage changes
            \Mamba\Modules\Caching\Services\Invalidation::clearStoreApi();
        }
        // Generic page handling
        else {
            // Clear and warm the specific page
            \Mamba\Modules\Caching\Services\Invalidation::clearUrl($url);
            $urlsToWarm[] = $url;
        }
        
        // Warm up all collected URLs immediately
        if (get_option('mamba_enable_page_cache', 0) && !empty($urlsToWarm)) {
            foreach ($urlsToWarm as $warmUrl) {
                \Mamba\Modules\Caching\Services\Preload\Preloader::warmOne($warmUrl);
            }
        }
    }
    
    /**
     * Render a lightweight frontend toast for admin bar actions
     */
    public function renderFrontendNotice(): void {
        if (is_admin()) return;
        if (!is_user_logged_in() || !current_user_can('manage_options')) return;
        if (empty($_GET['mamba_notice'])) return;

        $type = sanitize_key(wp_unslash($_GET['mamba_notice']));
        $message = '';
        if ($type === 'purged') {
            $message = __('Mamba: Cache purged for this page.', 'mamba-cache-for-woocommerce');
        } elseif ($type === 'warmed') {
            $message = __('Mamba: Warmup scheduled for this page.', 'mamba-cache-for-woocommerce');
        } elseif ($type === 'purged_warmed') {
            $message = __('Mamba: Purged and warmup scheduled for related pages.', 'mamba-cache-for-woocommerce');
        }
        if ($message === '') return;

        $cls = 'info';
        if ($type === 'purged') { $cls = 'success'; }
        if ($type === 'warmed') { $cls = 'success'; }
        if ($type === 'purged_warmed') { $cls = 'success'; }

        $toast_css = '.mamba-toast-container{position:fixed;top:36px;right:20px;z-index:999999;pointer-events:none}.mamba-toast{pointer-events:auto;display:flex;align-items:flex-start;gap:10px;background:linear-gradient(135deg,#ffffff 0%,#f8fafc 100%);border:1px solid #d1d5db;border-left-width:4px;border-radius:10px;padding:12px 14px;box-shadow:0 8px 24px rgba(0,0,0,0.12);max-width:360px;color:#1e293b;font:14px/1.45 -apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Helvetica,Arial,sans-serif;transform:translateX(16px) translateY(-10px);opacity:.001;transition:transform .25s ease,opacity .25s ease}.mamba-toast.show{transform:translateX(0) translateY(0);opacity:1}.mamba-toast .mamba-icon{flex:0 0 auto;width:18px;height:18px;border-radius:50%;display:inline-flex;align-items:center;justify-content:center;color:#fff}.mamba-toast .mamba-content{flex:1 1 auto}.mamba-toast .mamba-title{margin:0 0 2px 0;font-weight:600;font-size:14px}.mamba-toast .mamba-msg{margin:0;font-size:13px;color:#334155}.mamba-toast .mamba-close{appearance:none;background:transparent;border:0;color:#64748b;cursor:pointer;padding:2px;margin-left:6px}.mamba-toast.success{border-left-color:#16a34a}.mamba-toast.success .mamba-icon{background:#16a34a}.mamba-toast.info{border-left-color:#2563eb}.mamba-toast.info .mamba-icon{background:#2563eb}.mamba-toast.warning{border-left-color:#d97706}.mamba-toast.warning .mamba-icon{background:#d97706}';
        wp_register_style('mamba-toast', false);
        wp_enqueue_style('mamba-toast');
        wp_add_inline_style('mamba-toast', $toast_css);

        $toast_js = '(function(){try{var msg=' . wp_json_encode($message) . ';var type=' . wp_json_encode($cls) . ';var C=document.querySelector(".mamba-toast-container");if(!C){C=document.createElement("div");C.className="mamba-toast-container";document.body.appendChild(C);}var T=document.createElement("div");T.className="mamba-toast "+type;T.setAttribute("role","status");T.setAttribute("aria-live","polite");var icon=document.createElement("div");icon.className="mamba-icon";var svgNS="http://www.w3.org/2000/svg";var svg=document.createElementNS(svgNS,"svg");svg.setAttribute("viewBox","0 0 20 20");svg.setAttribute("width","12");svg.setAttribute("height","12");var path=document.createElementNS(svgNS,"path");path.setAttribute("d","M16.704 5.296a1 1 0 0 1 0 1.414l-7 7a1 1 0 0 1-1.414 0l-3-3A1 1 0 0 1 6.704 9.296L9 11.586l6.296-6.29a1 1 0 0 1 1.408 0z");path.setAttribute("fill","#fff");svg.appendChild(path);icon.appendChild(svg);var content=document.createElement("div");content.className="mamba-content";var title=document.createElement("div");title.className="mamba-title";title.textContent="Mamba";var p=document.createElement("p");p.className="mamba-msg";p.textContent=msg;content.appendChild(title);content.appendChild(p);var close=document.createElement("button");close.className="mamba-close";close.setAttribute("type","button");close.setAttribute("aria-label","Close");close.textContent="x";T.appendChild(icon);T.appendChild(content);T.appendChild(close);C.appendChild(T);setTimeout(function(){T.classList.add("show");},20);var remove=function(){T.classList.remove("show");setTimeout(function(){if(T&&T.parentNode){T.parentNode.removeChild(T);}},250);};var timer=setTimeout(remove,3500);close.addEventListener("click",function(){clearTimeout(timer);remove();});if(window.history&&history.replaceState){var u=new URL(window.location.href);u.searchParams.delete("mamba_notice");history.replaceState({},document.title,u.toString());}}catch(e){}})();';
        wp_register_script('mamba-toast', false, [], false, true);
        wp_enqueue_script('mamba-toast');
        wp_add_inline_script('mamba-toast', $toast_js);
    }

    /**
     * AJAX handler to clear warmup completion notifications
     */
    public function clearWarmupNotification(): void {
        // Verify nonce and permissions
        if (!current_user_can('manage_options') || !wp_verify_nonce(sanitize_text_field(wp_unslash($_POST['nonce'] ?? '')), 'wp_rest')) {
            wp_die('Unauthorized');
        }
        
        // Get current notifications
        $notifications = get_option('mamba_admin_notifications', []);
        
        // Remove warmup completion notifications
        $filteredNotifications = array_filter($notifications, function($notification) {
            return ($notification['type'] ?? '') !== 'warmup_completed';
        });
        
        // Update the option with filtered notifications
        update_option('mamba_admin_notifications', array_values($filteredNotifications));
        
        // Send success response
        wp_send_json_success();
    }
    
    /**
     * Handle Elementor editor save events
     * Triggers WooCommerce cache purge when Elementor templates are updated
     * 
     * @param int $postId The post ID that was saved
     */
    public function onElementorEditorSave(int $postId): void {
        // Only proceed if Elementor is active and this is an Elementor post
        if (!class_exists('\Elementor\Plugin') || !\Elementor\Plugin::$instance->documents->get($postId)) {
            return;
        }
        
        // Get the document to check if it's a WooCommerce-related template
        $document = \Elementor\Plugin::$instance->documents->get($postId);
        if (!$document) {
            return;
        }
        
        // Check if this is a WooCommerce-related template type
        $templateType = $document->get_name();
        $isWooTemplate = in_array($templateType, [
            'single-product',
            'archive-product',
            'product-category',
            'product-tag',
            'shop',
            'product'
        ]);
        
        // If it's a WooCommerce template, trigger comprehensive cache purge
        if ($isWooTemplate) {
            // Clear all WooCommerce-related caches
            \Mamba\Modules\Caching\Services\Invalidation::clearStoreApi();
            
            // Clear shop and homepage (always affected by template changes)
            $shopUrl = wc_get_page_permalink('shop');
            $homeUrl = home_url('/');
            \Mamba\Modules\Caching\Services\Invalidation::clearUrl($shopUrl);
            \Mamba\Modules\Caching\Services\Invalidation::clearUrl($homeUrl);
            
            // Schedule a comprehensive warmup to rebuild caches
            \Mamba\Modules\Caching\Services\Preload\Preloader::schedule();
            
            // Log the action for debugging
            if (defined('WP_DEBUG') && WP_DEBUG) {
                error_log("Mamba: Elementor WooCommerce template saved (ID: {$postId}, Type: {$templateType}) - cache purged");
            }
        }
    }
    
    /**
     * Handle Elementor cache clear events
     * Triggers WooCommerce cache purge when Elementor CSS is regenerated
     */
    public function onElementorCacheClear(): void {
        // Only proceed if Elementor is active
        if (!class_exists('\Elementor\Plugin')) {
            return;
        }
        
        // Clear all WooCommerce-related caches when Elementor CSS is regenerated
        // This ensures all pages using Elementor templates get fresh content
        \Mamba\Modules\Caching\Services\Invalidation::clearStoreApi();
        
        // Clear shop and homepage (commonly affected by CSS changes)
        $shopUrl = wc_get_page_permalink('shop');
        $homeUrl = home_url('/');
        \Mamba\Modules\Caching\Services\Invalidation::clearUrl($shopUrl);
        \Mamba\Modules\Caching\Services\Invalidation::clearUrl($homeUrl);
        
        // Schedule a comprehensive warmup to rebuild caches
        \Mamba\Modules\Caching\Services\Preload\Preloader::schedule();
        
        // Log the action for debugging
        if (defined('WP_DEBUG') && WP_DEBUG) {
            error_log("Mamba: Elementor cache cleared - WooCommerce cache purged");
        }
    }
    
    /**
     * Handle Breakdance document save events
     * Triggers WooCommerce cache purge when Breakdance documents are updated
     * 
     * @param int $postId The post ID that was saved
     */
    public function onBreakdanceDocumentSave(int $postId): void {
        // Only proceed if Breakdance is active
        if (!class_exists('\Breakdance\Plugin')) {
            return;
        }
        
        // Get post type and check if it's WooCommerce-related
        $postType = get_post_type($postId);
        $isWooPost = in_array($postType, ['product', 'product_cat', 'product_tag']);
        
        // Also check if it's a page/post that might contain WooCommerce content
        $isWooPage = in_array($postType, ['page', 'post']) && $this->containsWooCommerceContent($postId);
        
        // If it's WooCommerce-related, trigger comprehensive cache purge
        if ($isWooPost || $isWooPage) {
            // Clear all WooCommerce-related caches
            \Mamba\Modules\Caching\Services\Invalidation::clearStoreApi();
            
            // Clear shop and homepage (commonly affected by content changes)
            $shopUrl = wc_get_page_permalink('shop');
            $homeUrl = home_url('/');
            \Mamba\Modules\Caching\Services\Invalidation::clearUrl($shopUrl);
            \Mamba\Modules\Caching\Services\Invalidation::clearUrl($homeUrl);
            
            // Schedule a comprehensive warmup to rebuild caches
            \Mamba\Modules\Caching\Services\Preload\Preloader::schedule();
            
            if (defined('WP_DEBUG') && WP_DEBUG) {
                error_log("Mamba: Breakdance WooCommerce document saved (ID: {$postId}, Type: {$postType}) - cache purged");
            }
        }
    }
    
    /**
     * Check if a post contains WooCommerce content
     * 
     * @param int $postId The post ID to check
     * @return bool True if the post contains WooCommerce content
     */
    private function containsWooCommerceContent(int $postId): bool {
        // Get post content
        $post = get_post($postId);
        if (!$post) {
            return false;
        }
        
        $content = $post->post_content;
        
        // Check for WooCommerce blocks (modern block editor)
        if (function_exists('parse_blocks')) {
            $blocks = parse_blocks($content);
            foreach ($blocks as $block) {
                if (isset($block['blockName']) && strpos($block['blockName'], 'woocommerce/') === 0) {
                    return true;
                }
            }
        }
        
        // Check for WooCommerce shortcodes and Breakdance elements
        $wooPatterns = [
            'woocommerce',
            'product',
            'shop',
            'cart',
            'checkout',
            'my-account',
            'add_to_cart',
            'products',
            'product_categories',
            'recent_products',
            'featured_products',
            'sale_products',
            'best_selling_products',
            'top_rated_products'
        ];
        
        foreach ($wooPatterns as $pattern) {
            if (stripos($content, $pattern) !== false) {
                return true;
            }
        }
        
        return false;
    }
    
    /**
     * Detect Store API mutations and version-bump per-cart microcache
     * This ensures instant freshness after POST/PATCH/DELETE operations
     */
    public function onStoreApiMutation($result, $server, $request) {
        $method = strtoupper($request->get_method());
        if ($method === 'GET') return $result;
        
        $route = $request->get_route();
        if (strpos($route, '/wc/store/') !== 0) return $result;
        
        // Version bump for microcache
        if ($cartHash = $this->getStoreApiCartHash()) {
            set_transient('mamba_mc_ver_' . md5($cartHash), time(), 60);
        }
        
        // CDN purge for critical Store API endpoints
        if (strpos($route, '/wc/store/v1/cart') === 0) {
            do_action('mamba_purge_tags', ['store_api_cart', 'cart_fragments']);
        } elseif (strpos($route, '/wc/store/v1/checkout') === 0) {
            do_action('mamba_purge_tags', ['store_api_checkout']);
        }
        
        return $result;
    }
    
    /**
     * Handle cart fragment clearing with CDN purge
     */
    public static function onCartFragmentClear(): void {
        // Trigger CDN purge for cart fragments
        do_action('mamba_purge_tags', ['cart_fragments', 'store_api_cart']);
    }
    
    /**
     * Get Store API cart hash from cookie (same validation as AdminPage::getCartHash)
     */
    private function getStoreApiCartHash(): ?string {
        if (!isset($_COOKIE['store_api_cart_hash'])) return null;
        // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized -- Sanitized via sanitize_text_field
        $hash = sanitize_text_field(wp_unslash($_COOKIE['store_api_cart_hash']));
        if ($hash === '') return null;
        return preg_match('/^[a-zA-Z0-9]{8,32}$/', $hash) ? $hash : null;
    }
    
    /**
     * Check cache size and trigger cleanup if needed
     */
    public function checkCacheSize(): void {
        // FIX: Make cache size limit configurable via filter and admin setting
        $defaultMaxSize = 200 * 1024 * 1024; // 200MB default (increased from 50MB)
        $adminMaxSize = (int)get_option('mamba_cache_size_limit', $defaultMaxSize);
        $maxSize = apply_filters('mamba_cache_size_limit', $adminMaxSize);
        
        // 0 = unlimited (Pro feature), skip size checks entirely
        if ($maxSize === 0) {
            return;
        }
        
        // Ensure minimum reasonable limit (10MB)
        $maxSize = max(10 * 1024 * 1024, $maxSize);
        
        $stats = get_option('mamba_cache_stats', ['cache_size' => 0]);
        $reportedSize = (int)($stats['cache_size'] ?? 0);
        
        // Fast exit if reported size is comfortably below limit (performance optimization)
        if ($reportedSize < 0.7 * $maxSize) {
            return; // Skip expensive filesystem walk
        }
        
        // Only recalculate if reported size is near the cap
        $actualSize = \Mamba\Modules\Caching\Services\PageCache::recalculateCacheSize();
        
        // Only act if actual size exceeds limit
        if ($actualSize > $maxSize) {
            if (defined('WP_DEBUG') && WP_DEBUG) {
                error_log("Mamba: Cache size exceeded limit: " . round($actualSize / 1024 / 1024, 2) . "MB (reported: " . round($reportedSize / 1024 / 1024, 2) . "MB, limit: " . round($maxSize / 1024 / 1024, 2) . "MB)");
            }
            
            // Check if this is a persistent issue (not just a temporary spike)
            $lastCheck = get_option('mamba_cache_size_last_check', 0);
            $currentTime = time();
            
            if (($currentTime - $lastCheck) > 300) { // 5 minutes between checks
                update_option('mamba_cache_size_last_check', $currentTime);
                
                // Trigger cache cleanup
                \Mamba\Modules\Caching\Services\Invalidation::clearAll();
                
                // Log the cleanup action
                if (defined('WP_DEBUG') && WP_DEBUG) {
                    error_log("Mamba: Cache cleared due to size limit exceeded");
                }
            }
        }
    }
}
