import { Component, NewState, Util, $ } from '@web/state';
import { EditorView, basicSetup } from 'codemirror';
import { EditorState, Compartment } from '@codemirror/state';
import { javascript } from '@codemirror/lang-javascript';
import { json } from '@codemirror/lang-json';
import { html } from '@codemirror/lang-html';
import { oneDark } from '@codemirror/theme-one-dark';
import { keymap } from '@codemirror/view';
import { indentWithTab } from '@codemirror/commands';

const languageConf = new Compartment();
const themeConf = new Compartment();
const readonlyConf = new Compartment();

const getLanguage = (lang) => {
    switch (lang?.toLowerCase()) {
        case 'js':
        case 'javascript': return javascript();
        case 'json': return json();
        case 'html': return html();
        // TODO: add yaml when available
        default: return javascript();
    }
};

const CodeEditor = (container) => {
    const initialState = container.getAttribute('value') || '';
    const lang = container.getAttribute('lang') || 'javascript';
    const theme = container.getAttribute('theme') || 'dark';
    const readonly = container.hasAttribute('readonly');

    const extensions = [
        basicSetup,
        keymap.of([indentWithTab]),
        languageConf.of(getLanguage(lang)),
        themeConf.of(theme === 'dark' ? oneDark : []),
        readonlyConf.of(EditorState.readOnly.of(readonly)),
        EditorView.updateListener.of((update) => {
            if (update.docChanged) {
                container.dispatchEvent(new CustomEvent('change', {
                    bubbles: true,
                    detail: update.state.doc.toString()
                }));
                // Also trigger input for $bind consistency
                container.dispatchEvent(new Event('input', { bubbles: true }));
            }
        })
    ];

    const view = new EditorView({
        state: EditorState.create({
            doc: initialState,
            extensions
        }),
        parent: container
    });

    container.view = view;

    // Define value property for $bind compatibility
    Object.defineProperty(container, 'value', {
        get: () => view.state.doc.toString(),
        set: (val) => {
            if (val === view.state.doc.toString()) return;
            view.dispatch({
                changes: { from: 0, to: view.state.doc.length, insert: String(val || '') }
            });
        },
        configurable: true
    });

    // Handle attribute changes
    const observer = new MutationObserver((mutations) => {
        mutations.forEach((mutation) => {
            if (mutation.type === 'attributes') {
                const name = mutation.attributeName;
                if (name === 'lang') {
                    view.dispatch({
                        effects: languageConf.reconfigure(getLanguage(container.getAttribute('lang')))
                    });
                } else if (name === 'theme') {
                    const newTheme = container.getAttribute('theme');
                    view.dispatch({
                        effects: themeConf.reconfigure(newTheme === 'dark' ? oneDark : [])
                    });
                } else if (name === 'readonly') {
                    view.dispatch({
                        effects: readonlyConf.reconfigure(EditorState.readOnly.of(container.hasAttribute('readonly')))
                    });
                }
            }
        });
    });

    observer.observe(container, { attributes: true });

    // Cleanup on remove
    container.addEventListener('unload', () => {
        view.destroy();
        observer.disconnect();
    });

};

Component.register('CodeEditor', CodeEditor, Util.makeDom(/*html*/`<style>
    CodeEditor {
        display: block;
        border: 1px solid var(--bs-border-color, #ccc);
        border-radius: 4px;
        overflow: hidden;
        min-height: 100px;
    }
    CodeEditor .cm-editor {
        height: 100%;
        max-height: 500px;
    }
    CodeEditor .cm-scroller {
        font-family: var(--bs-font-monospace, monospace);
        font-size: 14px;
    }
</style>`));

import { AutoForm } from '@web/base';

// Register with AutoForm
if (AutoForm) {
    AutoForm.register('CodeEditor', 'code');
}

export { CodeEditor as default };
