<?php
/**
 * Block Cache Manager Service
 *
 * Manages caching and invalidation for WooCommerce Gutenberg blocks.
 * Tracks which pages contain which blocks and enables selective cache clearing.
 *
 * @package Mamba\Modules\Caching\Services
 * @since   1.0.0
 */

namespace Mamba\Modules\Caching\Services;

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

/**
 * Class BlockCacheManager
 *
 * Manages caching and invalidation for WooCommerce Gutenberg blocks.
 * Tracks which pages contain which blocks and enables selective cache clearing.
 *
 * @since 1.0.0
 */
final class BlockCacheManager {

    /**
     * Initialize block cache management
     */
    public static function init(): void {
        // Hook into post saves to update block index
        add_action('save_post', [__CLASS__, 'updateBlockIndex'], 10, 3);

        // Hook into product changes for selective invalidation
        add_action('woocommerce_update_product', [__CLASS__, 'onProductChanged'], 10, 1);
        add_action('woocommerce_product_set_stock', [__CLASS__, 'onProductStockChanged'], 10, 1);

        // Hook into category changes
        add_action('edited_product_cat', [__CLASS__, 'onCategoryChanged'], 10, 1);

        // Periodic cleanup
        if (!wp_next_scheduled('mamba_block_cache_cleanup')) {
            wp_schedule_event(time(), 'daily', 'mamba_block_cache_cleanup');
        }
        add_action('mamba_block_cache_cleanup', [__CLASS__, 'cleanupOldIndices']);
    }

    /**
     * Update block index when a post is saved
     */
    public static function updateBlockIndex(int $postId, \WP_Post $post, bool $update): void {
        // Only index published posts/pages
        if ($post->post_status !== 'publish') {
            return;
        }

        // Check if post contains WooCommerce blocks
        $wooBlocks = self::parseWooCommerceBlocks($postId);
        if (empty($wooBlocks)) {
            // Remove from index if it had blocks before
            self::removeFromBlockIndex($postId);
            return;
        }

        // Build index entry
        $indexEntry = [
            'post_id' => $postId,
            'blocks' => [],
            'products' => [],
            'categories' => [],
            'updated' => time()
        ];

        foreach ($wooBlocks as $block) {
            $blockName = $block['blockName'] ?? '';
            $attrs = $block['attrs'] ?? [];

            $indexEntry['blocks'][] = $blockName;

            // Extract product/category IDs from block attributes
            $productIds = self::extractProductIdsFromBlock($blockName, $attrs);
            $categoryIds = self::extractCategoryIdsFromBlock($blockName, $attrs);

            $indexEntry['products'] = array_unique(array_merge($indexEntry['products'], $productIds));
            $indexEntry['categories'] = array_unique(array_merge($indexEntry['categories'], $categoryIds));
        }

        // Store in cache
        $cacheKey = 'mamba_block_index_' . $postId;
        wp_cache_set($cacheKey, $indexEntry, 'mamba_block_cache', 0); // Persistent

        // Also store in option for persistence across cache clears
        $allIndices = get_option('mamba_block_indices', []);
        $allIndices[$postId] = $indexEntry;
        update_option('mamba_block_indices', $allIndices, false);
    }

    /**
     * Remove post from block index
     */
    private static function removeFromBlockIndex(int $postId): void {
        wp_cache_delete('mamba_block_index_' . $postId, 'mamba_block_cache');

        $allIndices = get_option('mamba_block_indices', []);
        unset($allIndices[$postId]);
        update_option('mamba_block_indices', $allIndices, false);
    }

    /**
     * Parse WooCommerce blocks from post content
     */
    private static function parseWooCommerceBlocks(int $postId): array {
        $post = get_post($postId);
        if (!$post) {
            return [];
        }

        $content = $post->post_content;
        $wooBlocks = [];

        if (function_exists('parse_blocks')) {
            $blocks = parse_blocks($content);
            foreach ($blocks as $block) {
                $blockName = $block['blockName'] ?? '';
                if (strpos($blockName, 'woocommerce/') === 0) {
                    $wooBlocks[] = $block;
                }
            }
        }

        return $wooBlocks;
    }

    /**
     * Extract product IDs from block attributes
     */
    private static function extractProductIdsFromBlock(string $blockName, array $attrs): array {
        $productIds = [];

        switch ($blockName) {
            case 'woocommerce/product':
            case 'woocommerce/featured-product':
                if (!empty($attrs['productId'])) {
                    $productIds[] = (int) $attrs['productId'];
                }
                break;

            case 'woocommerce/products':
            case 'woocommerce/product-on-sale':
            case 'woocommerce/product-new':
            case 'woocommerce/product-top-rated':
            case 'woocommerce/product-best-sellers':
                // These blocks may have specific product IDs in attributes
                if (!empty($attrs['products'])) {
                    $productIds = array_map('intval', (array) $attrs['products']);
                }
                break;
        }

        return array_filter($productIds);
    }

