<script lang="ts">
    import { onMount, onDestroy } from 'svelte';
    import { browser } from '$app/environment';
    import { ensureCodeMirrorModules } from './codemirror_modules';

    interface Props {
        content?: string;
        placeholder?: string;
    }

    let { content = $bindable(''), placeholder = 'Start typing...' }: Props = $props();

    let editor_container: HTMLDivElement | undefined = $state();
    let editor_view: any;
    let cm: any; // Declare cm at the top level

    async function createEditor() {
        if (!browser) return;
        cm = await ensureCodeMirrorModules(); // Assign to the top-level cm
        if (!cm) return;

        // If an existing instance exists (HMR / remount), destroy it first
        if (editor_view && typeof editor_view.destroy === 'function') {
            try {
                editor_view.destroy();
            } catch (e) {
                /* ignore */
            }
            editor_view = null;
        }

        // Build extensions defensively
        const extensions = [
            cm.lineNumbers(),
            cm.highlightSpecialChars(),
            cm.history(),
            cm.foldGutter(),
            cm.drawSelection(),
            cm.dropCursor(),
            cm.EditorState_allowMultipleSelections.of(true),
            cm.indentOnInput(),
            cm.bracketMatching(),
            cm.closeBrackets(),
            cm.autocompletion(),
            cm.rectangularSelection(),
            cm.crosshairCursor(),
            cm.highlightActiveLine(),
            cm.highlightActiveLineGutter(),
            cm.EditorView_lineWrapping,
            cm.keymap.of([
                ...cm.defaultKeymap,
                ...cm.searchKeymap,
                ...cm.historyKeymap,
                ...cm.foldKeymap,
                ...cm.completionKeymap,
                ...cm.lintKeymap
            ]),
            cm.markdown ? cm.markdown({ base: cm.markdownLanguage }) : null,
            cm.EditorView && cm.EditorView.updateListener
                ? cm.EditorView.updateListener.of((update: any) => {
                      if (update.docChanged) content = update.state.doc.toString();
                  })
                : null
        ].filter(Boolean);

        // Create editor
        if (!editor_container) {
            console.error('Editor container not found.');
            return;
        }

        editor_view = new cm.EditorView({
            state: cm.EditorState.create({
                doc: content ?? '',
                extensions
            }),
            parent: editor_container as HTMLElement
        });
    }

    onMount(async () => {
        // ensure it's created only in browser and after modules resolved
        await createEditor();
    });

    onDestroy(() => {
        if (editor_view && typeof editor_view.destroy === 'function') {
            try {
                editor_view.destroy();
            } catch (e) {
                /* ignore */
            }
            editor_view = null;
        }
    });

    // Helper functions using the live editor_view (unchanged)
    const wrapSelection = (before: string, after: string = before) => {
        if (!editor_view) return;
        const state = editor_view.state;
        const changes = state.changeByRange((range: any) => {
            const isAlreadyWrapped =
                state.sliceDoc(range.from - before.length, range.from) === before &&
                state.sliceDoc(range.to, range.to + after.length) === after;

            if (isAlreadyWrapped) {
                return {
                    changes: [
                        { from: range.from - before.length, to: range.from, insert: '' },
                        { from: range.to, to: range.to + after.length, insert: '' }
                    ],
                    range: cm.EditorSelection.range(
                        range.from - before.length,
                        range.to - before.length
                    )
                };
            }

            return {
                changes: [
                    { from: range.from, insert: before },
                    { from: range.to, insert: after }
                ],
                range: cm.EditorSelection.range(
                    range.from + before.length,
                    range.to + before.length
                )
            };
        });
        editor_view.dispatch(changes);
        editor_view.focus();
    };

    const insertList = () => {
        if (!editor_view) return;
        const state = editor_view.state;
        const changes = state.changeByRange((range: any) => {
            const line = state.doc.lineAt(range.from);
            return {
                changes: [{ from: line.from, insert: '- ' }],
                range: cm.EditorSelection.range(range.from + 2, range.to + 2)
            };
        });
        editor_view.dispatch(changes);
        editor_view.focus();
    };
</script>

<div class="codemirror-wrapper border rounded">
    <div class="toolbar p-1 bg-gray-100 border-b">
        <button
            type="button"
            onclick={() => wrapSelection('**')}
            class="px-2 py-1 rounded hover:bg-gray-200"><b>B</b></button
        >
        <button
            type="button"
            onclick={() => wrapSelection('*')}
            class="px-2 py-1 rounded hover:bg-gray-200"><i>I</i></button
        >
        <button type="button" onclick={insertList} class="px-2 py-1 rounded hover:bg-gray-200"
            >List</button
        >
    </div>
    <div bind:this={editor_container} class="h-full min-h-[150px] overflow-auto"></div>
</div>
