/*!
 * Copyright (c) 2024-2026 STMicroelectronics.
 * All rights reserved.
 * This software is licensed under terms that can be found in the LICENSE file
 * in the root directory of this software component.
 * If no LICENSE file comes with this software, it is provided AS-IS.
 * SPDX-License-Identifier: SLA0044
 */
/**
 * localtoc_tabs_sync.js - Tab-aware navigation for multi-die HAL documentation
 *
 * ARCHITECTURAL OVERVIEW
 * ======================
 * This script provides two related navigation features for multi-die HAL documentation:
 *
 * 1. **Localtoc synchronization**: Synchronizes localtoc (local table of contents) links with sphinx-tabs.
 *    When a user switches tabs, localtoc links are updated to point to the corresponding
 *    anchors for the active tab's die/variant (e.g., STM32C562xx, STM32C5A3xx, STM32C542xx).
 *
 * 2. **Cross-page type link navigation**: Makes function signature parameter type links die-aware.
 *    When a user clicks a type link (e.g., hal_i3c_handle_t in a function signature), the target
 *    URL is rewritten to navigate to the user's preferred die variant on the target page.
 *
 * Both features are kept in the same file because:
 * - They share utility functions (extractDieFromTabButton, die name extraction)
 * - They are needed on the same set of pages (all *_exported_functions.html pages)
 * - Single file inclusion simplifies post-processing
 * - Both implement "tab-aware navigation" for multi-die documentation
 *
 * LOCALTOC SYNCHRONIZATION
 * ========================
 * The HTML post-processing (html.py) adds data attributes to localtoc links:
 * - href="#<default_group_id>" - Points to default die's anchor (initially)
 * - data-cpp-id="<cpp_id>" - Original C++ identifier (for reference)
 * - data-all-group-ids="<id1>,<id2>,<id3>" - Comma-separated list of ALL die group IDs (default is first)
 *
 * Algorithm:
 * 1. Track the currently active tab (die variant) using MutationObserver on aria-selected attribute
 * 2. When a tab switches (detected via MutationObserver), extract the die name (e.g., "STM32C562xx") from button text
 * 3. Update all localtoc links to point to anchors matching the active die
 * 4. If no matching group ID exists for the active die, set href to invalid anchor and mark as unavailable
 *
 * Synchronization:
 * Uses MutationObserver to watch for aria-selected attribute changes on sphinx-tabs buttons.
 * This provides robust, event-driven synchronization without fragile setTimeout delays.
 *
 * CROSS-PAGE TYPE LINK NAVIGATION
 * ================================
 * The HTML post-processing (html.py) adds data attributes and onclick handler to cross-page type links:
 * - href="page.html#<default_group_id>" - Points to default die's anchor on target page
 * - data-cpp-id="<cpp_id>" - Original C++ identifier (for reference)
 * - data-all-group-ids="<id1>,<id2>,<id3>" - Comma-separated list of ALL die group IDs for target type
 * - onclick="handleCrossPageTypeLinkClick(event, this); return false;" - Navigation interception
 *
 * Algorithm:
 * 1. Intercept link click events via onclick handler
 * 2. Extract user's preferred die from active tab button on current page
 * 3. Check if href already points to preferred die (optimization - allow default navigation)
 * 4. Find matching die variant in data-all-group-ids
 * 5. Rewrite window.location.href to target URL with preferred die's anchor
 * 6. If type unavailable for preferred die, show alert and prevent navigation
 */

