<template>
  <VueMonacoEditor
    :options="options"
    :defaultLanguage="language"
    :onBeforeMount="onBeforeMount"
    :onMount="onMount"
    class="codeEditBox"
    className="codeEditBox"
  />
</template>

<script>
import _ from 'lodash'
import { loader, VueMonacoEditor } from '@guolao/vue-monaco-editor'
import { setupMonacoEditor } from '@/core/script/ScriptSupport.js'

loader.config({
  paths: {
    vs: 'static/monaco-editor/min/vs'
  },
  'vs/nls': { availableLanguages: { '*': 'zh-cn' } }
})

export default {
  props: {
    modelValue: String,
    language: String,
    readonly: { defaults: false, required: false, type: Boolean },
    lineNumbers: { defaults: true, required: false, type: Boolean },
    expressMode: { defaults: false, required: false, type: Boolean }
  },
  components: {
    VueMonacoEditor
  },
  emits: [
    'update:modelValue',
    'editor-mounted',
    'change',
    'editor-blur',
    'editor-focus'
  ],
  mounted() {
  },
  data() {
    const option = {
      value: this.modelValue,
      language: this.language ?? 'javascript',
      minimap: {
        enabled: false
      },
      selectOnLineNumbers: true,
      renderSideBySide: false,
      automaticLayout: true,
      // * 这个属性，允许悬浮的提示溢出到 dom 外
      fixedOverflowWidgets: true,
      allowEditorOverflow: false
    }
    if (!this.$props.lineNumbers) {
      option.lineNumbers = 'off'
    }
    if (this.$props.expressMode === true) {
      _.extend(option, {
        lineNumbers: 'off',
        hideCursorInOverviewRuler: true,
        overviewRulerBorder: false,
        glyphMargin: false,
        lineDecorationsWidth: 0,
        fontSize: '19px',
        roundedSelection: false,
        scrollBeyondLastLine: false,
        disableMonospaceOptimizations: true,
        readOnly: this.readonly
      })
    }
    return {
      options: option
      // language: option.language,
    }
  },
  watch: {
    'modelValue': {
      handler(newVal) {
        if (!this.editor) {
          return
        }
        if (newVal === this.editor.getValue()) {
          // 防止递归
          return
        }
        this.editor.setValue(newVal ?? '')
      }
    },
    'language': {
      handler(newVal) {
        if (this.editor) {
          this.setLanguage(newVal)
        }
      }
    },
    'loadTypeAction': {
      handler(newVal) {

      }
    }
  },
  unmounted() {
    if (this.editor) {
      this.editor.dispose()
      this.editor = null
    }
  },
  methods: {
    onBeforeMount(monaco) {
      this.monaco = monaco
      setupMonacoEditor(monaco)
    },
    onMount(editor, monaco) {
      this.editor = editor
      this.monaco = monaco
      this.init()
    },
    focus() {
      _.defer(() => {
        this.editor?.focus()
      })
    },
    insertText(text) {
      if (!this.editor) {
        return
      }
      const position = this.editor.getPosition()
      this.editor.executeEdits('', [{
        range: new this.monaco.Range(position.lineNumber, position.column, position.lineNumber, position.column),
        text: text,
        forceMoveMarkers: true
      }])
    },
    scrollToButtom() {
      this.editor?.revealLine(this.editor.getModel().getLineCount())
    },
    appendText(text) {
      this.editor?.getModel().pushEditOperations(
        [],
        [
          {
            range: new monaco.Range(1, 1, 1, 1),
            text: text
          }
        ],
        () => null
      )
    },
    init() {
      // this.editor.updateOptions(option);
      this.editor.setValue(this.modelValue ?? '')
      // 监听值的变化
      this.editor.onDidChangeModelContent(() => {
        const value = this.editor.getValue() // 给父组件实时返回最新文本
        this.$emit('update:modelValue', value)
        this.$emit('change', value)
      })

      this.editor.onDidBlurEditorWidget((e) => {
        this.$emit('editor-blur', e)
      })
      this.editor.onDidFocusEditorWidget((e) => {
        this.$emit('editor-focus', e)
      })

      if (this.language === 'typescript' || this.language === 'javascript') {
        this.editor.onDidFocusEditorWidget(() => {
          window['editor'] = this.editor
          window['monaco'] = this.monaco
        })
        const monaco = this.monaco
        const editor = this.editor
        editor.addCommand(
          monaco.KeyMod.CtrlCmd | monaco.KeyMod.Alt | monaco.KeyCode.KeyL,
          () => editor.getAction('editor.action.formatDocument')?.run()
        )
      }

      this.$emit('editor-mounted', this.editor)
      // .monacoInitFinished()
    },
    updateOptions(options) {
      if (this.editor && options) {
        this.editor.updateOptions(options)
      }
    },
    setLanguage(lang) {
      if (this.editor && lang) {
        this.monaco.editor.setModelLanguage(this.editor.getModel(), lang)
      }
    }
  }
}
</script>

<style lang="less">
.codeEditBox {
  width: 100%;
  flex: 1;
  overflow-y: auto;
  border: 1px solid #ccc;

  .monaco-editor .suggest-widget .monaco-list .monaco-list-row > .contents > .main {
    flex-direction: row;
    font-size: 14px;
  }

  .monaco-editor .suggest-widget .monaco-list .monaco-list-row .suggest-icon {
    height: 18px;
  }
}
</style>
