// ==========================================
// Chat Switchboard — CM6 Wikilink Extension
// ==========================================
// Provides:
//   1. ViewPlugin that decorates [[Title]] as clickable chips
//   2. Autocomplete source triggered by [[
//   3. Distinct styling for ![[transclusion]] markers
//
// Usage:
//   import { wikilinkExtension } from './wikilink.mjs';
//   const ext = wikilinkExtension({
//       onLink: (title) => { ... },
//       linkCompleter: async (query) => [{ label, id }],
//   });
// ==========================================

import {
    ViewPlugin, Decoration, WidgetType, EditorView,
} from '@codemirror/view';
import { RangeSetBuilder } from '@codemirror/state';
import { autocompletion } from '@codemirror/autocomplete';

// ── Wikilink Regex ──────────────────────────

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

// ── Widget: Clickable Link Chip ─────────────

class WikilinkWidget extends WidgetType {
    constructor(title, displayText, isTransclusion, onLink) {
        super();
        this.title = title;
        this.displayText = displayText || title;
        this.isTransclusion = isTransclusion;
        this.onLink = onLink;
    }

    toDOM() {
        const chip = document.createElement('span');
        chip.className = this.isTransclusion
            ? 'cm-wikilink cm-wikilink-transclusion'
            : 'cm-wikilink';
        chip.textContent = (this.isTransclusion ? '↗ ' : '') + this.displayText;
        chip.title = this.isTransclusion
            ? `Embed: ${this.title}`
            : `Link: ${this.title}`;
        chip.addEventListener('click', (e) => {
            e.preventDefault();
            e.stopPropagation();
            if (this.onLink) this.onLink(this.title);
        });
        return chip;
    }

    eq(other) {
        return this.title === other.title
            && this.displayText === other.displayText
            && this.isTransclusion === other.isTransclusion;
    }

    ignoreEvent() { return false; }
}

// ── ViewPlugin: Decorate [[links]] ──────────

function wikilinkDecoPlugin(onLink) {
    return ViewPlugin.fromClass(class {
        decorations;

        constructor(view) {
            this.decorations = this.build(view);
        }

        update(update) {
            if (update.docChanged || update.viewportChanged) {
                this.decorations = this.build(update.view);
            }
        }

        build(view) {
            const builder = new RangeSetBuilder();
            const doc = view.state.doc;
            const text = doc.toString();

            let match;
            WIKILINK_RE.lastIndex = 0;
            while ((match = WIKILINK_RE.exec(text)) !== null) {
                const from = match.index;
                const to = from + match[0].length;

                // Don't decorate if cursor is inside the link (let user edit)
                const sel = view.state.selection.main;
                if (sel.from >= from && sel.from <= to) continue;

                const isTransclusion = match[1] === '!';
                const title = match[2].trim();
                const displayText = match[3] ? match[3].trim() : '';

                builder.add(from, to, Decoration.replace({
                    widget: new WikilinkWidget(title, displayText, isTransclusion, onLink),
                }));
            }

            return builder.finish();
        }
    }, {
        decorations: (v) => v.decorations,
    });
}

// ── Autocomplete: [[ trigger ────────────────

function wikilinkAutocomplete(linkCompleter) {
    return autocompletion({
        override: [
            async (ctx) => {
                // Look for [[ before the cursor
                const line = ctx.state.doc.lineAt(ctx.pos);
                const textBefore = ctx.state.doc.sliceString(line.from, ctx.pos);
                const triggerMatch = textBefore.match(/\[\[([^\]]*?)$/);

                if (!triggerMatch) return null;

                const query = triggerMatch[1];
                const from = ctx.pos - query.length;

                if (!linkCompleter) return null;

                try {
                    const results = await linkCompleter(query);
                    if (!results || results.length === 0) return null;

                    return {
                        from,
                        options: results.map(r => ({
                            label: r.label || r.title,
                            apply: (view, completion, from, to) => {
                                // Check if ]] already exists after cursor (from closeBrackets auto-close)
                                const afterCursor = view.state.doc.sliceString(to, to + 2);
                                const endPos = afterCursor === ']]' ? to + 2 : to;
                                const insert = completion.label + ']]';
                                view.dispatch({
                                    changes: { from, to: endPos, insert },
                                    selection: { anchor: from + insert.length },
                                });
                            },
                        })),
                    };
                } catch (e) {
                    console.warn('[wikilink] autocomplete error:', e);
                    return null;
                }
            },
        ],
        activateOnTyping: true,
    });
}

// ── Theme: Wikilink Chip Styles ─────────────

const wikilinkTheme = EditorView.baseTheme({
    '.cm-wikilink': {
        display: 'inline-block',
        padding: '1px 6px',
        margin: '0 1px',
        borderRadius: '4px',
        backgroundColor: 'rgba(var(--accent-rgb, 99, 102, 241), 0.15)',
        color: 'var(--accent, #6366f1)',
        cursor: 'pointer',
        fontSize: '0.9em',
        fontWeight: '500',
        textDecoration: 'none',
        verticalAlign: 'baseline',
        '&:hover': {
            backgroundColor: 'rgba(var(--accent-rgb, 99, 102, 241), 0.25)',
        },
    },
    '.cm-wikilink-transclusion': {
        borderLeft: '2px solid var(--accent, #6366f1)',
        fontStyle: 'italic',
    },
});

// ── Public: Combined Extension ──────────────

/**
 * Create the wikilink CM6 extension bundle.
 *
 * @param {Object} opts
 * @param {Function} [opts.onLink]          - Called with (title) when a link chip is clicked
 * @param {Function} [opts.linkCompleter]   - async (query) => [{ label, id }]
 * @returns {Extension[]} Array of CM6 extensions
 */
export function wikilinkExtension(opts = {}) {
    const extensions = [
        wikilinkDecoPlugin(opts.onLink || null),
        wikilinkTheme,
    ];

    if (opts.linkCompleter) {
        extensions.push(wikilinkAutocomplete(opts.linkCompleter));
    }

    return extensions;
}
