<?php

/**
 * Breadcrumbs Module
 *
 * @package ProRank\SEO\Modules\Content
 * @since   0.1.0
 */

declare(strict_types=1);

namespace ProRank\SEO\Modules\Content;

use ProRank\SEO\Modules\BaseModule;

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


/**
 * Breadcrumbs module class
 */


class BreadcrumbsModule extends BaseModule {
    
    /**
     * Module slug
     *
     * @var string
     */
    protected string $slug = 'breadcrumbs';
    
    /**
     * Module name
     *
     * @var string
     */
    protected string $name = 'Breadcrumbs';
    
    /**
     * Module description
     *
     * @var string
     */
    protected string $description = 'Add navigational breadcrumbs with schema markup';
    
    /**
     * Required tier
     *
     * @var string
     */
    protected string $feature_tier = 'free';
    
    /**
     * Parent module
     *
     * @var string|null
     */
    protected ?string $parent_slug = 'on-page-seo';
    
    /**
     * Initialize module hooks
     *
     * @return void
     */
    public function init_hooks(): void {
        if (!$this->is_enabled()) {
            return;
        }
        
        // Add breadcrumb functionality
        add_action('init', [$this, 'register_shortcode']);
        add_action('init', [$this, 'register_breadcrumbs_block']);
        add_action('prorank_seo_breadcrumbs', [$this, 'display_breadcrumbs']);
        add_filter('the_content', [$this, 'maybe_add_breadcrumbs'], 5);
        
        // Enqueue frontend styles
        add_action('wp_enqueue_scripts', [$this, 'enqueue_styles']);

        // Enqueue block editor assets
        add_action('enqueue_block_editor_assets', [$this, 'enqueue_block_editor_assets']);

        // Register REST API endpoints
        add_action('rest_api_init', [$this, 'register_rest_routes']);

        // Cache invalidation hooks
        add_action('save_post', [$this, 'clear_post_breadcrumb_cache']);
        add_action('delete_post', [$this, 'clear_post_breadcrumb_cache']);
        add_action('edited_term', [$this, 'clear_all_breadcrumb_cache']);
        add_action('created_term', [$this, 'clear_all_breadcrumb_cache']);
        add_action('deleted_term', [$this, 'clear_all_breadcrumb_cache']);
    }
    
    /**
     * Enqueue frontend styles
     *
     * @return void
     */
    public function enqueue_styles(): void {
        $settings = get_option('prorank_seo_breadcrumbs_settings', []);
        
        // Only enqueue if breadcrumbs are enabled
        if (empty($settings['enabled'])) {
            return;
        }
        
        // Check if we should display on current page
        if (!$this->should_display_breadcrumbs($settings)) {
            return;
        }
        
        wp_enqueue_style(
            'prorank-seo-breadcrumbs',
            PRORANK_PLUGIN_URL . 'assets/css/breadcrumbs.css',
            [],
            PRORANK_SEO_VERSION
        );
        
        // Add custom CSS if provided
        if (!empty($settings['custom_css'])) {
            wp_add_inline_style('prorank-seo-breadcrumbs', $settings['custom_css']);
        }
    }

