<template>
  <div
    class="vtj-code-editor"
    :class="{ 'is-border': props.border }"
    ref="container"
    :style="{ height: props.height }"></div>
</template>
<script lang="ts" setup>
import { ref, onMounted, onUnmounted, watch, nextTick } from 'vue';
import { editor as monacoEditor } from 'monaco-editor';
import useCore from '../hooks/useCore';

export interface Props {
  lang?: string;
  modelValue?: string;
  options?: monacoEditor.IEditorConstructionOptions;
  height?: string;
  readonly?: boolean;
  dark?: boolean;
  border?: boolean;
  minimap?: boolean;
}

const { engine } = useCore();
self.MonacoEnvironment = {
  getWorker(_, label) {
    const { editorWorker, jsonWorker, cssWorker, htmlWorker, tsWorker } =
      engine.config.workers || {};
    if (label === 'json' && jsonWorker) {
      return new jsonWorker();
    }
    if (['css', 'scss', 'less'].includes(label) && cssWorker) {
      return new cssWorker();
    }
    if (['html', 'handlebars', 'razor', 'vue'].includes(label) && htmlWorker) {
      return new htmlWorker();
    }
    if (['typescript', 'javascript'].includes(label) && tsWorker) {
      return new tsWorker();
    }
    if (editorWorker) {
      return new editorWorker();
    }
    return Promise.resolve({}) as Promise<Worker>;
  }
};

const props = withDefaults(defineProps<Props>(), {
  height: '300px',
  lang: 'typescript',
  modelValue: '',
  readonly: false,
  dark: true,
  minimap: false,
  options: () => ({})
});

const emit = defineEmits(['change', 'blur']);

const container = ref();
let editor: monacoEditor.IStandaloneCodeEditor | null = null;

// const exposeEditor = ref();

const handleBlur = () => {
  emit('blur', editor?.getValue());
};

const createEditor = () => {
  editor = monacoEditor.create(container.value, {
    value: props.modelValue,
    language: props.lang,
    readOnly: props.readonly,
    theme: props.dark ? 'vs-dark' : 'vs',
    automaticLayout: true,
    minimap: { enabled: props.minimap },
    ...props.options
  });

  editor.onDidChangeModelContent((e) => {
    emit('change', {
      value: editor?.getValue(),
      e: e
    });
  });

  editor.onDidBlurEditorText(handleBlur);
};

onMounted(() => {
  nextTick(createEditor);
});

onUnmounted(() => {
  if (editor) {
    editor.dispose();
  }
});

watch(
  () => props.modelValue,
  (value) => {
    if (editor) {
      editor.setValue(value);
    }
  }
);

const getEditor = () => {
  return editor;
};

defineExpose({ getEditor });
</script>