(function() {
    'use strict';

    // Debug flag for highly verbose/detailed logging (loops, data structure dumps)
    // Set to true only when deep debugging is needed for localtoc synchronization issues
    // Basic debug messages use console.debug() directly (controlled by browser console settings)
    const ACTIVATE_DETAILED_DEBUG_INFO = false;

    // Current active die (e.g., "STM32C562xx")
    let currentActiveDie = null;
    // Base64-encoded die name from tab button's name attribute (e.g., "U1RNMzJDNTYyeHg=")
    let currentActiveDieEncoded = null;

    /**
     * Extract die name from tab button text.
     * Tab buttons have text like "STM32C562xx", "STM32C5A3xx", etc.
     *
     * @param {HTMLElement} tabButton - The sphinx-tabs button element
     * @returns {string|null} Die name (e.g., "STM32C562xx") or null if not found
     */
    function extractDieFromTabButton(tabButton) {
        const text = tabButton.textContent.trim();
        // Die names MUST follow pattern: STM32<series><variant>xx (e.g., STM32C562xx, STM32C5A3xx)
        // If this assumption changes, this function must be updated accordingly
        const diePattern = /^STM32[A-Z0-9]+xx$/i;
        if (diePattern.test(text)) {
            return text;
        }
        console.warn(`[localtoc_tabs_sync] Tab button text does not match expected die pattern: "${text}"`);
        return null;
    }

    /**
     * Extract die name from a Doxygen group ID or type ID.
     * Group IDs follow pattern: STM32<die>_group__... (e.g., STM32C562xx_group__FLASH__...)
     * Type IDs follow pattern: STM32<die>_struct/union/typedef... (e.g., STM32C562xx_structhal__flash__area__info__t)
     *
     * @param {string} groupId - The Doxygen group ID or type ID
     * @returns {string|null} Die name (e.g., "STM32C562xx") or null if pattern doesn't match
     */
    function extractDieFromGroupId(groupId) {
        // Match both group IDs (functions, enums) and type IDs (struct/union/typedef)
        const match = groupId.match(/^(STM32[^_]+)_(group__|struct|union|typedef)/);
        return match ? match[1] : null;
    }

    /**
     * Update all localtoc links to point to anchors for the currently active die.
     *
     * For each link with data-cpp-id:
     * 1. Get all group IDs from data-all-group-ids
     * 2. Find the group ID matching the current active die
     * 3. Update href to point to the matching group ID
     */
    function updateLocaltocLinks() {
        if (!currentActiveDie) {
            return; // No active die tracked yet
        }

        // Find the localtoc container for Shibuya theme
        const localtoc = document.querySelector('.localtoc');
        if (!localtoc) {
            return; // No localtoc on this page
        }

        // Find all links with data-cpp-id (these are the processed breathe links)
        const links = localtoc.querySelectorAll('a[data-cpp-id]');

        links.forEach(link => {
            // Get all group IDs from data attribute
            const allGroupIdsStr = link.getAttribute('data-all-group-ids');
            if (!allGroupIdsStr) {
                return; // Skip links without group IDs
            }

            const allGroupIds = allGroupIdsStr.split(',');

            // Find the group ID matching the current active die
            let targetGroupId = null;
            for (const groupId of allGroupIds) {
                const die = extractDieFromGroupId(groupId);
                if (die === currentActiveDie) {
                    targetGroupId = groupId;
                    break;
                }
            }

            // Update href if a matching group ID was found
            if (targetGroupId) {
                link.setAttribute('href', `#${targetGroupId}`);
                link.classList.remove('localtoc-link-unavailable');
            } else {
                // No die match found - set href to non-existent anchor to prevent navigation to other tabs
                const cppId = link.getAttribute('data-cpp-id');
                link.setAttribute('href', `#MISSING_LINK_${currentActiveDie}_${cppId}`);
                link.classList.add('localtoc-link-unavailable');
                console.warn(`[localtoc_tabs_sync] No matching group ID for die ${currentActiveDie} on link with cpp-id ${cppId}`);
            }
        });
    }

    /**
     * Check if an element is inside a hidden sphinx-tabs panel or collapsed section.
     *
     * @param {HTMLElement} element - The element to check
     * @returns {Object} Object with {hasHiddenPanel: boolean, hiddenPanel: Element|null, hasCollapsedParent: boolean}
     */
    function checkElementVisibility(element) {
        let current = element;
        let hasCollapsedParent = false;
        let hasHiddenPanel = false;
        let hiddenPanel = null;

        while (current && current !== document.body) {
            // Check for collapsed globaltoc sections
            if (current.tagName === 'LI' && current.classList.contains('_collapse')) {
                hasCollapsedParent = true;
            }

            // Check for hidden sphinx-tabs panel
            if (current.classList && current.classList.contains('sphinx-tabs-panel') && current.hasAttribute('hidden')) {
                hasHiddenPanel = true;
                hiddenPanel = current;
            }

            current = current.parentElement;
        }

        return { hasHiddenPanel, hiddenPanel, hasCollapsedParent };
    }

    /**
     * Activate a sphinx-tabs panel by clicking its corresponding tab button.
     *
     * @param {HTMLElement} panel - The sphinx-tabs panel to activate
     * @returns {boolean} True if tab was activated, false otherwise
     */
    function activateTabForPanel(panel) {
        if (!panel) return false;

        const panelId = panel.getAttribute('id');
        if (!panelId) {
            console.warn('[localtoc_tabs_sync] Panel has no id attribute:', panel);
            return false;
        }

        // Find the tab button that controls this panel
        const tabButton = document.querySelector(`button.sphinx-tabs-tab[aria-controls="${panelId}"]`);
        if (!tabButton) {
            console.warn('[localtoc_tabs_sync] No tab button found for panel:', panelId);
            return false;
        }

        // Click the tab to activate it
        console.debug(`[localtoc_tabs_sync] Activating tab for panel: ${panelId}`);
        tabButton.click();
        return true;
    }

    /**
     * Check if an element has any collapsed parent sections.
     *
     * @param {HTMLElement} element - The element to check
     * @returns {boolean} True if element has a collapsed parent, false otherwise
     */
    function hasCollapsedParent(element) {
        let current = element;
        while (current && current !== document.body) {
            if (current.tagName === 'LI' && current.classList.contains('_collapse')) {
                return true;
            }
            current = current.parentElement;
        }
        return false;
    }

    /**
     * Expand all collapsed parent sections containing the target element.
     * This ensures navigation works even when content is in collapsed sections.
     *
     * @param {HTMLElement} element - The target element to expand parents for
     * @returns {number} Number of collapsed parents that were expanded
     */
    function expandParentSections(element) {
        // Walk up the DOM tree to find all parent <li> elements with _collapse class
        let current = element;
        let expandedCount = 0;
        const expandedElements = [];

        while (current && current !== document.body) {
            if (current.tagName === 'LI' && current.classList.contains('_collapse')) {
                // Change from collapsed to expanded
                current.classList.remove('_collapse');
                current.classList.add('_expand');
                expandedCount++;

                // Log which element we're expanding for debugging
                const elementInfo = current.querySelector('a')?.textContent || current.className || 'unknown';
                expandedElements.push(elementInfo);
            }
            current = current.parentElement;
        }

        if (expandedCount > 0) {
            console.debug(`[localtoc_tabs_sync] Expanded ${expandedCount} collapsed parent section(s):`, expandedElements);
        }

        return expandedCount;
    }

    /**
     * Handle click on localtoc links with fallback navigation.
     * If the target anchor doesn't exist, try all other group IDs.
     *
     * @param {Event} event - The click event on a localtoc link
     */
    function handleLocaltocLinkClick(event) {
        const link = event.currentTarget;
        const href = link.getAttribute('href');

        if (!href || !href.startsWith('#')) {
            return; // Let browser handle normally
        }

        const targetId = href.substring(1);

        // Defensive: Search for target in all tab panels for the current die (even if section is collapsed)
        // There are multiple tab sections on the page, all with the same die names
        // We want to find the target even if its section is collapsed - browser will expand it on navigation
        // But we still filter by current die to avoid navigating to a different die's tab

        // Get all panels that match the current die (based on their name attribute matching the active die)
        // CRITICAL: When user clicks active tab to collapse accordion, all tabs get aria-selected="false"
        // In this case, use currentActiveDieEncoded as fallback - panel names are base64-encoded!
        const activeTabButton = document.querySelector('button.sphinx-tabs-tab[aria-selected="true"]');
        const activeDieNameEncoded = activeTabButton ? activeTabButton.getAttribute('name') : currentActiveDieEncoded;

        console.debug(`[localtoc_tabs_sync] Handling link click for target: ${targetId}, activeDieNameEncoded: ${activeDieNameEncoded}`);

        // Dump all sphinx-tabs-panel names for debugging (verbose - only when detailed debug enabled)
        if (ACTIVATE_DETAILED_DEBUG_INFO) {
            const allPanels = document.querySelectorAll('.sphinx-tabs-panel[role="tabpanel"]');
            console.debug(`[localtoc_tabs_sync] All sphinx-tabs-panel names on page:`,
                Array.from(allPanels).map(panel => ({
                    name: panel.getAttribute('name'),
                    id: panel.getAttribute('id'),
                    hidden: panel.hasAttribute('hidden')
                }))
            );
        }

        // Find all panels matching the current die name
        // IMPORTANT: Don't filter by [hidden] - we need to find panels even when accordion is collapsed!
        // Both activeDieNameEncoded and currentActiveDieEncoded are base64-encoded
        const dieNameToQuery = activeDieNameEncoded || currentActiveDieEncoded;

        if (!dieNameToQuery) {
            // This should never happen - means no tab is selected AND we haven't tracked any die yet
            // Defensive: prevent navigation to wrong die by returning early
            console.error('[localtoc_tabs_sync] No die name available for link navigation - this should not happen');
            return; // Let browser handle navigation normally (will fail to find anchor)
        }

        const currentDiePanels = document.querySelectorAll(`.sphinx-tabs-panel[role="tabpanel"][name="${dieNameToQuery}"]`);

        console.debug(`[localtoc_tabs_sync] Found ${currentDiePanels.length} panels for current die: ${dieNameToQuery}`);

        // Try to find target in any panel for the current die
        let targetElement = null;
        for (const panel of currentDiePanels) {
            targetElement = panel.querySelector(`#${CSS.escape(targetId)}`);
            if (targetElement) {
                break; // Found it
            }
        }

        // If target exists in any panel for current die, expand parent sections and navigate
        // Note: This check succeeds for most elements including functions (where group ID is on <dt>)
        // and some types. However, for certain type structures (e.g., enums with deeply nested spans),
        // the querySelector may fail to find the element when panels are collapsed, causing a fallback
        // to the alternate group IDs path below.
        if (targetElement) {
            // Check visibility status
            const visibility = checkElementVisibility(targetElement);

            console.debug(`[localtoc_tabs_sync] Target found: ${targetId}`, {
                hasHiddenPanel: visibility.hasHiddenPanel,
                hasCollapsedParent: visibility.hasCollapsedParent,
                panelId: visibility.hiddenPanel?.getAttribute('id') || 'none'
            });

            const needsIntervention = visibility.hasHiddenPanel || visibility.hasCollapsedParent;

            if (needsIntervention) {
                // Prevent default navigation - we'll handle it manually after making content visible
                event.preventDefault();

                console.debug(`[localtoc_tabs_sync] Preventing default navigation for: ${targetId}`);

                // Activate hidden tab if needed
                if (visibility.hasHiddenPanel) {
                    const activated = activateTabForPanel(visibility.hiddenPanel);
                    if (!activated) {
                        console.error(`[localtoc_tabs_sync] Failed to activate tab for panel`);
                    }
                }

                // Expand any collapsed parent sections
                if (visibility.hasCollapsedParent) {
                    const expandedCount = expandParentSections(targetElement);
                    if (expandedCount === 0) {
                        console.warn(`[localtoc_tabs_sync] Expected collapsed parents but none were found to expand for: ${targetId}`);
                    }
                }

                // Navigate after a short delay to allow DOM to update
                // Use requestAnimationFrame to ensure CSS changes are applied
                requestAnimationFrame(() => {
                    console.debug(`[localtoc_tabs_sync] Navigating to target: ${targetId}`);
                    window.location.hash = targetId;
                    targetElement.scrollIntoView({ behavior: 'smooth', block: 'start' });
                });
            } else {
                console.debug(`[localtoc_tabs_sync] No intervention needed, letting browser handle navigation for: ${targetId}`);
            }

            return;
        }        // Target doesn't exist - try all other group IDs
        event.preventDefault();

        const allGroupIdsStr = link.getAttribute('data-all-group-ids');
        const allGroupIds = allGroupIdsStr ? allGroupIdsStr.split(',') : [];

        // Try each group ID in order, searching across all panels for current die (even collapsed)
        for (const groupId of allGroupIds) {
            if (groupId === targetId) {
                continue; // Skip the one we already tried
            }

            // Check all current die panels (visible or hidden) for this group ID
            let element = null;
            for (const panel of currentDiePanels) {
                element = panel.querySelector(`#${CSS.escape(groupId)}`);
                if (element) {
                    break; // Found it
                }
            }

            if (element) {
                // Found a valid alternate in current die panels - check visibility and handle expansion
                // This fallback path is critical for types/enums where the initial querySelector failed
                // to find the target (e.g., when panel is collapsed). By checking alternate group IDs,
                // we can locate the element and handle panel expansion just like the main path above.
                console.debug(`[localtoc_tabs_sync] Found alternate group ID: ${groupId}`);

                const visibility = checkElementVisibility(element);

                if (visibility.hasHiddenPanel) {
                    // Panel is collapsed/hidden - activate/expand it
                    console.debug(`[localtoc_tabs_sync] Expanding collapsed panel for current die`);
                    const activated = activateTabForPanel(visibility.hiddenPanel);
                    if (!activated) {
                        console.error(`[localtoc_tabs_sync] Failed to expand panel`);
                        continue; // Try next group ID
                    }
                }

                // Expand any collapsed parent sections (for globaltoc collapsible sections)
                const expandedCount = expandParentSections(element);
                if (expandedCount === 0) {
                    console.debug(`[localtoc_tabs_sync] No collapsed parents found for alternate: ${groupId}`);
                }

                // Navigate after a short delay to allow panel expansion
                requestAnimationFrame(() => {
                    console.debug(`[localtoc_tabs_sync] Navigating to alternate target: ${groupId}`);
                    window.location.hash = groupId;
                    element.scrollIntoView({ behavior: 'smooth', block: 'start' });
                });
                return;
            }
        }

        // No valid anchor found - mark link as unavailable and show user feedback
        // Defensive: This should already be set by updateLocaltocLinks(), but ensure it's applied
        link.classList.add('localtoc-link-unavailable');
        console.warn(`No valid anchor found for any group ID: ${allGroupIds.join(', ')}`);

        // Display a user-friendly notification
        const linkText = link.textContent.trim();
        const message = currentActiveDie
            ? `The content "${linkText}" is not available for ${currentActiveDie}.\n\nPlease switch to a different tab to view this content.`
            : `The content "${linkText}" is not available for the currently selected variant.`;

        alert(message);
    }

    /**
     * Handle tab switch events.
     * Triggered when sphinx-tabs activates a new tab (detected via MutationObserver).
     */
    function handleTabSwitch() {
        // Find the currently active tab button
        const activeTabButton = document.querySelector('button.sphinx-tabs-tab[aria-selected="true"]');
        if (!activeTabButton) {
            console.warn('[localtoc_tabs_sync] No active tab button found during tab switch handling');
            return;
        }

        // Extract die name from button text and store encoded name
        const die = extractDieFromTabButton(activeTabButton);
        const encodedName = activeTabButton.getAttribute('name');
        if (die && die !== currentActiveDie) {
            currentActiveDie = die;
            currentActiveDieEncoded = encodedName;
            updateLocaltocLinks();
        }
    }

    /**
     * Set up MutationObserver to monitor tab switches.
     * Watches for aria-selected attribute changes on sphinx-tabs buttons.
     *
     * Note: A page may have multiple sphinx-tabs sections (e.g., one per API category),
     * each with one sphinx-tabs container holding the same set of die tabs
     * (STM32C562xx, STM32C5A3xx, STM32C542xx).
     * These tab sets are synchronized by sphinx-tabs - clicking a die tab in one section
     * automatically activates the same die tab in all other sections on the page.
     *
     * We install one MutationObserver per sphinx-tabs container to detect when any
     * tab button's aria-selected attribute changes, which triggers updateLocaltocLinks()
     * to retarget all localtoc links for the newly active die.
     */
    function setupMutationObserver() {
        // Find all sphinx-tabs containers (one container per section on the page)
        const tabsContainers = document.querySelectorAll('.sphinx-tabs');        // Create one observer for each tabs container
        tabsContainers.forEach(tabsContainer => {
            const observer = new MutationObserver(mutationsList => {
                mutationsList.forEach(mutation => {
                    if (mutation.type === 'attributes' && mutation.attributeName === 'aria-selected') {
                        handleTabSwitch();
                    }
                });
            });

            // Observe changes in attributes and child elements within the container
            observer.observe(tabsContainer, {
                attributes: true,
                childList: true,
                subtree: true
            });
        });
    }

    /**
     * Initialize the tab synchronization system.
     * 1. Find all sphinx-tabs buttons
     * 2. Attach click listeners to tabs
     * 3. Attach click listeners to localtoc links for fallback navigation
     * 4. Determine initial active die from aria-selected="true"
     * 5. Update localtoc links to match the initially active tab
     *
     * Note: sphinx-tabs persists the active tab selection across page navigations.
     * If user switched to Tab B on Page A, then navigates to Page B, sphinx-tabs
     * will automatically activate Tab B on Page B load. However, the HTML post-processing
     * generated links pointing to the default tab, so we must update them on page load
     * to match the persisted active tab.
     */
    function initialize() {
        // Check if there are any tabs on this page
        const tabsContainers = document.querySelectorAll('.sphinx-tabs');
        if (tabsContainers.length === 0) {
            return; // No tabs on this page
        }

        // Set up MutationObserver to watch for tab switches
        setupMutationObserver();

        // Attach click listeners to localtoc links for fallback navigation
        const localtoc = document.querySelector('.localtoc');
        if (localtoc) {
            // data-cpp-id is only present on links processed by breathe and rewritten by html.py
            const links = localtoc.querySelectorAll('a[data-cpp-id]');
            links.forEach(link => {
                link.addEventListener('click', handleLocaltocLinkClick);
            });
        }

        // Find the initially active tab (aria-selected="true")
        // This may not be the default tab if sphinx-tabs persisted a different selection
        const activeTabButton = document.querySelector('button.sphinx-tabs-tab[aria-selected="true"]');
        if (activeTabButton) {
            const die = extractDieFromTabButton(activeTabButton);
            const encodedName = activeTabButton.getAttribute('name');
            if (die) {
                currentActiveDie = die;
                currentActiveDieEncoded = encodedName;
                updateLocaltocLinks(); // Update links to match the active tab
            }
        }
    }

    // Initialize when DOM is ready
    if (document.readyState === 'loading') {
        document.addEventListener('DOMContentLoaded', initialize);
    } else {
        // DOM already loaded
        initialize();
    }

    // ========================================================================
    // Cross-Page Type Link Navigation
    // ========================================================================
    //
    // This section handles cross-page navigation for function signature parameter type links.
    // It is kept in the same file as localtoc synchronization because:
    //
    // 1. Code reuse: Reuses extractDieFromTabButton() defined above
    // 2. Same scope: Needed on the same pages where localtoc sync is included
    // 3. Shared purpose: Both implement tab-aware navigation for multi-die docs
    // 4. Single inclusion: Simplifies post-processing (only one JS file to include)
    //
    // Unlike *_rewrite.js files (how_to_use_rewrite.js, use_cases_rewrite.js) which are
    // page-type-specific, this functionality is needed on ALL pages that already include
    // localtoc_tabs_sync.js (all *_exported_functions.html pages).
    //
    // DETAILED ALGORITHM
    // ==================
    // When user clicks a type link in a function signature (e.g., hal_i3c_handle_t parameter):
    //
    // 1. ONCLICK INTERCEPTION:
    //    - Link has onclick="handleCrossPageTypeLinkClick(event, this); return false;"
    //    - Handler is called before browser navigates
    //
    // 2. SAFETY CHECKS:
    //    - Verify link has data-cpp-id attribute (post-processed link)
    //    - Verify href contains '#' (has anchor)
    //    - If not, allow default navigation (return true)
    //
    // 3. EXTRACT TARGET INFORMATION:
    //    - Split href into page path and anchor fragment
    //    - Example: "hal_i3c_exported_types.html#STM32C562xx_group__I3C__Types_1ga..."
    //      -> targetPage = "hal_i3c_exported_types.html"
    //      -> currentGroupId = "STM32C562xx_group__I3C__Types_1ga..."
    //
    // 4. DETERMINE USER'S DIE PREFERENCE:
    //    - Check active tab button (aria-selected="true") on current page
    //    - Extract die name from button text (e.g., "STM32C5A3xx")
    //    - Fallback to sessionStorage if no active tab (rare edge case)
    //    - If no preference found, allow default navigation (return true)
    //
    // 5. OPTIMIZATION CHECK:
    //    - If currentGroupId already contains preferredDie, no rewrite needed
    //    - Allow default navigation (return true)
    //
    // 6. FIND MATCHING DIE VARIANT:
    //    - Extract data-all-group-ids attribute (comma-separated list)
    //    - Search for group ID containing preferredDie
    //    - Example: "STM32C562xx_group__...,STM32C5A3xx_group__...,STM32C542xx_group__..."
    //      -> Find "STM32C5A3xx_group__..." when preferredDie = "STM32C5A3xx"
    //
    // 7. REWRITE OR ALERT:
    //    - If match found:
    //      * Prevent default navigation (event.preventDefault() implicit via return false)
    //      * Rewrite window.location.href to targetPage + '#' + preferredGroupId
    //      * Browser navigates to rewritten URL
    //    - If no match:
    //      * Type not available for preferred die
    //      * Show alert to user
    //      * Prevent navigation (return false)
    //
    // EXAMPLE:
    // User on STM32C5A3xx tab clicks link to hal_i3c_handle_t type:
    //   Initial href: "hal_i3c_exported_types.html#STM32C562xx_group__I3C__Types_1ga123"
    //   Preferred die: "STM32C5A3xx" (from active tab)
    //   data-all-group-ids: "STM32C562xx_group__I3C__Types_1ga123,STM32C5A3xx_group__I3C__Types_1ga456,..."
    //   -> Find "STM32C5A3xx_group__I3C__Types_1ga456"
    //   -> Navigate to "hal_i3c_exported_types.html#STM32C5A3xx_group__I3C__Types_1ga456"
    //   -> Target page shows STM32C5A3xx variant of the type
    //
    // ========================================================================

    /**
     * Handle cross-page type link clicks (function signature parameter types).
     *
     * This function intercepts clicks on type links in function signatures and rewrites
     * the target URL to match the user's currently active die/variant preference.
     *
     * Called by onclick="return handleCrossPageTypeLinkClick(event, this);"
     *
     * @param {Event} event - The click event
     * @param {HTMLElement} link - The clicked link element
     * @returns {boolean} True to allow default navigation, false to prevent it
     */
    window.handleCrossPageTypeLinkClick = function(event, link) {
        console.debug('[cross-page-links] Handler invoked');
        console.debug('[cross-page-links] Link element:', link);
        console.debug('[cross-page-links] Link attributes:', {
            href: link.getAttribute('href'),
            dataCppId: link.getAttribute('data-cpp-id'),
            dataAllGroupIds: link.getAttribute('data-all-group-ids'),
            onclick: link.getAttribute('onclick')
        });

        // Safety check: verify link was post-processed
        if (!link.hasAttribute('data-cpp-id')) {
            console.debug('[cross-page-links] Link missing data-cpp-id - allowing default navigation');
            return true; // Not post-processed, allow default navigation
        }

        const href = link.getAttribute('href');
        if (!href || !href.includes('#')) {
            console.debug('[cross-page-links] Invalid href - allowing default navigation');
            return true; // Invalid href, allow default navigation
        }

        // Extract target page and current group ID from href
        const hashIndex = href.indexOf('#');
        const targetPage = href.substring(0, hashIndex);
        const currentGroupId = href.substring(hashIndex + 1);
        console.debug('[cross-page-links] Target page:', targetPage);
        console.debug('[cross-page-links] Current group ID:', currentGroupId);

        // Determine user's preferred die from current page's active tab
        let preferredDie = null;

        // Try to find active tab button on current page
        const activeTabButton = document.querySelector('button.sphinx-tabs-tab[aria-selected="true"]');
        if (activeTabButton) {
            preferredDie = extractDieFromTabButton(activeTabButton);
            console.debug('[cross-page-links] Found active tab, preferred die:', preferredDie);
        } else {
            // Fallback to sessionStorage (rare edge case - should always have active tab)
            const storedTab = sessionStorage.getItem('sphinx-tabs-last-selected');
            if (storedTab) {
                try {
                    preferredDie = atob(storedTab); // Decode base64
                    console.debug('[cross-page-links] Decoded from sessionStorage, preferred die:', preferredDie);
                } catch (e) {
                    console.warn('[cross-page-links] Failed to decode stored tab preference:', e);
                }
            }
        }

        if (!preferredDie) {
            console.debug('[cross-page-links] No preferred die found - allowing default navigation');
            return true; // No preference - allow default navigation
        }

        // Optimization: check if href already points to preferred die
        if (currentGroupId.includes(preferredDie)) {
            console.debug('[cross-page-links] href already points to preferred die - allowing default navigation');
            return true; // Already correct - allow default navigation
        }

        // Find matching die variant in data-all-group-ids
        const allGroupIdsStr = link.getAttribute('data-all-group-ids');
        if (!allGroupIdsStr) {
            console.debug('[cross-page-links] No data-all-group-ids attribute - allowing default navigation');
            return true; // No group IDs available, allow default navigation
        }

        const allGroupIds = allGroupIdsStr.split(',');
        console.debug('[cross-page-links] All group IDs:', allGroupIds);
        let preferredGroupId = null;

        for (const groupId of allGroupIds) {
            if (groupId.includes(preferredDie)) {
                preferredGroupId = groupId;
                console.debug('[cross-page-links] Found matching group ID:', preferredGroupId);
                break;
            }
        }

        if (preferredGroupId) {
            // Rewrite navigation target
            const newHref = targetPage + '#' + preferredGroupId;
            console.debug('[cross-page-links] Rewriting navigation to:', newHref);
            window.location.href = newHref;
            return false; // Prevent default navigation
        } else {
            // Type not available for preferred die
            console.debug('[cross-page-links] Type not available for preferred die:', preferredDie);
            alert('This type may not be available for ' + preferredDie);
            return false; // Prevent navigation to wrong die
        }
    };

})();