    /**
     * Enqueue block editor assets for breadcrumbs block
     *
     * @return void
     */
    public function enqueue_block_editor_assets(): void {
        // Check if block script exists
        $script_path = PRORANK_PLUGIN_DIR . 'build/blocks/breadcrumbs.js';
        if (!file_exists($script_path)) {
            return;
        }

        // Enqueue the block editor script
        wp_enqueue_script(
            'prorank-seo-breadcrumbs-block',
            PRORANK_PLUGIN_URL . 'build/blocks/breadcrumbs.js',
            [
                'wp-blocks',
                'wp-element',
                'wp-editor',
                'wp-components',
                'wp-i18n',
                'wp-block-editor',
                'wp-server-side-render',
            ],
            PRORANK_SEO_VERSION,
            true
        );

        // Enqueue frontend styles for editor preview
        wp_enqueue_style(
            'prorank-seo-breadcrumbs',
            PRORANK_PLUGIN_URL . 'assets/css/breadcrumbs.css',
            [],
            PRORANK_SEO_VERSION
        );

        // Add editor-specific styles
        wp_add_inline_style('prorank-seo-breadcrumbs', '
            .prorank-breadcrumbs-block-editor {
                padding: 8px 0;
            }
            .prorank-breadcrumbs-placeholder {
                display: flex;
                align-items: center;
                gap: 8px;
                padding: 12px;
                background: #f0f0f1;
                border: 1px dashed #ccc;
                border-radius: 4px;
                color: #757575;
                font-size: 13px;
            }
            .prorank-breadcrumbs-placeholder svg {
                width: 24px;
                height: 24px;
                fill: currentColor;
            }
        ');
    }

    /**
     * Register breadcrumbs shortcode
     *
     * @return void
     */
    public function register_shortcode(): void {
        add_shortcode('prorank_breadcrumbs', [$this, 'shortcode_output']);
    }

    /**
     * Register Gutenberg block for breadcrumbs
     *
     * @return void
     */
    public function register_breadcrumbs_block(): void {
        if (!function_exists('register_block_type')) {
            return;
        }

        register_block_type('prorank-seo/breadcrumbs', [
            'api_version' => 3,
            'render_callback' => [$this, 'render_breadcrumbs_block'],
            'attributes' => [
                'separator' => [
                    'type' => 'string',
                    'default' => '›',
                ],
                'homeText' => [
                    'type' => 'string',
                    'default' => 'Home',
                ],
                'showCurrent' => [
                    'type' => 'boolean',
                    'default' => true,
                ],
                'showHome' => [
                    'type' => 'boolean',
                    'default' => true,
                ],
                'homeIcon' => [
                    'type' => 'boolean',
                    'default' => false,
                ],
                'style' => [
                    'type' => 'string',
                    'default' => 'default',
                ],
                'displayStyle' => [
                    'type' => 'string',
                    'default' => 'inline',
                ],
                'className' => [
                    'type' => 'string',
                    'default' => '',
                ],
            ],
            'editor_script' => 'prorank-seo-breadcrumbs-block',
            'category' => 'prorank-seo',
            'title' => __('ProRank Breadcrumbs', 'prorank-seo'),
            'description' => __('Display navigational breadcrumbs with schema markup.', 'prorank-seo'),
            'icon' => 'admin-links',
            'keywords' => ['breadcrumbs', 'navigation', 'seo', 'schema'],
            'supports' => [
                'html' => false,
                'align' => true,
            ],
        ]);

        // Register block category
        add_filter('block_categories_all', [$this, 'register_block_category'], 10, 2);
    }

    /**
     * Register ProRank SEO block category
     *
     * @param array $categories Block categories.
     * @param object $post Current post.
     * @return array Modified categories.
     */
    public function register_block_category($categories, $post): array {
        // Check if category already exists
        foreach ($categories as $category) {
            if ($category['slug'] === 'prorank-seo') {
                return $categories;
            }
        }

        return array_merge(
            $categories,
            [
                [
                    'slug' => 'prorank-seo',
                    'title' => __('ProRank SEO', 'prorank-seo'),
                    'icon' => 'chart-line',
                ],
            ]
        );
    }

    /**
     * Render breadcrumbs block
     *
     * @param array $attributes Block attributes.
     * @return string Block HTML output.
     */
    public function render_breadcrumbs_block($attributes): string {
        $settings = get_option('prorank_seo_breadcrumbs_settings', []);

        // Merge block attributes with saved settings
        $args = [
            'separator' => $attributes['separator'] ?? $settings['separator'] ?? '›',
            'home_text' => $attributes['homeText'] ?? $settings['home_text'] ?? __('Home', 'prorank-seo'),
            'show_current' => $attributes['showCurrent'] ?? $settings['show_current'] ?? true,
            'show_home' => $attributes['showHome'] ?? $settings['show_home'] ?? true,
            'home_icon' => $attributes['homeIcon'] ?? $settings['home_icon'] ?? false,
            'style' => $attributes['style'] ?? $settings['style'] ?? 'default',
            'display_style' => $attributes['displayStyle'] ?? $settings['display_style'] ?? 'inline',
            'class' => $attributes['className'] ?? '',
        ];

        ob_start();
        $this->display_breadcrumbs($args);
        return ob_get_clean();
    }

    /**
     * Output breadcrumbs via shortcode
     *
     * @param array $atts Shortcode attributes
     * @return string
     */
    public function shortcode_output($atts = []): string {
        $settings = get_option('prorank_seo_breadcrumbs_settings', []);

        $atts = shortcode_atts([
            'separator' => $settings['separator'] ?? '›',
            'home_text' => $settings['home_text'] ?? __('Home', 'prorank-seo'),
            'show_current' => $settings['show_current'] ?? true,
            'show_home' => $settings['show_home'] ?? true,
            'class' => '',
            'style' => $settings['style'] ?? 'default',
            'display_style' => $settings['display_style'] ?? 'inline',
            'home_icon' => $settings['home_icon'] ?? false,
        ], $atts);

        ob_start();
        $this->display_breadcrumbs($atts);
        return ob_get_clean();
    }
    
    /**
     * Display breadcrumbs
     *
     * @param array $args Display arguments
     * @return void
     */
    public function display_breadcrumbs($args = []): void {
        $settings = get_option('prorank_seo_breadcrumbs_settings', []);
        $args = wp_parse_args($args, [
            'separator' => $settings['separator'] ?? '›',
            'home_text' => $settings['home_text'] ?? __('Home', 'prorank-seo'),
            'show_current' => $settings['show_current'] ?? true,
            'show_home' => $settings['show_home'] ?? true,
            'class' => '',
            'style' => $settings['style'] ?? 'default',
            'display_style' => $settings['display_style'] ?? 'inline',
            'home_icon' => $settings['home_icon'] ?? false,
        ]);

        // Check if we should display breadcrumbs on this page type
        if (!$this->should_display_breadcrumbs($settings)) {
            return;
        }

        $breadcrumbs = $this->generate_breadcrumb_trail($args);

        if (empty($breadcrumbs)) {
            return;
        }

        // Determine schema settings with context-aware disabling
        $schema_type = $settings['schema_type'] ?? 'jsonld';
        $schema_disabled_on = $this->is_schema_disabled_for_context($settings);
        $use_microdata = !$schema_disabled_on && !empty($settings['enable_schema']) && in_array($schema_type, ['microdata', 'both'], true);
        $use_jsonld = !$schema_disabled_on && !empty($settings['enable_schema']) && in_array($schema_type, ['jsonld', 'both'], true);

        // Respect global basic schema settings for breadcrumbs
        $basic_schema_settings = get_option('prorank_basic_schema_settings', []);
        $enable_breadcrumb_schema = true;
        if (is_array($basic_schema_settings) && array_key_exists('enable_breadcrumb_schema', $basic_schema_settings)) {
            $enable_breadcrumb_schema = (bool) $basic_schema_settings['enable_breadcrumb_schema'];
        }

        if (!$enable_breadcrumb_schema) {
            $use_microdata = false;
            $use_jsonld = false;
        } else {
            // Avoid duplicate JSON-LD when Schema Markup module outputs breadcrumbs
            $schema_module_active = false;
            if (class_exists('\\ProRank\\SEO\\Plugin')) {
                $plugin = \ProRank\SEO\Plugin::get_instance();
                if ($plugin && method_exists($plugin, 'modules')) {
                    $modules = $plugin->modules();
                    if ($modules && method_exists($modules, 'is_active')) {
                        $schema_module_active = (bool) $modules->is_active('schema-markup');
                    }
                }
            }

            if ($schema_module_active) {
                $use_jsonld = false;
            }
        }

        // Build CSS classes
        $classes = ['prorank-breadcrumbs'];
        if (!empty($args['style']) && $args['style'] !== 'default') {
            $classes[] = 'style-' . sanitize_html_class($args['style']);
        }
        if (!empty($args['display_style'])) {
            if ($args['display_style'] === 'background') {
                $classes[] = 'has-background';
            } elseif ($args['display_style'] !== 'inline') {
                $classes[] = 'style-' . sanitize_html_class($args['display_style']);
            }
        }
        if (!empty($args['class'])) {
            $classes[] = sanitize_html_class($args['class']);
        }

        // Get customizable aria-label
        $aria_label = apply_filters(
            'prorank_seo_breadcrumbs_aria_label',
            $settings['aria_label'] ?? __('Breadcrumb', 'prorank-seo')
        );

        // Output HTML
        echo '<nav class="' . esc_attr(implode(' ', $classes)) . '" aria-label="' . esc_attr($aria_label) . '">';

        if ($use_microdata) {
            echo '<ol class="prorank-breadcrumbs-list" itemscope itemtype="https://schema.org/BreadcrumbList">';
        } else {
            echo '<ol class="prorank-breadcrumbs-list">';
        }

        $position = 1;
        $last_key = array_key_last($breadcrumbs);

        foreach ($breadcrumbs as $key => $crumb) {
            $is_last = ($key === $last_key);
            $is_home = ($position === 1 && $args['show_home']);

            // Output list item with or without microdata
            if ($use_microdata) {
                echo '<li class="prorank-breadcrumb-item" itemprop="itemListElement" itemscope itemtype="https://schema.org/ListItem">';
            } else {
                echo '<li class="prorank-breadcrumb-item">';
            }

            // Build the display text (with optional home icon)
            $display_text = $crumb['name'];
            if ($is_home && !empty($args['home_icon'])) {
                $display_text = '<span class="prorank-home-icon" aria-hidden="true">🏠</span> <span class="prorank-home-text">' . esc_html($crumb['name']) . '</span>';
            } else {
                $display_text = esc_html($crumb['name']);
            }

            if (!empty($crumb['url']) && !$is_last) {
                if ($use_microdata) {
                    echo '<a itemprop="item" href="' . esc_url($crumb['url']) . '">';
                    if ($is_home && !empty($args['home_icon'])) {
                        echo '<span class="prorank-home-icon" aria-hidden="true">🏠</span> <span itemprop="name" class="prorank-home-text">' . esc_html($crumb['name']) . '</span>';
                    } else {
                        echo '<span itemprop="name">' . esc_html($crumb['name']) . '</span>';
                    }
                    echo '</a>';
                } else {
                    echo '<a href="' . esc_url($crumb['url']) . '">';
                    if ($is_home && !empty($args['home_icon'])) {
                        echo '<span class="prorank-home-icon" aria-hidden="true">🏠</span> <span class="prorank-home-text">' . esc_html($crumb['name']) . '</span>';
                    } else {
                        echo esc_html($crumb['name']);
                    }
                    echo '</a>';
                }
            } else {
                if ($use_microdata) {
                    echo '<span class="prorank-breadcrumb-current" itemprop="name">' . esc_html($crumb['name']) . '</span>';
                    if (!empty($crumb['url'])) {
                        echo '<meta itemprop="item" content="' . esc_url($crumb['url']) . '" />';
                    }
                } else {
                    echo '<span class="prorank-breadcrumb-current">' . esc_html($crumb['name']) . '</span>';
                }
            }

            if ($use_microdata) {
                echo '<meta itemprop="position" content="' . esc_attr( $position ) . '" />';
            }

            if (!$is_last) {
                echo '<span class="prorank-breadcrumb-separator" aria-hidden="true">' . esc_html($args['separator']) . '</span>';
            }

            echo '</li>';
            $position++;
        }

        echo '</ol>';
        echo '</nav>';

        // Add JSON-LD structured data if enabled
        if ($use_jsonld) {
            $this->output_jsonld_schema($breadcrumbs);
        }
    }
    
    /**
     * Maybe add breadcrumbs to content
     *
     * @param string $content Post content
     * @return string
     */
    public function maybe_add_breadcrumbs($content): string {
        $settings = get_option('prorank_seo_breadcrumbs_settings', []);
        
        if (empty($settings['auto_insert']) || !is_singular()) {
            return $content;
        }
        
        $breadcrumbs = $this->shortcode_output();
        
        if ($settings['position'] === 'before') {
            return $breadcrumbs . $content;
        }
        
        return $content . $breadcrumbs;
    }
    
    /**
     * Register REST API routes
     *
     * @return void
     */
    public function register_rest_routes(): void {
        register_rest_route('prorank-seo/v1', '/settings/breadcrumbs', [
            'methods' => 'GET',
            'callback' => [$this, 'get_settings'],
            'permission_callback' => [$this, 'rest_permission_check'],
        ]);
        
        register_rest_route('prorank-seo/v1', '/settings/breadcrumbs', [
            'methods' => 'POST',
            'callback' => [$this, 'update_settings'],
            'permission_callback' => [$this, 'rest_permission_check'],
            'args' => $this->get_settings_schema(),
        ]);
    }
    
    /**
     * Check REST API permissions
     *
     * @return bool
     */
    public function rest_permission_check(): bool {
        return current_user_can('manage_options');
    }
    
    /**
     * Get breadcrumbs settings via REST API
     *
     * @return \WP_REST_Response
     */
    public function get_settings(): \WP_REST_Response {
        $defaults = [
            'enabled' => true,
            'separator' => '›',
            'home_text' => __('Home', 'prorank-seo'),
            'show_current' => true,
            'show_home' => true,
            'home_icon' => false,
            'auto_insert' => false,
            'position' => 'before',
            'enable_schema' => true,
            'schema_type' => 'jsonld', // 2025 recommendation: JSON-LD only
            'style' => 'default',
            'display_style' => 'inline',
            'show_on_home' => false,
            'show_on_posts' => true,
            'show_on_pages' => true,
            'show_on_archives' => true,
            'show_on_404' => false,
            'custom_css' => '',
            'enable_cache' => false,
            'aria_label' => __('Breadcrumb', 'prorank-seo'),
            'disable_schema_on' => [],
        ];

        $settings = wp_parse_args(
            get_option('prorank_seo_breadcrumbs_settings', []),
            $defaults
        );

        return rest_ensure_response([
            'success' => true,
            'data' => $settings,
        ]);
    }
    
    /**
     * Update breadcrumbs settings via REST API
     *
     * @param \WP_REST_Request $request Request object
     * @return \WP_REST_Response
     */
    public function update_settings(\WP_REST_Request $request): \WP_REST_Response {
        $params = $request->get_params();
        
        // Validate and sanitize
        $settings = [
            'enabled' => !empty($params['enabled']),
            'separator' => sanitize_text_field($params['separator'] ?? '›'),
            'home_text' => sanitize_text_field($params['home_text'] ?? 'Home'),
            'show_current' => !empty($params['show_current']),
            'show_home' => !empty($params['show_home']),
            'home_icon' => !empty($params['home_icon']),
            'auto_insert' => !empty($params['auto_insert']),
            'position' => in_array($params['position'] ?? 'before', ['before', 'after']) ? $params['position'] : 'before',
            'enable_schema' => !empty($params['enable_schema']),
            'schema_type' => in_array($params['schema_type'] ?? 'jsonld', ['microdata', 'jsonld', 'both']) ? $params['schema_type'] : 'jsonld',
            'style' => in_array($params['style'] ?? 'default', ['default', 'arrow', 'slash', 'pipe']) ? $params['style'] : 'default',
            'display_style' => in_array($params['display_style'] ?? 'inline', ['inline', 'background', 'compact', 'large']) ? $params['display_style'] : 'inline',
            'show_on_home' => !empty($params['show_on_home']),
            'show_on_posts' => !empty($params['show_on_posts']),
            'show_on_pages' => !empty($params['show_on_pages']),
            'show_on_archives' => !empty($params['show_on_archives']),
            'show_on_404' => !empty($params['show_on_404']),
            'custom_css' => sanitize_textarea_field($params['custom_css'] ?? ''),
            'enable_cache' => !empty($params['enable_cache']),
            'aria_label' => sanitize_text_field($params['aria_label'] ?? __('Breadcrumb', 'prorank-seo')),
            'disable_schema_on' => $this->sanitize_disable_schema_on($params['disable_schema_on'] ?? []),
        ];
        
        update_option('prorank_seo_breadcrumbs_settings', $settings);
        
        return rest_ensure_response([
            'success' => true,
            'message' => __('Breadcrumbs settings saved successfully', 'prorank-seo'),
        ]);
    }
    
    /**
     * Check if breadcrumbs should be displayed on current page
     *
     * @param array $settings Breadcrumb settings
     * @return bool
     */
    private function should_display_breadcrumbs($settings): bool {
        if (is_front_page() && empty($settings['show_on_home'])) {
            return false;
        }
        if (is_single() && empty($settings['show_on_posts'])) {
            return false;
        }
        if (is_page() && !is_front_page() && empty($settings['show_on_pages'])) {
            return false;
        }
        if (is_archive() && empty($settings['show_on_archives'])) {
            return false;
        }
        if (is_404() && empty($settings['show_on_404'])) {
            return false;
        }
        return true;
    }
    
    /**
     * Generate breadcrumb trail based on current page
     *
     * @param array $args Display arguments
     * @return array
     */
    private function generate_breadcrumb_trail($args): array {
        // Try to get from cache first
        $cache_key = $this->get_breadcrumb_cache_key($args);
        $settings = get_option('prorank_seo_breadcrumbs_settings', []);
        $cache_enabled = !empty($settings['enable_cache']);

        if ($cache_enabled && $cache_key) {
            $cached = get_transient($cache_key);
            if ($cached !== false) {
                return apply_filters('prorank_seo_breadcrumbs_trail', $cached, $args);
            }
        }

        $breadcrumbs = [];

        // Add home link if enabled
        if ($args['show_home']) {
            $breadcrumbs[] = [
                'name' => $args['home_text'],
                'url' => home_url('/')
            ];
        }

        // Generate breadcrumbs based on page type
        if (is_single()) {
            $breadcrumbs = array_merge($breadcrumbs, $this->get_single_breadcrumbs($args));
        } elseif (is_page() && !is_front_page()) {
            $breadcrumbs = array_merge($breadcrumbs, $this->get_page_breadcrumbs($args));
        } elseif (is_category()) {
            $breadcrumbs = array_merge($breadcrumbs, $this->get_category_breadcrumbs($args));
        } elseif (is_tag()) {
            $breadcrumbs = array_merge($breadcrumbs, $this->get_tag_breadcrumbs($args));
        } elseif (is_tax()) {
            $breadcrumbs = array_merge($breadcrumbs, $this->get_taxonomy_breadcrumbs($args));
        } elseif (is_author()) {
            $breadcrumbs = array_merge($breadcrumbs, $this->get_author_breadcrumbs($args));
        } elseif (is_date()) {
            $breadcrumbs = array_merge($breadcrumbs, $this->get_date_breadcrumbs($args));
        } elseif (is_search()) {
            $breadcrumbs = array_merge($breadcrumbs, $this->get_search_breadcrumbs($args));
        } elseif (is_404()) {
            $breadcrumbs[] = ['name' => __('404 Not Found', 'prorank-seo'), 'url' => ''];
        } elseif (is_archive()) {
            $breadcrumbs = array_merge($breadcrumbs, $this->get_archive_breadcrumbs($args));
        }

        // WooCommerce support
        if (class_exists('WooCommerce')) {
            $breadcrumbs = $this->maybe_add_woocommerce_breadcrumbs($breadcrumbs, $args);
        }

        // Allow custom items to be injected via filter
        $breadcrumbs = apply_filters('prorank_seo_breadcrumbs_custom_items', $breadcrumbs, $args);

        // Add pagination crumb for paged content
        $breadcrumbs = $this->maybe_add_pagination_crumb($breadcrumbs, $args);

        // Cache the breadcrumbs (1 hour by default)
        if ($cache_enabled && $cache_key && !empty($breadcrumbs)) {
            $cache_duration = apply_filters('prorank_seo_breadcrumbs_cache_duration', HOUR_IN_SECONDS);
            set_transient($cache_key, $breadcrumbs, $cache_duration);
        }

        return apply_filters('prorank_seo_breadcrumbs_trail', $breadcrumbs, $args);
    }

    /**
     * Generate a unique cache key for breadcrumbs
     *
     * @param array $args Display arguments.
     * @return string|false Cache key or false if caching should not be used.
     */
    private function get_breadcrumb_cache_key(array $args) {
        // Don't cache search or 404 pages
        if (is_search() || is_404()) {
            return false;
        }

        $key_parts = ['prorank_breadcrumbs'];

        // Add context-specific parts to the key
        if (is_singular()) {
            $post_id = get_queried_object_id();
            $key_parts[] = 'post_' . $post_id;
        } elseif (is_category() || is_tag() || is_tax()) {
            $term = get_queried_object();
            if ($term) {
                $key_parts[] = 'term_' . $term->term_id;
            }
        } elseif (is_author()) {
            $author = get_queried_object();
            if ($author) {
                $key_parts[] = 'author_' . $author->ID;
            }
        } elseif (is_date()) {
            $key_parts[] = 'date_' . get_query_var('year', 0) . '_' . get_query_var('monthnum', 0) . '_' . get_query_var('day', 0);
        } elseif (is_post_type_archive()) {
            $key_parts[] = 'archive_' . get_query_var('post_type');
        } else {
            // Generic archive/page
            $key_parts[] = 'page_' . md5($_SERVER['REQUEST_URI'] ?? '');
        }

        // Add relevant args to the key
        $key_parts[] = 'h' . ($args['show_home'] ? '1' : '0');
        $key_parts[] = 'c' . ($args['show_current'] ? '1' : '0');

        // Add pagination to the key
        $paged = max(get_query_var('paged', 0), get_query_var('page', 0));
        if ($paged > 1) {
            $key_parts[] = 'p' . $paged;
        }

        // Add language for WPML/Polylang support
        $lang = $this->get_current_language();
        if ($lang) {
            $key_parts[] = 'l' . $lang;
        }

        // Add style settings hash to avoid stale cache after settings change
        $settings = get_option('prorank_seo_breadcrumbs_settings', []);
        $style_hash = substr(md5(($settings['style'] ?? '') . ($settings['display_style'] ?? '')), 0, 6);
        $key_parts[] = 's' . $style_hash;

        return implode('_', $key_parts);
    }

    /**
     * Get current language for multilingual sites
     *
     * @return string|null Language code or null.
     */
    private function get_current_language(): ?string {
        // WPML support
        if (defined('ICL_LANGUAGE_CODE')) {
            return ICL_LANGUAGE_CODE;
        }

        // Polylang support
        if (function_exists('pll_current_language')) {
            return pll_current_language();
        }

        // TranslatePress support
        if (class_exists('TRP_Translate_Press')) {
            global $TRP_LANGUAGE;
            if (!empty($TRP_LANGUAGE)) {
                return $TRP_LANGUAGE;
            }
        }

        return null;
    }

    /**
     * Sanitize the disable_schema_on array
     *
     * @param mixed $value Input value.
     * @return array Sanitized array of context names.
     */
    private function sanitize_disable_schema_on($value): array {
        if (!is_array($value)) {
            return [];
        }

        $allowed = ['home', 'posts', 'pages', 'archives', 'search', '404'];
        return array_values(array_intersect($value, $allowed));
    }

    /**
     * Check if schema is disabled for the current page context
     *
     * @param array $settings Breadcrumbs settings.
     * @return bool True if schema should be disabled.
     */
    private function is_schema_disabled_for_context(array $settings): bool {
        $disable_schema_on = $settings['disable_schema_on'] ?? [];

        if (empty($disable_schema_on) || !is_array($disable_schema_on)) {
            return false;
        }

        // Check each context
        if (in_array('home', $disable_schema_on, true) && (is_home() || is_front_page())) {
            return true;
        }

        if (in_array('posts', $disable_schema_on, true) && is_singular('post')) {
            return true;
        }

        if (in_array('pages', $disable_schema_on, true) && is_singular('page')) {
            return true;
        }

        if (in_array('archives', $disable_schema_on, true) && is_archive()) {
            return true;
        }

        if (in_array('search', $disable_schema_on, true) && is_search()) {
            return true;
        }

        if (in_array('404', $disable_schema_on, true) && is_404()) {
            return true;
        }

        // Allow custom contexts via filter
        return apply_filters('prorank_seo_breadcrumbs_disable_schema', false, $settings);
    }

    /**
     * Clear breadcrumb cache for a specific post
     *
     * @param int $post_id Post ID.
     * @return void
     */
    public function clear_post_breadcrumb_cache(int $post_id): void {
        if ( \ProRank\SEO\Plugin::is_elementor_builder_save_request() ) {
            return;
        }

        // Delete the specific post cache
        delete_transient('prorank_breadcrumbs_post_' . $post_id . '_h1_c1');
        delete_transient('prorank_breadcrumbs_post_' . $post_id . '_h1_c0');
        delete_transient('prorank_breadcrumbs_post_' . $post_id . '_h0_c1');
        delete_transient('prorank_breadcrumbs_post_' . $post_id . '_h0_c0');

        // Clear parent page caches if this is a hierarchical post
        $post = get_post($post_id);
        if ($post && $post->post_parent) {
            $this->clear_post_breadcrumb_cache($post->post_parent);
        }
    }

    /**
     * Clear all breadcrumb caches
     *
     * @return void
     */
    public function clear_all_breadcrumb_cache(): void {
        global $wpdb;

        // Delete all breadcrumb transients
        $wpdb->query(
            "DELETE FROM {$wpdb->options} WHERE option_name LIKE '_transient_prorank_breadcrumbs_%' OR option_name LIKE '_transient_timeout_prorank_breadcrumbs_%'"
        );
    }

    /**
     * Add pagination crumb for paged content
     *
     * @param array $breadcrumbs Existing breadcrumbs.
     * @param array $args Display arguments.
     * @return array Modified breadcrumbs.
     */
    private function maybe_add_pagination_crumb(array $breadcrumbs, array $args): array {
        $paged = get_query_var('paged', 0);
        $page = get_query_var('page', 0);
        $current_page = max($paged, $page);

        if ($current_page > 1) {
            // translators: %d is the page number
            $page_text = sprintf(__('Page %1$d', 'prorank-seo'), $current_page);

            $breadcrumbs[] = [
                'name' => apply_filters('prorank_seo_breadcrumbs_pagination_text', $page_text, $current_page),
                'url' => '',  // No URL for current page crumb
            ];
        }

        return $breadcrumbs;
    }

    /**
     * Get breadcrumbs for single post
     *
     * @param array $args Display arguments
     * @return array
     */
    private function get_single_breadcrumbs($args): array {
        $breadcrumbs = [];
        $post = get_post();
        
        if (!$post) {
            return $breadcrumbs;
        }
        
        // Add post type archive if not 'post'
        if ($post->post_type !== 'post') {
            $post_type = get_post_type_object($post->post_type);
            if ($post_type && $post_type->has_archive) {
                $breadcrumbs[] = [
                    'name' => $post_type->labels->name,
                    'url' => get_post_type_archive_link($post->post_type)
                ];
            }
        }
        
        // Add taxonomies for posts and custom post types
        $taxonomy_breadcrumbs = $this->get_post_taxonomy_breadcrumbs($post);
        if (!empty($taxonomy_breadcrumbs)) {
            $breadcrumbs = array_merge($breadcrumbs, $taxonomy_breadcrumbs);
        }
        
        // Add current post
        if ($args['show_current']) {
            $breadcrumbs[] = [
                'name' => get_the_title($post),
                'url' => get_permalink($post)
            ];
        }
        
        return $breadcrumbs;
    }
    
    /**
     * Get breadcrumbs for page
     *
     * @param array $args Display arguments
     * @return array
     */
    private function get_page_breadcrumbs($args): array {
        $breadcrumbs = [];
        $post = get_post();
        
        if (!$post) {
            return $breadcrumbs;
        }
        
        // Get page ancestors
        $ancestors = array_reverse(get_post_ancestors($post));
        
        foreach ($ancestors as $ancestor) {
            $breadcrumbs[] = [
                'name' => get_the_title($ancestor),
                'url' => get_permalink($ancestor)
            ];
        }
        
        // Add current page
        if ($args['show_current']) {
            $breadcrumbs[] = [
                'name' => get_the_title($post),
                'url' => get_permalink($post)
            ];
        }
        
        return $breadcrumbs;
    }
    
    /**
     * Get breadcrumbs for category archive
     *
     * @param array $args Display arguments
     * @return array
     */
    private function get_category_breadcrumbs($args): array {
        $breadcrumbs = [];
        $category = get_queried_object();
        
        if (!$category || !isset($category->term_id)) {
            return $breadcrumbs;
        }
        
        // Get category ancestors
        $ancestors = array_reverse(get_ancestors($category->term_id, 'category'));
        
        foreach ($ancestors as $ancestor) {
            $ancestor_cat = get_category($ancestor);
            $breadcrumbs[] = [
                'name' => $ancestor_cat->name,
                'url' => get_category_link($ancestor)
            ];
        }
        
        // Add current category
        if ($args['show_current']) {
            $breadcrumbs[] = [
                'name' => single_cat_title('', false),
                'url' => get_category_link($category->term_id)
            ];
        }
        
        return $breadcrumbs;
    }
    
    /**
     * Get breadcrumbs for tag archive
     *
     * @param array $args Display arguments
     * @return array
     */
    private function get_tag_breadcrumbs($args): array {
        $breadcrumbs = [];
        
        if ($args['show_current']) {
            $breadcrumbs[] = [
                'name' => single_tag_title('', false),
                'url' => get_tag_link(get_queried_object_id())
            ];
        }
        
        return $breadcrumbs;
    }
    
    /**
     * Get breadcrumbs for custom taxonomy
     *
     * @param array $args Display arguments
     * @return array
     */
    private function get_taxonomy_breadcrumbs($args): array {
        $breadcrumbs = [];
        $term = get_queried_object();
        
        if (!$term || !isset($term->taxonomy)) {
            return $breadcrumbs;
        }
        
        $taxonomy = get_taxonomy($term->taxonomy);
        
        // Add post type archive if exists
        if ($taxonomy && !empty($taxonomy->object_type)) {
            $post_type = get_post_type_object($taxonomy->object_type[0]);
            if ($post_type && $post_type->has_archive) {
                $breadcrumbs[] = [
                    'name' => $post_type->labels->name,
                    'url' => get_post_type_archive_link($taxonomy->object_type[0])
                ];
            }
        }
        
        // Get term ancestors
        $ancestors = array_reverse(get_ancestors($term->term_id, $term->taxonomy));
        
        foreach ($ancestors as $ancestor) {
            $ancestor_term = get_term($ancestor, $term->taxonomy);
            $breadcrumbs[] = [
                'name' => $ancestor_term->name,
                'url' => get_term_link($ancestor, $term->taxonomy)
            ];
        }
        
        // Add current term
        if ($args['show_current']) {
            $breadcrumbs[] = [
                'name' => $term->name,
                'url' => get_term_link($term)
            ];
        }
        
        return $breadcrumbs;
    }
    
    /**
     * Get breadcrumbs for author archive
     *
     * @param array $args Display arguments
     * @return array
     */
    private function get_author_breadcrumbs($args): array {
        $breadcrumbs = [];
        
        if ($args['show_current']) {
            $author = get_queried_object();
            $breadcrumbs[] = [
/* translators: %1$: value */
                'name' => sprintf(__('Author: %1$s', 'prorank-seo'), $author->display_name),
                'url' => get_author_posts_url($author->ID)
            ];
        }
        
        return $breadcrumbs;
    }
    
    /**
     * Get breadcrumbs for date archive
     *
     * @param array $args Display arguments
     * @return array
     */
    private function get_date_breadcrumbs($args): array {
        $breadcrumbs = [];
        
        if (is_year()) {
            $breadcrumbs[] = [
                'name' => get_the_date('Y'),
                'url' => get_year_link(get_the_date('Y'))
            ];
        } elseif (is_month()) {
            $breadcrumbs[] = [
                'name' => get_the_date('Y'),
                'url' => get_year_link(get_the_date('Y'))
            ];
            $breadcrumbs[] = [
                'name' => get_the_date('F'),
                'url' => get_month_link(get_the_date('Y'), get_the_date('m'))
            ];
        } elseif (is_day()) {
            $breadcrumbs[] = [
                'name' => get_the_date('Y'),
                'url' => get_year_link(get_the_date('Y'))
            ];
            $breadcrumbs[] = [
                'name' => get_the_date('F'),
                'url' => get_month_link(get_the_date('Y'), get_the_date('m'))
            ];
            $breadcrumbs[] = [
                'name' => get_the_date('d'),
                'url' => get_day_link(get_the_date('Y'), get_the_date('m'), get_the_date('d'))
            ];
        }
        
        return $breadcrumbs;
    }
    
    /**
     * Get breadcrumbs for search results
     *
     * @param array $args Display arguments
     * @return array
     */
    private function get_search_breadcrumbs($args): array {
        $breadcrumbs = [];
        
        if ($args['show_current']) {
            $breadcrumbs[] = [
/* translators: %1$: value */
                'name' => sprintf(__('Search Results for: %1$s', 'prorank-seo'), get_search_query()),
                'url' => ''
            ];
        }
        
        return $breadcrumbs;
    }
    
    /**
     * Get breadcrumbs for generic archive
     *
     * @param array $args Display arguments
     * @return array
     */
    private function get_archive_breadcrumbs($args): array {
        $breadcrumbs = [];
        
        if ($args['show_current']) {
            $breadcrumbs[] = [
                'name' => post_type_archive_title('', false),
                'url' => ''
            ];
        }
        
        return $breadcrumbs;
    }
    
    /**
     * Add WooCommerce specific breadcrumbs
     *
     * @param array $breadcrumbs Existing breadcrumbs
     * @param array $args Display arguments
     * @return array
     */
    private function maybe_add_woocommerce_breadcrumbs($breadcrumbs, $args): array {
        if (!function_exists('is_woocommerce') || !is_woocommerce()) {
            return $breadcrumbs;
        }
        
        // Clear default breadcrumbs for WooCommerce pages
        $breadcrumbs = $args['show_home'] ? [['name' => $args['home_text'], 'url' => home_url('/')]] : [];
        
        // Shop page
        if (is_shop()) {
            if ($args['show_current']) {
                $breadcrumbs[] = [
                    'name' => wc_get_page_id('shop') ? get_the_title(wc_get_page_id('shop')) : __('Shop', 'prorank-seo'),
                    'url' => get_permalink(wc_get_page_id('shop'))
                ];
            }
        }
        // Product category
        elseif (is_product_category()) {
            $term = get_queried_object();
            
            // Add shop link
            $breadcrumbs[] = [
                'name' => wc_get_page_id('shop') ? get_the_title(wc_get_page_id('shop')) : __('Shop', 'prorank-seo'),
                'url' => get_permalink(wc_get_page_id('shop'))
            ];
            
            // Add category ancestors
            $ancestors = array_reverse(get_ancestors($term->term_id, 'product_cat'));
            foreach ($ancestors as $ancestor) {
                $ancestor_term = get_term($ancestor, 'product_cat');
                $breadcrumbs[] = [
                    'name' => $ancestor_term->name,
                    'url' => get_term_link($ancestor, 'product_cat')
                ];
            }
            
            // Add current category
            if ($args['show_current']) {
                $breadcrumbs[] = [
                    'name' => $term->name,
                    'url' => get_term_link($term)
                ];
            }
        }
        // Single product
        elseif (is_product()) {
            // Add shop link
            $breadcrumbs[] = [
                'name' => wc_get_page_id('shop') ? get_the_title(wc_get_page_id('shop')) : __('Shop', 'prorank-seo'),
                'url' => get_permalink(wc_get_page_id('shop'))
            ];
            
            // Add product categories
            $terms = get_the_terms(get_the_ID(), 'product_cat');
            if ($terms && !is_wp_error($terms)) {
                $primary_term = $this->get_primary_term($terms, get_the_ID(), 'product_cat');
                
                // Add category ancestors
                $ancestors = array_reverse(get_ancestors($primary_term->term_id, 'product_cat'));
                foreach ($ancestors as $ancestor) {
                    $ancestor_term = get_term($ancestor, 'product_cat');
                    $breadcrumbs[] = [
                        'name' => $ancestor_term->name,
                        'url' => get_term_link($ancestor, 'product_cat')
                    ];
                }
                
                // Add primary category
                $breadcrumbs[] = [
                    'name' => $primary_term->name,
                    'url' => get_term_link($primary_term)
                ];
            }
            
            // Add current product
            if ($args['show_current']) {
                $breadcrumbs[] = [
                    'name' => get_the_title(),
                    'url' => get_permalink()
                ];
            }
        }
        
        return $breadcrumbs;
    }
    
    /**
     * Get primary category/term from list
     *
     * @param array $terms List of terms
     * @param int $post_id Post ID
     * @param string $taxonomy Taxonomy name
     * @return object
     */
    private function get_primary_term($terms, $post_id, $taxonomy = 'category') {
        // Check for Yoast primary category
        if (class_exists('WPSEO_Primary_Term')) {
            $primary_term = new \WPSEO_Primary_Term($taxonomy, $post_id);
            $primary_id = $primary_term->get_primary_term();
            if ($primary_id) {
                foreach ($terms as $term) {
                    if ($term->term_id == $primary_id) {
                        return $term;
                    }
                }
            }
        }
        
        // Return first term as fallback
        return $terms[0];
    }
    
    /**
     * Get primary category from list
     *
     * @param array $categories List of categories
     * @param int $post_id Post ID
     * @return object
     */
    private function get_primary_category($categories, $post_id) {
        return $this->get_primary_term($categories, $post_id, 'category');
    }

    /**
     * Get taxonomy breadcrumbs for a post (supports CPT)
     *
     * @param \WP_Post $post The post object.
     * @return array Array of breadcrumb items.
     */
    private function get_post_taxonomy_breadcrumbs(\WP_Post $post): array {
        $breadcrumbs = [];

        // Handle standard posts with categories
        if ($post->post_type === 'post') {
            $categories = get_the_category($post->ID);
            if (!empty($categories)) {
                $category = $this->get_primary_category($categories, $post->ID);
                $breadcrumbs = $this->build_term_breadcrumbs($category, 'category');
            }
            return $breadcrumbs;
        }

        // Handle custom post types
        $taxonomies = get_object_taxonomies($post->post_type, 'objects');
        if (empty($taxonomies)) {
            return $breadcrumbs;
        }

        // Find the primary hierarchical taxonomy for this CPT
        $primary_taxonomy = null;
        foreach ($taxonomies as $taxonomy) {
            // Skip non-hierarchical taxonomies (like tags)
            if (!$taxonomy->hierarchical) {
                continue;
            }

            // Check if this taxonomy has terms for this post
            $terms = get_the_terms($post->ID, $taxonomy->name);
            if (!empty($terms) && !is_wp_error($terms)) {
                $primary_taxonomy = $taxonomy->name;
                break;
            }
        }

        // If no hierarchical taxonomy found, try non-hierarchical
        if (!$primary_taxonomy) {
            foreach ($taxonomies as $taxonomy) {
                $terms = get_the_terms($post->ID, $taxonomy->name);
                if (!empty($terms) && !is_wp_error($terms)) {
                    $primary_taxonomy = $taxonomy->name;
                    break;
                }
            }
        }

        if (!$primary_taxonomy) {
            return $breadcrumbs;
        }

        // Get terms and find primary
        $terms = get_the_terms($post->ID, $primary_taxonomy);
        if (empty($terms) || is_wp_error($terms)) {
            return $breadcrumbs;
        }

        $primary_term = $this->get_primary_term($terms, $post->ID, $primary_taxonomy);
        return $this->build_term_breadcrumbs($primary_term, $primary_taxonomy);
    }

    /**
     * Build breadcrumb trail from a term and its ancestors
     *
     * @param \WP_Term $term The term object.
     * @param string $taxonomy The taxonomy name.
     * @return array Array of breadcrumb items.
     */
    private function build_term_breadcrumbs(\WP_Term $term, string $taxonomy): array {
        $breadcrumbs = [];

        // Get ancestors
        $ancestors = array_reverse(get_ancestors($term->term_id, $taxonomy));

        // Add ancestor terms
        foreach ($ancestors as $ancestor_id) {
            $ancestor_term = get_term($ancestor_id, $taxonomy);
            if ($ancestor_term && !is_wp_error($ancestor_term)) {
                $breadcrumbs[] = [
                    'name' => $ancestor_term->name,
                    'url' => get_term_link($ancestor_term, $taxonomy)
                ];
            }
        }

        // Add the primary term itself
        $breadcrumbs[] = [
            'name' => $term->name,
            'url' => get_term_link($term, $taxonomy)
        ];

        return $breadcrumbs;
    }

    /**
     * Output JSON-LD structured data
     *
     * @param array $breadcrumbs Breadcrumb trail
     * @return void
     */
    private function output_jsonld_schema($breadcrumbs): void {
        if (empty($breadcrumbs)) {
            return;
        }
        
        $schema = [
            '@context' => 'https://schema.org',
            '@type' => 'BreadcrumbList',
            'itemListElement' => []
        ];
        
        $position = 1;
        foreach ($breadcrumbs as $crumb) {
            $item = [
                '@type' => 'ListItem',
                'position' => $position,
                'name' => $crumb['name']
            ];
            
            if (!empty($crumb['url'])) {
                $item['item'] = $crumb['url'];
            }
            
            $schema['itemListElement'][] = $item;
            $position++;
        }
        
        echo '<script type="application/ld+json">' . wp_json_encode($schema, JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE) . '</script>';
    }
    
    /**
     * Get settings schema for REST API
     *
     * @return array
     */
    private function get_settings_schema(): array {
        return [
            'enabled' => [
                'type' => 'boolean',
                'default' => true,
            ],
            'separator' => [
                'type' => 'string',
                'default' => '›',
            ],
            'home_text' => [
                'type' => 'string',
                'default' => 'Home',
            ],
            'show_current' => [
                'type' => 'boolean',
                'default' => true,
            ],
            'show_home' => [
                'type' => 'boolean',
                'default' => true,
            ],
            'home_icon' => [
                'type' => 'boolean',
                'default' => false,
            ],
            'auto_insert' => [
                'type' => 'boolean',
                'default' => false,
            ],
            'position' => [
                'type' => 'string',
                'enum' => ['before', 'after'],
                'default' => 'before',
            ],
            'enable_schema' => [
                'type' => 'boolean',
                'default' => true,
            ],
            'schema_type' => [
                'type' => 'string',
                'enum' => ['microdata', 'jsonld', 'both'],
                'default' => 'jsonld', // 2025 recommendation
            ],
            'style' => [
                'type' => 'string',
                'enum' => ['default', 'arrow', 'slash', 'pipe'],
                'default' => 'default',
            ],
            'display_style' => [
                'type' => 'string',
                'enum' => ['inline', 'background', 'compact', 'large'],
                'default' => 'inline',
            ],
            'show_on_home' => [
                'type' => 'boolean',
                'default' => false,
            ],
            'show_on_posts' => [
                'type' => 'boolean',
                'default' => true,
            ],
            'show_on_pages' => [
                'type' => 'boolean',
                'default' => true,
            ],
            'show_on_archives' => [
                'type' => 'boolean',
                'default' => true,
            ],
            'show_on_404' => [
                'type' => 'boolean',
                'default' => false,
            ],
            'custom_css' => [
                'type' => 'string',
                'default' => '',
            ],
            'enable_cache' => [
                'type' => 'boolean',
                'default' => false,
            ],
            'aria_label' => [
                'type' => 'string',
                'default' => 'Breadcrumb',
            ],
            'disable_schema_on' => [
                'type' => 'array',
                'items' => [
                    'type' => 'string',
                    'enum' => ['home', 'posts', 'pages', 'archives', 'search', '404'],
                ],
                'default' => [],
            ],
        ];
    }
}
