/*!
 * 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
 */
/**
 * Version and Language Switcher Fallback Handler
 *
 * Handles 404 errors when navigating between documentation versions or languages
 * by redirecting to the appropriate index.html page while preserving context.
 *
 * Implementation pattern: IIFE (Immediately Invoked Function Expression)
 * Benefits: Prevents global namespace pollution by encapsulating all functions
 * and variables in a private scope, avoiding conflicts with other scripts.
 *
 * URL Structure:
 *   https://<domain>/<scope>/<product>/<version>/<lang>/<page-path>
 *
 * Where:
 *   - domain: dev.st.com, qa-dev.st.com, stm32cubedocs-dev.st.com, etc.
 *   - scope: stm32cube-docs, st-edge-ai-docs, etc. (required, no extra folders between domain and scope)
 *   - product: Product identifier from docs-urls.json
 *   - version: Semantic version (1.0.0, 2.1.3, latest)
 *   - lang: ISO 639 language code (en, zh-cn, fr, ja, etc.)
 *   - page-path: Path to specific documentation page
 *
 * Production URL example:
 *   https://dev.st.com/stm32cube-docs/multi-version-test-doc/2.0.0/en/index.html
 *
 * Test deployment URL example:
 *   https://stm32cubedocs-dev.st.com/stm32cube-docs/multi-version-test-doc/2.0.0/en/index.html
 *
 * IMPORTANT: Test deployments must follow the same structure - no extra folders
 * between domain and scope. The scope (e.g., stm32cube-docs) must be the first
 * path segment after the domain.
 *
 * STMicroelectronics customization for Shibuya theme.
 */

