// ==========================================
// NotesPane Kit — Markdown with Wikilinks
// ==========================================
// Renders markdown content via marked + DOMPurify,
// then post-processes wikilinks into clickable chips
// and transclusion blocks.
// Independently importable.

const WIKILINK_RE = /(!?)\[\[([^\[\]|]+?)(?:\|([^\]]+?))?\]\]/g;

/**
 * Render markdown with wikilink support.
 *
 * @param {string} content — raw markdown
 * @param {{ onLinkClick?: (title: string) => void }} opts
 * @returns {{ html: string, wikilinks: Array<{title: string, display: string, isTransclusion: boolean}> }}
 */
export function renderNoteMarkdown(content, opts = {}) {
    if (!content) return { html: '', wikilinks: [] };

    // 1. Render markdown
    let rendered = '';
    if (window.marked) {
        try {
            rendered = window.marked.parse(content, { breaks: true, gfm: true });
        } catch {
            rendered = _escapeHtml(content).replace(/\n/g, '<br>');
        }
    } else {
        rendered = _escapeHtml(content).replace(/\n/g, '<br>');
    }

    // 2. Sanitize
    if (window.DOMPurify) {
        rendered = window.DOMPurify.sanitize(rendered, {
            ADD_ATTR: ['target', 'rel'],
        });
    }

    // 3. Extract and replace wikilinks
    const wikilinks = [];
    rendered = rendered.replace(WIKILINK_RE, (_match, bang, title, display) => {
        const titleTrimmed = title.trim();
        const displayText = display ? display.trim() : titleTrimmed;
        const isTransclusion = bang === '!';

        wikilinks.push({ title: titleTrimmed, display: displayText, isTransclusion });

        if (isTransclusion) {
            return `<div class="sw-notes-pane__transclusion" data-title="${_escapeAttr(titleTrimmed)}">` +
                `<div class="sw-notes-pane__transclusion-header">` +
                `<span class="sw-notes-pane__wikilink sw-notes-pane__wikilink--transclusion" ` +
                `data-link-title="${_escapeAttr(titleTrimmed)}">` +
                `\u2197 ${_escapeHtml(displayText)}</span></div>` +
                `<div class="sw-notes-pane__transclusion-content">Loading\u2026</div></div>`;
        }

        return `<span class="sw-notes-pane__wikilink" ` +
            `data-link-title="${_escapeAttr(titleTrimmed)}">${_escapeHtml(displayText)}</span>`;
    });

    return { html: rendered, wikilinks };
}

/**
 * Attach click handlers to wikilink elements inside a container.
 * @param {HTMLElement} container
 * @param {(title: string) => void} onLinkClick
 */
export function attachWikilinkHandlers(container, onLinkClick) {
    if (!container || !onLinkClick) return;
    container.querySelectorAll('[data-link-title]').forEach(el => {
        el.style.cursor = 'pointer';
        el.addEventListener('click', (e) => {
            e.preventDefault();
            e.stopPropagation();
            onLinkClick(el.dataset.linkTitle);
        });
    });
}

/**
 * Resolve transclusion blocks — load content for ![[Title]] embeds.
 * @param {HTMLElement} container
 * @param {(title: string) => void} onLinkClick
 */
export async function resolveTransclusions(container, onLinkClick) {
    const embeds = container?.querySelectorAll('.sw-notes-pane__transclusion');
    if (!embeds?.length) return;

    const api = window.sw?.api?.notes;
    if (!api) return;

    const cache = {};
    for (const el of embeds) {
        const title = el.dataset.title;
        const contentEl = el.querySelector('.sw-notes-pane__transclusion-content');
        if (!title || !contentEl) continue;

        try {
            let note = cache[title.toLowerCase()];
            if (!note) {
                const resp = await api.searchTitles(title, 1);
                const match = (resp || []).find(
                    n => n.title.toLowerCase() === title.toLowerCase()
                );
                if (!match) {
                    contentEl.innerHTML = '<span style="color:var(--text-3)">Note not found</span>';
                    continue;
                }
                note = await api.get(match.id);
                cache[title.toLowerCase()] = note;
            }
            // Render content (strip nested transclusions to prevent recursion)
            const safeContent = (note.content || '').replace(/!\[\[[^\]]+\]\]/g, (m) => {
                const inner = m.match(/!\[\[([^\]|]+)/)?.[1]?.trim() || '';
                return `[Embedded: ${inner}]`;
            });
            const { html } = renderNoteMarkdown(safeContent);
            contentEl.innerHTML = html;
            // Attach link handlers inside transclusion
            if (onLinkClick) attachWikilinkHandlers(contentEl, onLinkClick);
        } catch {
            contentEl.innerHTML = '<span style="color:var(--text-3)">Failed to load</span>';
        }
    }
}

/**
 * Extract headings from markdown content for outline/TOC.
 * @param {string} content — raw markdown
 * @returns {Array<{level: number, text: string, id: string}>}
 */
export function extractHeadings(content) {
    if (!content) return [];
    const headings = [];
    const lines = content.split('\n');
    for (const line of lines) {
        const match = line.match(/^(#{1,3})\s+(.+)/);
        if (match) {
            const text = match[2].trim();
            const id = text.toLowerCase().replace(/[^\w]+/g, '-').replace(/^-|-$/g, '');
            headings.push({ level: match[1].length, text, id });
        }
    }
    return headings;
}

function _escapeHtml(str) {
    const el = document.createElement('div');
    el.textContent = str;
    return el.innerHTML;
}

function _escapeAttr(str) {
    return str.replace(/&/g, '&amp;').replace(/"/g, '&quot;').replace(/</g, '&lt;').replace(/>/g, '&gt;');
}
