// CodeMirror 6 wrapper module
// Provides createEditor() and getLanguageExtension() for the rest of the app.

const {
  EditorView,
  keymap,
  lineNumbers,
  highlightActiveLine,
  drawSelection,
} = require('@codemirror/view');
const { EditorState } = require('@codemirror/state');
const { markdown, markdownLanguage } = require('@codemirror/lang-markdown');
// Language extensions loaded lazily on first use
let _javascript, _html, _css, _json, _python;
const {
  defaultKeymap,
  history,
  historyKeymap,
  indentWithTab,
} = require('@codemirror/commands');
const {
  searchKeymap,
  highlightSelectionMatches,
} = require('@codemirror/search');
const {
  autocompletion,
  completionKeymap,
} = require('@codemirror/autocomplete');
const {
  bracketMatching,
  foldGutter,
  indentOnInput,
} = require('@codemirror/language');
const { oneDark } = require('@codemirror/theme-one-dark');

// Custom theme for JetBrains Mono font
const jetBrainsMonoTheme = EditorView.theme({
  '&': {
    fontFamily: "'JetBrains Mono', 'Fira Code', 'SF Mono', Monaco, 'Courier New', monospace"
  },
  '.cm-content': {
    fontFamily: 'inherit'
  },
  '.cm-scroller': {
    fontFamily: 'inherit'
  }
});

/**
 * Create a CodeMirror 6 editor instance.
 *
 * @param {HTMLElement} parentElement - DOM element to mount the editor in
 * @param {Object}  options
 * @param {string}  options.content          - initial document content (default '')
 * @param {Function} options.onChange        - called with new content string on every doc change
 * @param {Function} options.onUpdate       - called with the EditorView on every update (selection, doc change, etc.)
 * @param {boolean} options.isDark           - apply oneDark theme when true (default false)
 * @param {boolean} options.showLineNumbers  - show line-number gutter (default true)
 * @returns {EditorView} the created editor view
 */
function createEditor(parentElement, options = {}) {
  console.log('[createEditor] Called with parentElement:', parentElement?.id, 'dimensions:', parentElement?.clientWidth, 'x', parentElement?.clientHeight);
  if (!parentElement) {
    console.error('[createEditor] ERROR: parentElement is null or undefined!');
    return null;
  }
  const {
    content = '',
    onChange = () => {},
    onUpdate = null,
    isDark = false,
    showLineNumbers = true,
  } = options;

  const extensions = [
    markdown({ base: markdownLanguage }),
    history(),
    drawSelection(),
    highlightActiveLine(),
    bracketMatching(),
    indentOnInput(),
    highlightSelectionMatches(),
    autocompletion(),
    foldGutter(),
    jetBrainsMonoTheme,
    keymap.of([
      ...defaultKeymap,
      ...historyKeymap,
      ...searchKeymap,
      ...completionKeymap,
      indentWithTab,
    ]),
    EditorView.updateListener.of((update) => {
      if (update.docChanged) {
        onChange(update.state.doc.toString());
      }
      if (onUpdate && (update.docChanged || update.selectionSet)) {
        onUpdate(update.view);
      }
    }),
    EditorView.lineWrapping,
  ];

  if (showLineNumbers) {
    extensions.push(lineNumbers());
  }

  if (isDark) {
    extensions.push(oneDark);
  }

  const state = EditorState.create({ doc: content, extensions });
  const view = new EditorView({ state, parent: parentElement });
  return view;
}

/**
 * Return the appropriate CodeMirror language extension for a given language name.
 *
 * Supported values: javascript, js, html, css, json, python, py, markdown.
 * Falls back to markdown when the language is unrecognised.
 *
 * @param {string} lang - language identifier
 * @returns {Extension} CodeMirror language extension
 */
function getLanguageExtension(lang) {
  const loaders = {
    javascript: () => { if (!_javascript) _javascript = require('@codemirror/lang-javascript').javascript; return _javascript(); },
    html: () => { if (!_html) _html = require('@codemirror/lang-html').html; return _html(); },
    css: () => { if (!_css) _css = require('@codemirror/lang-css').css; return _css(); },
    json: () => { if (!_json) _json = require('@codemirror/lang-json').json; return _json(); },
    python: () => { if (!_python) _python = require('@codemirror/lang-python').python; return _python(); },
    markdown: () => markdown({ base: markdownLanguage }),
  };
  loaders.js = loaders.javascript;
  loaders.py = loaders.python;

  const loader = loaders[lang];
  return loader ? loader() : markdown({ base: markdownLanguage });
}

module.exports = { createEditor, getLanguageExtension };
