<script lang="ts">
    /**
     * AE_Comp_Editor_CodeMirror.svelte
     * Consolidated CodeMirror 6 Editor for Aether Platform.
     * Combines technical power with a user-friendly Markdown toolbar.
     * Uses strictly snake_case and Svelte 5 Runes.
     */
    import { onMount, onDestroy, untrack } from 'svelte';
    import { browser } from '$app/environment';
    import { ensureCodeMirrorModules } from './codemirror_modules';
    import type { key_val } from '$lib/stores/ae_stores';

    // Icons (Standardized to Lucide where possible, or FontAwesome placeholders)
    import { Bold, Italic, List, Code, Maximize2 } from 'lucide-svelte';

    interface Props {
        content?: string;
        new_content?: string;
        placeholder?: string;
        theme_mode?: 'light' | 'dark';
        language?: 'markdown' | 'json' | 'html' | 'javascript';
        readonly?: boolean;
        show_line_numbers?: boolean;
        wrap_lines?: boolean;
        show_toolbar?: boolean;
        editor_view?: any; // $bindable for external control
        class_li?: string;
    }

    let {
        content = $bindable(''),
        new_content = $bindable(''),
        placeholder = 'Start typing...',
        theme_mode = 'light',
        language = 'markdown',
        readonly = false,
        show_line_numbers = false,
        wrap_lines = true,
        show_toolbar = true,
        editor_view = $bindable(),
        class_li = ''
    }: Props = $props();

    let editor_container: HTMLDivElement | undefined = $state();
    let cm: any = $state(); // CodeMirror modules cache

    async function create_editor() {
        if (!browser) return;
        
        cm = await ensureCodeMirrorModules();
        if (!cm) return;

        // Cleanup existing instance if HMR or remount occurs
        if (editor_view) {
            editor_view.destroy();
            editor_view = null;
        }

        const extensions = [
            cm.highlightSpecialChars(),
            cm.history(),
            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(),
            
            // Keymaps
            cm.keymap.of([
                ...cm.defaultKeymap,
                ...cm.searchKeymap,
                ...cm.historyKeymap,
                ...cm.foldKeymap,
                ...cm.completionKeymap,
                ...cm.lintKeymap
            ]),

            // Language Support
            language === 'markdown' ? cm.markdown({ base: cm.markdownLanguage }) : null,
            language === 'json' ? cm.languages.find((l: any) => l.name === 'json')?.load() : null,

            // Theme & Behavior
            theme_mode === 'dark' ? cm.oneDark : cm.EditorView.baseTheme(),
            cm.EditorView.contentAttributes.of({ spellcheck: 'true' }),
            readonly ? cm.EditorState.readOnly.of(true) : cm.EditorView.editable.of(true),
            show_line_numbers ? cm.lineNumbers() : null,
            wrap_lines ? cm.EditorView_lineWrapping : null,
            placeholder ? cm.placeholderExt(placeholder) : null,

            // Sync back to Svelte
            cm.EditorView.updateListener.of((update: any) => {
                if (update.docChanged) {
                    const doc_str = update.state.doc.toString();
                    content = doc_str;
                    new_content = doc_str;
                }
            })
        ].filter(Boolean);

        if (!editor_container) return;

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

    // Initialize on mount
    onMount(async () => {
        await create_editor();
    });

    // Cleanup on destroy
    onDestroy(() => {
        if (editor_view) editor_view.destroy();
    });

    // Reactive update if content is changed from outside (e.g. API load)
    $effect(() => {
        if (editor_view && content !== editor_view.state.doc.toString()) {
            untrack(() => {
                editor_view.dispatch({
                    changes: { from: 0, to: editor_view.state.doc.length, insert: content || '' }
                });
            });
        }
    });

    // *** Toolbar Helpers
    const wrap_selection = (before: string, after: string = before) => {
        if (!editor_view) return;
        const state = editor_view.state;
        const changes = state.changeByRange((range: any) => {
            const is_wrapped =
                state.sliceDoc(range.from - before.length, range.from) === before &&
                state.sliceDoc(range.to, range.to + after.length) === after;

            if (is_wrapped) {
                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 toggle_list = () => {
        if (!editor_view) return;
        const state = editor_view.state;
        const changes = state.changeByRange((range: any) => {
            const line = state.doc.lineAt(range.from);
            const has_list = line.text.startsWith('- ');
            
            if (has_list) {
                return {
                    changes: [{ from: line.from, to: line.from + 2, insert: '' }],
                    range: cm.EditorSelection.range(range.from - 2, range.to - 2)
                };
            }
            
            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="ae__comp__codemirror_editor flex flex-col border border-surface-500/20 rounded-container overflow-hidden h-full {class_li}">
    {#if show_toolbar && !readonly}
        <div class="toolbar flex flex-wrap gap-1 p-1 bg-surface-50 dark:bg-surface-900 border-b border-surface-500/20">
            <button type="button" class="btn btn-sm variant-soft hover:variant-filled-primary" onclick={() => wrap_selection('**')} title="Bold">
                <Bold size="14" />
            </button>
            <button type="button" class="btn btn-sm variant-soft hover:variant-filled-primary" onclick={() => wrap_selection('*')} title="Italic">
                <Italic size="14" />
            </button>
            <button type="button" class="btn btn-sm variant-soft hover:variant-filled-primary" onclick={toggle_list} title="Bullet List">
                <List size="14" />
            </button>
            <button type="button" class="btn btn-sm variant-soft hover:variant-filled-primary" onclick={() => wrap_selection('`')} title="Inline Code">
                <Code size="14" />
            </button>
            
            <div class="ml-auto flex gap-1">
                <span class="text-[10px] opacity-50 self-center uppercase font-bold mr-2">{language}</span>
            </div>
        </div>
    {/if}

    <div 
        bind:this={editor_container} 
        class="grow overflow-auto bg-white dark:bg-black/20"
        style="min-height: 100px;"
    ></div>
</div>

<style lang="postcss">
    .ae__comp__codemirror_editor :global(.cm-editor) {
        height: 100%;
        outline: none !important;
    }
    .ae__comp__codemirror_editor :global(.cm-scroller) {
        font-family: theme('fontFamily.mono');
        font-size: 0.875rem;
    }
    /* Hide the focus outline from CM6 default theme */
    .ae__comp__codemirror_editor :global(.cm-focused) {
        outline: none !important;
    }
</style>
