// Copyright (c) 2026 Modelware. All rights reserved.
import { createMarkdownRendererRegistry } from '../renderers/registry.js';
import { setIriLabelSnapshot } from '../renderers/renderer.js';
const SUPPORTED = new Set(['table', 'tree', 'graph', 'chart', 'diagram', 'list', 'text', 'matrix', 'table-editor']);
let wikilinkPreviewCard;
let wikilinkPreviewHideTimer;
let wikilinkPreviewRequestToken = 0;
let tabPreviewModifierActive = false;
let activeWikilinkHover;
function parseJsonNode(id, fallback) {
    const node = document.getElementById(id);
    if (!node) {
        return fallback;
    }
    try {
        return JSON.parse(node.textContent ?? '');
    }
    catch {
        return fallback;
    }
}
function safeDecode(value) {
    try {
        return decodeURIComponent(value);
    }
    catch {
        return value;
    }
}
function normalizeWikiPathKey(raw) {
    return String(raw || '')
        .replace(/\\/g, '/')
        .replace(/^\/+/, '')
        .replace(/[/]+/g, '/')
        .replace(/\.html$/i, '')
        .replace(/^\.\//, '')
        .toLowerCase();
}
function resolveWikiHref(iri, wikilinkIndex, iriAliasIndex) {
    const text = String(iri || '').trim();
    if (!text) {
        return undefined;
    }
    const alias = iriAliasIndex[text]
        || iriAliasIndex[text.replace(/[.,;:!?]+$/, '')]
        || iriAliasIndex[safeDecode(text)];
    if (typeof alias === 'string' && alias.length > 0) {
        return alias;
    }
    const hashIndex = text.indexOf('#');
    const fragment = hashIndex >= 0 ? text.slice(hashIndex) : '';
    const iriWithoutFragment = hashIndex >= 0 ? text.slice(0, hashIndex) : text;
    let parsed;
    try {
        parsed = new URL(iriWithoutFragment);
    }
    catch {
        return undefined;
    }
    const rawPath = safeDecode((parsed.pathname || '').replace(/^\/+/, ''));
    const hostPath = `${(parsed.hostname || '').toLowerCase()}/${rawPath}`.replace(/^\/+/, '');
    const candidates = [normalizeWikiPathKey(hostPath), normalizeWikiPathKey(rawPath)]
        .filter((candidate, index, all) => candidate && all.indexOf(candidate) === index);
    for (const candidate of candidates) {
        const direct = wikilinkIndex[candidate];
        if (typeof direct === 'string' && direct.length > 0) {
            return direct + fragment;
        }
    }
    let bestMatch;
    for (const candidate of candidates) {
        for (const [key, href] of Object.entries(wikilinkIndex)) {
            if (!candidate.endsWith('/' + key) && candidate !== key && !key.endsWith('/' + candidate)) {
                continue;
            }
            if (!bestMatch || key.length > bestMatch.key.length) {
                bestMatch = { key, href };
            }
        }
    }
    if (bestMatch && bestMatch.href.length > 0) {
        return bestMatch.href + fragment;
    }
    if (fragment) {
        const currentPath = normalizeWikiPathKey((window.location && window.location.pathname) || '');
        if (currentPath && candidates.some((candidate) => candidate === currentPath)) {
            return fragment;
        }
    }
    return undefined;
}
function applyWikilinks(scope, wikilinkIndex, iriAliasIndex, linkingEnabled) {
    const links = Array.from(scope.querySelectorAll('a.wikilink[iri]'));
    for (const link of links) {
        const iri = link.getAttribute('iri') || '';
        const label = link.textContent || iri;
        if (!linkingEnabled) {
            const span = document.createElement('span');
            span.className = 'wikilink';
            span.setAttribute('iri', iri);
            span.textContent = label;
            link.replaceWith(span);
            continue;
        }
        const href = resolveWikiHref(iri, wikilinkIndex, iriAliasIndex);
        if (href) {
            link.href = href;
            continue;
        }
        const span = document.createElement('span');
        span.className = 'wikilink';
        span.setAttribute('iri', iri);
        span.textContent = label;
        link.replaceWith(span);
    }
}
function installWikilinkObserver(wikilinkIndex, iriAliasIndex, linkingEnabled) {
    const observer = new MutationObserver((mutations) => {
        for (const mutation of mutations) {
            for (const added of Array.from(mutation.addedNodes)) {
                if (!(added instanceof Element)) {
                    continue;
                }
                if (added.matches('a.wikilink[iri]')) {
                    applyWikilinks(added.parentElement ?? document, wikilinkIndex, iriAliasIndex, linkingEnabled);
                    continue;
                }
                if (added.querySelector('a.wikilink[iri]')) {
                    applyWikilinks(added, wikilinkIndex, iriAliasIndex, linkingEnabled);
                }
            }
        }
    });
    observer.observe(document.body, { childList: true, subtree: true });
}
function setupDownloadHandler() {
    window.addEventListener('md-download-file', (event) => {
        const detail = event.detail;
        if (!detail || typeof detail.filename !== 'string') {
            return;
        }
        const blob = new Blob([detail.content ?? ''], { type: 'text/plain;charset=utf-8' });
        const anchor = document.createElement('a');
        const objectUrl = URL.createObjectURL(blob);
        anchor.href = objectUrl;
        anchor.download = detail.filename;
        anchor.style.display = 'none';
        document.body.appendChild(anchor);
        anchor.click();
        anchor.remove();
        URL.revokeObjectURL(objectUrl);
    });
}
function setupIriNavigationHandler(wikilinkIndex, iriAliasIndex, linkingEnabled) {
    window.addEventListener('md-navigate-iri', (event) => {
        const detail = event.detail;
        const iri = typeof detail?.iri === 'string' ? detail.iri.trim() : '';
        if (!iri || !linkingEnabled) {
            return;
        }
        const href = resolveWikiHref(iri, wikilinkIndex, iriAliasIndex);
        if (!href) {
            return;
        }
        window.location.assign(href);
    });
}
function isHoverPreviewEnabled(event) {
    if (!event) {
        return false;
    }
    return event.altKey || tabPreviewModifierActive;
}
function normalizeHoverAnchorRect(value) {
    if (!value || typeof value !== 'object') {
        return undefined;
    }
    const obj = value;
    if (typeof obj.left !== 'number' || typeof obj.right !== 'number' ||
        typeof obj.top !== 'number' || typeof obj.bottom !== 'number' ||
        typeof obj.width !== 'number' || typeof obj.height !== 'number') {
        return undefined;
    }
    return {
        left: obj.left,
        right: obj.right,
        top: obj.top,
        bottom: obj.bottom,
        width: obj.width,
        height: obj.height,
    };
}
function ensureWikilinkPreviewCard() {
    if (wikilinkPreviewCard) {
        return wikilinkPreviewCard;
    }
    const card = document.createElement('div');
    card.className = 'oml-wikilink-preview-card';
    card.style.position = 'fixed';
    card.style.zIndex = '1200';
    card.style.display = 'none';
    card.style.width = 'min(640px, calc(100vw - 48px))';
    card.style.height = 'min(480px, calc(100vh - 48px))';
    card.style.overflow = 'hidden';
    card.style.padding = '0';
    card.style.border = '1px solid var(--vscode-editorWidget-border, #c8ccd1)';
    card.style.borderRadius = '10px';
    card.style.background = 'var(--vscode-editor-background, #ffffff)';
    card.style.color = 'var(--vscode-editor-foreground, #1f2328)';
    card.style.boxShadow = '0 8px 24px rgb(0 0 0 / 24%)';
    card.style.fontFamily = 'system-ui, -apple-system, Segoe UI, Roboto, sans-serif';
    card.addEventListener('mouseenter', () => {
        if (wikilinkPreviewHideTimer !== undefined) {
            window.clearTimeout(wikilinkPreviewHideTimer);
            wikilinkPreviewHideTimer = undefined;
        }
    });
    // Don't hide on mouse leave - only ESC closes the preview now
    document.body.appendChild(card);
    wikilinkPreviewCard = card;
    return card;
}
function scheduleHideWikilinkPreview() {
    wikilinkPreviewRequestToken += 1;
    if (wikilinkPreviewHideTimer !== undefined) {
        window.clearTimeout(wikilinkPreviewHideTimer);
        wikilinkPreviewHideTimer = undefined;
    }
    // Immediately hide the preview (no delay)
    if (wikilinkPreviewCard) {
        wikilinkPreviewCard.style.display = 'none';
        wikilinkPreviewCard.replaceChildren();
    }
}
async function scheduleIriPreview(iri, href, anchorRect) {
    if (wikilinkPreviewHideTimer !== undefined) {
        window.clearTimeout(wikilinkPreviewHideTimer);
        wikilinkPreviewHideTimer = undefined;
    }
    const token = ++wikilinkPreviewRequestToken;
    await new Promise((resolve) => window.setTimeout(resolve, 220));
    if (token !== wikilinkPreviewRequestToken) {
        return;
    }
    const card = ensureWikilinkPreviewCard();
    // Create iframe to show the linked page
    const iframe = document.createElement('iframe');
    // Add preview mode parameter to prevent nested previews
    const iframeSrc = new URL(href, window.location.href);
    iframeSrc.searchParams.set('_oml_preview', '1');
    iframe.src = iframeSrc.toString();
    iframe.style.width = '100%';
    iframe.style.height = '100%';
    iframe.style.border = 'none';
    iframe.style.borderRadius = '4px';
    iframe.style.background = 'var(--vscode-editor-background, #ffffff)';
    iframe.style.display = 'block';
    // Intercept clicks in the iframe to navigate the parent page
    iframe.addEventListener('load', () => {
        try {
            const iframeDoc = iframe.contentDocument || iframe.contentWindow?.document;
            if (!iframeDoc) {
                return;
            }
            // Remove download attributes from all links to prevent file downloads
            const allLinks = iframeDoc.querySelectorAll('a[download]');
            allLinks.forEach(link => link.removeAttribute('download'));
            // Add click listener to all links and interactive elements in the iframe
            iframeDoc.addEventListener('click', (event) => {
                const target = event.target;
                if (!(target instanceof Element)) {
                    return;
                }
                const link = target.closest('a[href]');
                if (!link || !(link instanceof HTMLAnchorElement)) {
                    return;
                }
                const linkHref = link.getAttribute('href');
                if (!linkHref) {
                    return;
                }
                // Allow internal anchor links within the iframe
                if (linkHref.startsWith('#')) {
                    return;
                }
                // Prevent any navigation in the iframe
                event.preventDefault();
                event.stopPropagation();
                event.stopImmediatePropagation();
                // Get the absolute URL, accounting for any base URL in the iframe
                const iframeLocation = iframe.contentWindow?.location.href;
                const absoluteUrl = new URL(linkHref, iframeLocation || iframe.src);
                // Remove the preview parameter for the main navigation
                absoluteUrl.searchParams.delete('_oml_preview');
                // Close the preview and navigate the parent page
                scheduleHideWikilinkPreview();
                // Navigate the parent window (not the iframe)
                const targetUrl = absoluteUrl.toString();
                window.location.assign(targetUrl);
                return false;
            }, true); // Use capture phase to catch events early
        }
        catch (error) {
            // If we can't access iframe content (CORS), silently fail
            console.warn('Could not access iframe content for click interception:', error);
        }
    });
    card.replaceChildren(iframe);
    card.style.display = 'block';
    const cardRect = card.getBoundingClientRect();
    const margin = 12;
    const left = Math.min(Math.max(16, anchorRect.left), Math.max(16, window.innerWidth - cardRect.width - 16));
    let top = anchorRect.bottom + margin;
    if (top + cardRect.height > window.innerHeight - 16) {
        top = Math.max(16, window.innerHeight - cardRect.height - 16);
    }
    card.style.left = `${left}px`;
    card.style.top = `${top}px`;
}
function setupWikilinkHoverPreview(wikilinkIndex, iriAliasIndex, linkingEnabled) {
    // Don't enable previews if we're already in preview mode (prevents nested previews)
    const urlParams = new URLSearchParams(window.location.search);
    if (urlParams.has('_oml_preview')) {
        return;
    }
    // Close preview when clicking anywhere outside the preview card
    document.addEventListener('click', (event) => {
        if (!wikilinkPreviewCard || wikilinkPreviewCard.style.display === 'none') {
            return;
        }
        const target = event.target;
        if (!(target instanceof Element)) {
            return;
        }
        // Check if click is outside the preview card
        if (!target.closest('.oml-wikilink-preview-card')) {
            scheduleHideWikilinkPreview();
            activeWikilinkHover = undefined;
        }
    }, true); // Use capture to catch clicks before they propagate
    // Handle hover events for wikilinks in text content
    document.body.addEventListener('mouseover', (event) => {
        const target = event.target instanceof Element
            ? event.target
            : (event.target instanceof Node ? event.target.parentElement : null);
        if (!target || target.closest('.oml-wikilink-preview-card')) {
            return;
        }
        const link = target.closest('a.wikilink[iri]');
        if (!link) {
            return;
        }
        const iri = link.getAttribute('iri')?.trim();
        const href = link.getAttribute('href')?.trim();
        if (!iri || !href || href === '#') {
            return;
        }
        activeWikilinkHover = { link, iri };
        if (isHoverPreviewEnabled(event)) {
            void scheduleIriPreview(iri, href, link.getBoundingClientRect());
        }
    });
    window.addEventListener('keydown', (event) => {
        // ESC key closes the preview
        if (event.key === 'Escape') {
            scheduleHideWikilinkPreview();
            activeWikilinkHover = undefined;
            return;
        }
        if (event.key === 'Tab') {
            tabPreviewModifierActive = true;
        }
        if (!activeWikilinkHover) {
            return;
        }
        if (!(event.altKey || event.key === 'Alt' || (event.key === 'Tab' && tabPreviewModifierActive))) {
            return;
        }
        const link = activeWikilinkHover.link;
        if (!link.isConnected || !link.matches(':hover')) {
            return;
        }
        const href = link.getAttribute('href')?.trim();
        if (!href || href === '#') {
            return;
        }
        void scheduleIriPreview(activeWikilinkHover.iri, href, link.getBoundingClientRect());
    });
    window.addEventListener('keyup', (event) => {
        if (event.key === 'Tab') {
            tabPreviewModifierActive = false;
        }
    });
    window.addEventListener('blur', () => {
        tabPreviewModifierActive = false;
    });
    // Handle hover events dispatched by renderers (diagram, graph, table, etc.)
    window.addEventListener('md-show-iri-hover', (event) => {
        if (!(event instanceof CustomEvent)) {
            return;
        }
        const eventTarget = event.target;
        if (eventTarget instanceof Element && eventTarget.closest('.oml-wikilink-preview-card')) {
            return;
        }
        const detail = event.detail;
        const iri = typeof detail?.iri === 'string' ? detail.iri.trim() : '';
        const anchorRect = normalizeHoverAnchorRect(detail?.anchorRect);
        const previewEnabled = detail?.previewEnabled === true;
        if (!iri || !anchorRect || !previewEnabled || !linkingEnabled) {
            return;
        }
        const href = resolveWikiHref(iri, wikilinkIndex, iriAliasIndex);
        if (!href || href === '#') {
            return;
        }
        void scheduleIriPreview(iri, href, anchorRect);
    });
}
function getMdKindFromCodeElement(code) {
    for (const className of Array.from(code.classList)) {
        if (!className.startsWith('language-')) {
            continue;
        }
        const language = className.slice('language-'.length).toLowerCase();
        if (SUPPORTED.has(language)) {
            return language;
        }
    }
    return undefined;
}
async function loadResult(manifestEntry, inlineResults) {
    if (manifestEntry.blockId && Object.prototype.hasOwnProperty.call(inlineResults, manifestEntry.blockId)) {
        return inlineResults[manifestEntry.blockId];
    }
    const response = await fetch(manifestEntry.path);
    if (!response.ok) {
        return { status: 'error', message: `Failed to load block result: ${manifestEntry.path}` };
    }
    return await response.json();
}
async function applyExecutionResults() {
    const inlineResults = parseJsonNode('oml-md-block-inline-results', {});
    const wikilinkIndex = parseJsonNode('oml-md-wikilink-index', {});
    const iriAliasIndex = parseJsonNode('oml-md-wikilink-iri-aliases', {});
    const wikilinkConfig = parseJsonNode('oml-md-wikilink-config', { linkingEnabled: false });
    const memberLabelSnapshot = parseJsonNode('oml-md-member-labels', {});
    setIriLabelSnapshot(memberLabelSnapshot);
    const linkingEnabled = Boolean(wikilinkConfig?.linkingEnabled);
    // Resolve wikilinks in regular markdown content (outside code-block panels).
    applyWikilinks(document, wikilinkIndex, iriAliasIndex, linkingEnabled);
    // Re-apply wikilinks for dynamic renderer re-renders (tables, filters, paging, etc.).
    installWikilinkObserver(wikilinkIndex, iriAliasIndex, linkingEnabled);
    setupIriNavigationHandler(wikilinkIndex, iriAliasIndex, linkingEnabled);
    setupWikilinkHoverPreview(wikilinkIndex, iriAliasIndex, linkingEnabled);
    const manifest = parseJsonNode('oml-md-block-manifest', []);
    if (!Array.isArray(manifest) || manifest.length === 0) {
        return;
    }
    const codeNodes = Array.from(document.querySelectorAll('pre > code'))
        .filter((code) => getMdKindFromCodeElement(code) !== undefined);
    if (codeNodes.length === 0) {
        return;
    }
    const registry = createMarkdownRendererRegistry();
    for (let index = 0; index < codeNodes.length && index < manifest.length; index += 1) {
        const code = codeNodes[index];
        const pre = code.parentElement;
        if (!pre) {
            continue;
        }
        try {
            const result = await loadResult(manifest[index], inlineResults);
            const panel = registry.render(result);
            // Resolve wikilinks newly introduced by dynamic block renderers.
            applyWikilinks(panel, wikilinkIndex, iriAliasIndex, linkingEnabled);
            pre.replaceWith(panel);
        }
        catch (error) {
            const panel = document.createElement('div');
            panel.className = 'oml-md-result oml-md-result-error';
            const message = document.createElement('div');
            message.className = 'oml-md-result-message';
            message.textContent = `Render error: ${error instanceof Error ? error.message : String(error)}`;
            panel.appendChild(message);
            pre.replaceWith(panel);
        }
    }
}
setupDownloadHandler();
void applyExecutionResults();
//# sourceMappingURL=browser-runtime.js.map