    /**
     * Extract category IDs from block attributes
     */
    private static function extractCategoryIdsFromBlock(string $blockName, array $attrs): array {
        $categoryIds = [];

        switch ($blockName) {
            case 'woocommerce/product-category':
            case 'woocommerce/product-categories':
                if (!empty($attrs['categoryId'])) {
                    $categoryIds[] = (int) $attrs['categoryId'];
                }
                if (!empty($attrs['categories'])) {
                    $categoryIds = array_merge($categoryIds, array_map('intval', (array) $attrs['categories']));
                }
                break;

            case 'woocommerce/products':
                if (!empty($attrs['categories'])) {
                    $categoryIds = array_map('intval', (array) $attrs['categories']);
                }
                break;
        }

        return array_filter($categoryIds);
    }

    /**
     * Handle product changes - selectively invalidate pages containing this product
     * Note: woocommerce_update_product passes product ID as int
     *
     * @param int|\WC_Product $product Product ID or WC_Product object
     */
    public static function onProductChanged($product): void {
        $productId = $product instanceof \WC_Product ? $product->get_id() : (int) $product;
        
        if (!$productId) {
            return;
        }
        
        $pagesToClear = self::findPagesWithProduct($productId);

        foreach ($pagesToClear as $pageId) {
            Invalidation::clearUrl(get_permalink($pageId));
        }

        if (defined('WP_DEBUG') && WP_DEBUG) {
            error_log('Mamba Block Cache: Invalidated ' . count($pagesToClear) . ' pages for product ' . $productId);
        }
    }

    /**
     * Handle product stock changes
     * Note: woocommerce_product_set_stock passes WC_Product object, not int
     *
     * @param \WC_Product $product WC_Product object
     */
    public static function onProductStockChanged($product): void {
        $productId = $product instanceof \WC_Product ? $product->get_id() : (int) $product;
        
        if (!$productId) {
            return;
        }
        
        // Stock changes affect availability blocks
        $pagesToClear = self::findPagesWithProduct($productId);

        foreach ($pagesToClear as $pageId) {
            Invalidation::clearUrl(get_permalink($pageId));
        }
    }

    /**
     * Handle category changes
     */
    public static function onCategoryChanged(int $termId): void {
        $pagesToClear = self::findPagesWithCategory($termId);

        foreach ($pagesToClear as $pageId) {
            Invalidation::clearUrl(get_permalink($pageId));
        }

        if (defined('WP_DEBUG') && WP_DEBUG) {
            error_log('Mamba Block Cache: Invalidated ' . count($pagesToClear) . ' pages for category ' . $termId);
        }
    }

    /**
     * Find pages that contain blocks displaying a specific product
     */
    private static function findPagesWithProduct(int $productId): array {
        $allIndices = get_option('mamba_block_indices', []);
        $matchingPages = [];

        foreach ($allIndices as $postId => $indexEntry) {
            if (in_array($productId, $indexEntry['products'] ?? [])) {
                $matchingPages[] = $postId;
            }
        }

        return $matchingPages;
    }

    /**
     * Find pages that contain blocks displaying products from a specific category
     */
    private static function findPagesWithCategory(int $categoryId): array {
        $allIndices = get_option('mamba_block_indices', []);
        $matchingPages = [];

        foreach ($allIndices as $postId => $indexEntry) {
            if (in_array($categoryId, $indexEntry['categories'] ?? [])) {
                $matchingPages[] = $postId;
            }
        }

        return $matchingPages;
    }

    /**
     * Cleanup old block indices
     */
    public static function cleanupOldIndices(): void {
        $allIndices = get_option('mamba_block_indices', []);
        $cutoff = time() - (7 * 24 * 60 * 60); // 7 days ago
        $cleaned = 0;

        foreach ($allIndices as $postId => $indexEntry) {
            $updated = $indexEntry['updated'] ?? 0;
            if ($updated < $cutoff) {
                // Check if post still exists and has blocks
                $currentBlocks = self::parseWooCommerceBlocks($postId);
                if (empty($currentBlocks)) {
                    unset($allIndices[$postId]);
                    wp_cache_delete('mamba_block_index_' . $postId, 'mamba_block_cache');
                    $cleaned++;
                }
            }
        }

        if ($cleaned > 0) {
            update_option('mamba_block_indices', $allIndices, false);
            if (defined('WP_DEBUG') && WP_DEBUG) {
                error_log('Mamba Block Cache: Cleaned up ' . $cleaned . ' stale indices');
            }
        }
    }

    /**
     * Get statistics about block caching
     */
    public static function getStatistics(): array {
        $allIndices = get_option('mamba_block_indices', []);
        $stats = [
            'total_indexed_pages' => count($allIndices),
            'pages_with_product_blocks' => 0,
            'pages_with_category_blocks' => 0,
            'unique_products_indexed' => [],
            'unique_categories_indexed' => []
        ];

        foreach ($allIndices as $indexEntry) {
            if (!empty($indexEntry['products'])) {
                $stats['pages_with_product_blocks']++;
                $stats['unique_products_indexed'] = array_unique(array_merge(
                    $stats['unique_products_indexed'],
                    $indexEntry['products']
                ));
            }

            if (!empty($indexEntry['categories'])) {
                $stats['pages_with_category_blocks']++;
                $stats['unique_categories_indexed'] = array_unique(array_merge(
                    $stats['unique_categories_indexed'],
                    $indexEntry['categories']
                ));
            }
        }

        $stats['unique_products_indexed'] = count($stats['unique_products_indexed']);
        $stats['unique_categories_indexed'] = count($stats['unique_categories_indexed']);

        return $stats;
    }
}