(function() {
    'use strict';

    /**
     * Parse URL to extract documentation structure components.
     *
     * @param {string} url - Full URL or pathname
     * @returns {Object|null} Parsed components or null if invalid structure
     */
    function parseDocUrl(url) {
        try {
            const pathname = new URL(url, window.location.origin).pathname;
            const parts = pathname.split('/').filter(part => part !== '');

            // Expected structure: [scope, product, version, lang, ...page-path]
            // Example: ['stm32cube-docs', 'multi-version-test-doc', '2.0.0', 'en', 'docs', 'guide.html']

            if (parts.length < 4) {
                console.error('[version_language_fallback] URL does not have enough segments:', pathname);
                return null; // Not enough segments
            }

            // Find scope (stm32cube-docs, st-edge-ai-docs, etc.)
            const scopeIndex = parts.findIndex(part => part.includes('-docs'));
            if (scopeIndex === -1) {
                console.error('[version_language_fallback] Scope segment not found in URL:', pathname);
                return null;
            }

            const scope = parts[scopeIndex];
            const product = parts[scopeIndex + 1];
            const version = parts[scopeIndex + 2];
            const lang = parts[scopeIndex + 3];

            // Validate that we found all required components
            if (!product || !version || !lang) {
                console.error('[version_language_fallback] Missing product, version, or lang in URL:', pathname);
                return null;
            }

            return {
                scope: scope,
                product: product,
                version: version,
                lang: lang,
                scopeIndex: scopeIndex,
                parts: parts
            };
        } catch (e) {
            console.warn('Failed to parse documentation URL:', e);
            return null;
        }
    }

    /**
     * Check if a URL exists using a HEAD request.
     * This is the same proven approach as version_dropdown_preserve.js
     *
     * @param {string} url - The URL to check
     * @returns {Promise<boolean>} True if URL exists (status 200-299), false otherwise
     */
    function checkUrlExists(url) {
        return fetch(url, { method: 'HEAD' })
            .then(response => response.ok)
            .catch(() => false);
    }

    /**
     * Resolve 'latest' version to actual semantic version by parsing the trampoline redirect page.
     * When 'latest' is used, latest/<lang>/index.html is a trampoline generated from
     * redirection_template.html, which contains: let targetPath = '/2.0.0/en/index.html';
     * The version is extracted from the first path segment of targetPath.
     * Note: Fetch API doesn't follow HTML meta refresh redirects, only HTTP redirects.
     *
     * @param {Object} urlInfo - Parsed URL components
     * @param {string} lang - Target language
     * @returns {Promise<string|null>} Resolved version (e.g., '1.8.0') or null if resolution fails
     */
    function resolveLatestVersion(urlInfo, lang) {
        const latestIndexUrl = `/${urlInfo.scope}/${urlInfo.product}/latest/${lang}/index.html`;

        console.debug(`[Version resolution] Fetching: ${latestIndexUrl}`);

        return fetch(latestIndexUrl, {
            method: 'GET',
            redirect: 'follow' // Follow HTTP redirects (but not meta refresh)
        })
        .then(response => {
            console.debug(`[Version resolution] Response status: ${response.status}, ok: ${response.ok}`);
            console.debug(`[Version resolution] Final URL after redirects: ${response.url}`);

            if (!response.ok) {
                console.warn(`[Version resolution] Response not OK, status: ${response.status}`);
                return null;
            }

            // Get HTML content to parse meta refresh
            return response.text();
        })
        .then(html => {
            if (!html) {
                return null;
            }

            console.debug(`[Version resolution] HTML length: ${html.length} chars`);

            // Extract version from the targetPath variable in the trampoline page.
            // redirection_template.html format: let targetPath = '/2.0.0/en/index.html';
            // The version is the first path segment of the value.
            const jsTargetPathMatch = html.match(/(?:const|let|var)\s+targetPath\s*=\s*['"]\/([^\/'"]+)\//);

            if (jsTargetPathMatch && jsTargetPathMatch[1]) {
                const version = jsTargetPathMatch[1];
                console.debug(`[Version resolution] Found JavaScript targetPath, extracted version: ${version}`);

                if (version !== 'latest') {
                    console.debug(`[Version resolution] 'latest' resolved to: ${version}`);
                    return version;
                }
            } else {
                console.debug(`[Version resolution] No JavaScript targetPath found, trying meta refresh...`);

                // Fallback: Try meta refresh patterns
                // Example: <meta http-equiv="refresh" content="0; url=../1.8.0/en/index.html">
                let redirectUrl = null;

                // Try pattern 1: http-equiv first
                let match = html.match(/<meta\s+http-equiv=["']refresh["']\s+content=["'][^"']*url=([^"'\s>]+)["']/i);
                if (match) {
                    redirectUrl = match[1];
                }

                // Try pattern 2: content first
                if (!redirectUrl) {
                    match = html.match(/<meta\s+content=["'][^"']*url=([^"'\s>]+)["']\s+http-equiv=["']refresh["']/i);
                    if (match) {
                        redirectUrl = match[1];
                    }
                }

                if (redirectUrl) {
                    console.debug(`[Version resolution] Found meta refresh URL: ${redirectUrl}`);

                    // Resolve relative URL to absolute
                    const absoluteUrl = new URL(redirectUrl, latestIndexUrl).href;
                    const parsedRedirect = parseDocUrl(absoluteUrl);

                    if (parsedRedirect && parsedRedirect.version !== 'latest') {
                        console.debug(`[Version resolution] 'latest' resolved to: ${parsedRedirect.version}`);
                        return parsedRedirect.version;
                    }
                }
            }

            console.warn(`[Version resolution] Could not extract version from JavaScript or meta refresh`);
            return null;
        })
        .catch(error => {
            console.warn(`[Version resolution] Failed to resolve 'latest':`, error);
            return null;
        });
    }

    /**
     * Navigate to target URL with fallback if URL doesn't exist.
     * Checks URL existence before navigating, with fallback to index.html if not found.
     *
     * @param {string} targetUrl - The URL to navigate to
     * @param {string} fallbackUrl - The fallback URL if target doesn't exist
     */
    function navigateWithFallback(targetUrl, fallbackUrl) {
        checkUrlExists(targetUrl).then(exists => {
            if (exists) {
                console.debug(`[version_language_fallback] Target URL exists, navigating to: ${targetUrl}`);
                window.location.href = targetUrl;
            } else {
                console.info(`[version_language_fallback] Target URL not found, redirecting to fallback: ${fallbackUrl}`);
                displayRedirectMessage(fallbackUrl);
                setTimeout(() => {
                    window.location.href = fallbackUrl;
                }, 1500);
            }
        });
    }

    /**
     * Build fallback URL to index.html preserving version and language.
     *
     * @param {Object} urlInfo - Parsed URL components
     * @param {string} targetVersion - Target version (optional, uses urlInfo.version if not provided)
     * @param {string} targetLang - Target language (optional, uses urlInfo.lang if not provided)
     * @returns {string} Fallback URL
     */
    function buildFallbackUrl(urlInfo, targetVersion, targetLang) {
        if (!urlInfo) {
            return '/';
        }

        const version = targetVersion || urlInfo.version;
        const lang = targetLang || urlInfo.lang;

        // Build path: /<scope>/<product>/<version>/<lang>/index.html
        const pathParts = [urlInfo.scope, urlInfo.product, version, lang, 'index.html'];

        return '/' + pathParts.join('/');
    }

    /**
     * Display redirect message to user.
     *
     * @param {string} fallbackUrl - URL where user will be redirected
     */
    function displayRedirectMessage(fallbackUrl) {
        // Check if message already exists
        if (document.getElementById('st-404-redirect-msg')) {
            return;
        }

        const message = document.createElement('div');
        message.id = 'st-404-redirect-msg';

        const urlInfo = parseDocUrl(fallbackUrl);
        const versionLang = urlInfo ? `${urlInfo.version}/${urlInfo.lang}` : 'documentation';

        message.innerHTML = `
            <strong>Page not found</strong>
            <span class="st-redirect-subtitle">Redirecting to ${versionLang} homepage...</span>
        `;

        document.body.appendChild(message);
    }

    /**
     * Add click handlers to version switcher links.
     * Proactively checks if target URL exists before navigating.
     * Only runs if version switcher is present in the DOM.
     */
    function enhanceVersionSwitcher() {
        const versionContainer = document.querySelector('.nav-versions');
        if (!versionContainer) {
            return; // Version switcher disabled (offline mode)
        }

        const versionLinks = document.querySelectorAll('.nav-versions a');

        versionLinks.forEach(link => {
            link.addEventListener('click', (e) => {
                // In this handler, we override the default behavior to preserve the current language.
                // We use the link's href to get the target version, but keep the current page's language.
                // templateHref is the static link generated at build time (usually with "en" language).
                // It is used as a primary level fallback if we can't parse the current URL. It does not preserve language.
                // A second level of fallback exists to redirect to index.html in the target version with current language.
                // This second level of fallback is triggered if the specific page in target version doesn't exist.
                e.preventDefault(); // Prevent default navigation

                // Extract target version from the link href (e.g., "../../2.0.0/en/page.html")
                const templateHref = link.getAttribute('href');
                if (!templateHref) {
                    // **ERROR PATH 1**: Missing href attribute → SILENT FAILURE
                    // **NOTE**: This should NEVER happen with properly built documentation
                    // This indicates a bug in the Sphinx theme template generation
                    // Restriction: User stays on current page, no navigation occurs
                    // Cause: preventDefault() already called, then return exits without navigating
                    // User Experience: No visible feedback except console warning
                    console.warn('[version_language_fallback] Version link has no href attribute');
                    return;
                }

                const currentUrl = parseDocUrl(window.location.href);
                if (!currentUrl) {
                    // **ERROR PATH 2**: Current URL parsing failed → DIRECT NAVIGATION (bypasses 404 check)
                    // **NOTE**: Should NOT happen with proper deployment following standard URL structure
                    // Can occur if:
                    //   - User manually edits URL in browser address bar
                    //   - Documentation accessed from non-standard location (wrong folder structure)
                    //   - Deployment doesn't follow /<scope>/<product>/<version>/<lang>/<page> structure
                    // Restriction: No proactive URL check, no nice redirect message if page doesn't exist
                    // Example URLs that trigger this:
                    //   - Malformed: https://dev.st.com/invalid/structure/page.html (missing scope pattern)
                    //   - Missing segments: https://dev.st.com/stm32cube-docs/product/en/page.html (no version)
                    // User Experience:
                    //   - If target page exists => Success
                    //   - If target page doesn't exist => Browser's raw 404 page (not our custom message)
                    console.warn('[version_language_fallback] Cannot parse current URL, using template href as-is');
                    // Note: preventDefault() called earlier only blocks default link navigation,
                    // it doesn't prevent this programmatic navigation via window.location.href
                    window.location.href = templateHref;
                    return;
                }

                // Parse the template href to extract target version
                // The href is a relative URL like "../../2.0.0/en/page.html"
                // We need to resolve it to get the absolute URL, then extract the version
                const resolvedTemplateUrl = new URL(templateHref, window.location.href).href;
                const templateUrlParsed = parseDocUrl(resolvedTemplateUrl);

                if (!templateUrlParsed) {
                    // **ERROR PATH 3**: Template URL parsing failed => DIRECT NAVIGATION (bypasses 404 check)
                    // **NOTE**: This should NEVER happen with properly built documentation
                    // This indicates a bug in the version dropdown template generation (base.html)
                    // Restriction: No proactive URL check, no nice redirect message if page doesn't exist
                    // Example URLs that trigger this:
                    //   - Template href resolves to malformed URL (edge case, should be rare)
                    //   - Build-time error in version dropdown template generation
                    // User Experience:
                    //   - If target page exists => Success
                    //   - If target page doesn't exist => Browser's raw 404 page (not our custom message)
                    console.warn("[version_language_fallback] Cannot parse template URL to get target version, using template href as-is");
                    // Note: preventDefault() called earlier only blocks default link navigation,
                    // it doesn't prevent this programmatic navigation via window.location.href
                    window.location.href = templateHref;
                    return;
                }

                // Build target URL with CURRENT language (not the build-time "en")
                // This is the key fix: preserve the runtime language, not the template's hardcoded language
                const targetVersion = templateUrlParsed.version;
                const currentLang = currentUrl.lang; // Use current page's language

                // Extract page path (everything after /<scope>/<product>/<version>/<lang>/)
                // URL structure: /<scope>/<product>/<version>/<lang>/<page-path>
                // Example: ['stm32cube-docs', 'product', '1.0.0', 'en', 'docs', 'guide', 'tutorial.html']
                //           ^scopeIndex=0     ^+1        ^+2      ^+3   ^+4 (start of page path)
                // slice(scopeIndex + 4) extracts: ['docs', 'guide', 'tutorial.html']
                // join('/') produces: 'docs/guide/tutorial.html'
                const currentPagePath = currentUrl.parts.slice(currentUrl.scopeIndex + 4).join('/');

                // **HAPPY PATH**: All URL parsing succeeded, proceeding with smart navigation
                // This path provides:
                //   - Language preservation (uses current page's language, not template's)
                //   - Proactive page existence check (HEAD request before navigation)
                //   - Nice redirect message if page doesn't exist
                //   - Automatic fallback to index.html with 1.5s delay
                // Example successful flow:
                //   Current: https://dev.st.com/stm32cube-docs/product/1.0.0/fr/docs/guide.html
                //   Click: Switch to version 2.0.0
                //   Target: https://dev.st.com/stm32cube-docs/product/2.0.0/fr/docs/guide.html (preserves French)
                //   If 404: Shows message + redirects to /stm32cube-docs/product/2.0.0/fr/index.html

                // Special handling for 'latest': resolve to actual version first
                if (targetVersion === 'latest') {
                    console.debug(`[Version switch] Target is 'latest', resolving to actual version...`);

                    resolveLatestVersion(currentUrl, currentLang).then(resolvedVersion => {
                        if (resolvedVersion) {
                            // Build URL with resolved version
                            const resolvedTargetUrl = `/${currentUrl.scope}/${currentUrl.product}/${resolvedVersion}/${currentLang}/${currentPagePath}`;
                            const resolvedFallbackUrl = buildFallbackUrl(currentUrl, resolvedVersion, currentLang);

                            console.debug(`[Version switch] Using resolved version ${resolvedVersion}`);
                            console.debug(`[Version switch] Target: ${resolvedTargetUrl}, Fallback: ${resolvedFallbackUrl}`);

                            // Already on the resolved page - skip navigation to avoid an unnecessary reload
                            if (resolvedTargetUrl === window.location.pathname) {
                                console.debug(`[Version switch] Already on the resolved latest page, no navigation needed`);
                                return;
                            }
                            navigateWithFallback(resolvedTargetUrl, resolvedFallbackUrl);
                        } else {
                            // Resolution failed, fall back to 'latest' URLs (will redirect to index)
                            console.debug(`[Version switch] Failed to resolve 'latest', using latest URLs`);
                            const targetUrl = `/${currentUrl.scope}/${currentUrl.product}/latest/${currentLang}/${currentPagePath}`;
                            const fallbackUrl = buildFallbackUrl(currentUrl, 'latest', currentLang);

                            navigateWithFallback(targetUrl, fallbackUrl);
                        }
                    });
                    return; // Exit handler, async resolution continues above
                }

                // Build primary target URL: same page in target version with current language
                const targetUrl = `/${currentUrl.scope}/${currentUrl.product}/${targetVersion}/${currentLang}/${currentPagePath}`;

                // Build fallback URL: index.html in target version with current language
                const fallbackUrl = buildFallbackUrl(currentUrl, targetVersion, currentLang);

                console.debug(`[Version switch] Target: ${targetUrl}, Fallback: ${fallbackUrl}`);

                // Guard: skip navigation if already on the target page.
                // NOTE: This should normally never trigger for explicit version links, because the
                // current version is intentionally omitted from the version switcher dropdown —
                // there is no link to navigate from 2.0.0 back to 2.0.0.
                // The only realistic same-page case (clicking 'latest' while already on the latest
                // version) is handled earlier in the resolveLatestVersion branch above.
                // This guard is kept as a safety net against future theme changes or edge cases.
                if (targetUrl === window.location.pathname) {
                    console.debug(`[Version switch] Already on the target version's page, no navigation needed`);
                    return;
                }

                // Proactively check if target URL exists before navigating
                navigateWithFallback(targetUrl, fallbackUrl);
            });
        });
    }

    /**
     * Add click handlers to language switcher links.
     * Proactively checks if target URL exists before navigating.
     * Only runs if language switcher is present in the DOM.
     */
    function enhanceLanguageSwitcher() {
        const languageContainer = document.querySelector('.nav-languages');
        if (!languageContainer) {
            return; // Language switcher disabled (offline mode or single language)
        }

        const languageLinks = document.querySelectorAll('.nav-languages a');

        languageLinks.forEach(link => {
            link.addEventListener('click', (e) => {
                e.preventDefault(); // Prevent default navigation

                // Extract target language from the link href
                const targetHref = link.getAttribute('href');
                if (!targetHref) {
                    // **ERROR PATH 1**: Missing href attribute → SILENT FAILURE
                    // **NOTE**: This should NEVER happen with properly built documentation
                    // This indicates a bug in the language dropdown template generation
                    // Restriction: User stays on current page, no navigation occurs
                    // Same behavior as version switcher ERROR PATH 1
                    console.warn('[version_language_fallback] Language link has no href attribute');
                    return;
                }

                const currentUrl = parseDocUrl(window.location.href);
                if (!currentUrl) {
                    // **ERROR PATH 2**: Current URL parsing failed → DIRECT NAVIGATION (bypasses 404 check)
                    // **NOTE**: Should NOT happen with proper deployment following standard URL structure
                    // Can occur in same scenarios as version switcher ERROR PATH 2
                    // Restriction: No proactive URL check, no nice redirect message if page doesn't exist
                    // Example: User on malformed URL tries to switch language
                    //   Current: https://dev.st.com/invalid/structure/page.html
                    //   Target: Tries to navigate to French version
                    //   Result: Direct navigation, browser 404 if page doesn't exist                    // Note: preventDefault() called earlier only blocks default link navigation,
                    // it doesn't prevent this programmatic navigation via window.location.href                    window.location.href = targetHref;
                    return;
                }
                const targetUrl = parseDocUrl(new URL(targetHref, window.location.href).href);

                if (targetUrl) {
                    // **HAPPY PATH**: URL parsing succeeded, use navigateWithFallback for nice UX
                    // Build fallback URL for target language
                    const fallbackUrl = buildFallbackUrl(currentUrl, targetUrl.version, targetUrl.lang);

                    console.debug(`Language switch: checking if ${targetHref} exists...`);

                    // Proactively check if target URL exists before navigating
                    navigateWithFallback(targetHref, fallbackUrl);
                } else {
                    // **ERROR PATH 3**: Target URL parsing failed → DIRECT NAVIGATION (bypasses 404 check)
                    // **NOTE**: This should NEVER happen with properly built documentation
                    // This indicates a bug in the language dropdown template generation
                    // Restriction: No proactive URL check, no nice redirect message if page doesn't exist
                    // Example: Template generated invalid target href (rare edge case)
                    // User Experience:
                    //   - If target page exists → Success
                    //   - If target page doesn't exist → Browser's raw 404 page
                    // Note: preventDefault() called earlier only blocks default link navigation,
                    // it doesn't prevent this programmatic navigation via window.location.href
                    window.location.href = targetHref;
                }
            });
        });
    }

    /**
     * Initialize fallback handlers when DOM is ready.
     */
    function init() {
        // Enhance switchers with proactive URL checking (version_dropdown_preserve.js approach)
        enhanceVersionSwitcher();
        enhanceLanguageSwitcher();
    }

    // Run when DOM is ready
    if (document.readyState === 'loading') {
        // DOM not ready yet
        document.addEventListener('DOMContentLoaded', init);
    } else {
        // DOM already ready
        init();
    }
})();

