<template>
  <div class="editor-container" :style="containerStyle">
    <toolbar class="editor-toolbar" :editor="editorInstance" :default-config="toolbarConfig" :mode="props.mode" />
    <wd-editor
      class="editor-body"
      v-model="editorContent"
      :default-config="mergedEditorConfig"
      :mode="props.mode"
      @onCreated="handleEditorCreated"
      @onChange="handleEditorChange"
      @onFocus="handleEditorFocus"
      @onBlur="handleEditorBlur"
    />
    <material-picker ref="materialPickerRef" :type="fileType" :limit="-1" dialogOnly @change="handleMaterialSelect" />
  </div>
</template>

<script setup lang="ts">
// @ts-ignore
import { Editor as WdEditor, Toolbar } from '@wangeditor/editor-for-vue'
import '@wangeditor/editor/dist/css/style.css'
import type { IDomEditor, IEditorConfig, IToolbarConfig } from '@wangeditor/editor'
import { addUnit } from '@/utils/util'
import type { CSSProperties } from 'vue'

// 组件属性
const props = withDefaults(
  defineProps<{
    // 编辑器内容
    modelValue?: string
    // 编辑器模式
    mode?: 'default' | 'simple'
    // 编辑器宽度
    width?: string | number
    // 编辑器高度
    height?: string | number
    // 自定义工具栏配置
    toolbarConfig?: Partial<IToolbarConfig>
    // 自定义编辑器配置
    editorConfig?: Partial<IEditorConfig>
  }>(),
  {
    modelValue: '',
    mode: 'default',
    width: '100%',
    height: 500,
    toolbarConfig: () => ({}),
    editorConfig: () => ({})
  }
)

// 组件事件
const emit = defineEmits<{
  (event: 'update:modelValue', value: string): void
  (event: 'created', editor: IDomEditor): void
  (event: 'change', editor: IDomEditor): void
  (event: 'focus', editor: IDomEditor): void
  (event: 'blur', editor: IDomEditor): void
}>()

// 编辑器实例
const editorInstance = shallowRef<IDomEditor | null>(null)
// 素材选择器实例
const materialPickerRef = shallowRef<InstanceType<typeof MaterialPicker>>()
// 文件类型
const fileType = ref<string>('')
// 插入函数
let insertMediaFn: ((url: string) => void) | null = null
// 编辑器内容双向绑定
const editorContent = computed({
  get() {
    return props.modelValue || ''
  },
  set(value: string) {
    emit('update:modelValue', value)
  }
})
// 容器样式
const containerStyle = computed<CSSProperties>(() => ({
  width: addUnit(props.width),
  height: addUnit(props.height)
}))
// 合并编辑器配置
const mergedEditorConfig = computed<Partial<IEditorConfig>>(() => {
  return {
    autoFocus: false,
    scroll: true,
    MENU_CONF: {
      uploadImage: {
        customBrowseAndUpload: (insert: (url: string) => void) => {
          fileType.value = 'image'
          materialPickerRef.value?.open(-1)
          insertMediaFn = insert
        }
      },
      uploadVideo: {
        customBrowseAndUpload: (insert: (url: string) => void) => {
          fileType.value = 'video'
          materialPickerRef.value?.open(-1)
          insertMediaFn = insert
        }
      }
    },
    ...props.editorConfig
  }
})

// 处理编辑器创建
const handleEditorCreated = (editor: IDomEditor) => {
  editorInstance.value = editor
  emit('created', editor)
}
// 处理编辑器内容变化
const handleEditorChange = (editor: IDomEditor) => {
  emit('change', editor)
}
// 处理编辑器获得焦点
const handleEditorFocus = (editor: IDomEditor) => {
  emit('focus', editor)
}
// 处理编辑器失去焦点
const handleEditorBlur = (editor: IDomEditor) => {
  emit('blur', editor)
}
// 处理素材选择
const handleMaterialSelect = (fileUrls: string[]) => {
  if (!insertMediaFn) return
  fileUrls.forEach((url) => {
    if (insertMediaFn) {
      insertMediaFn(url)
    }
  })
  insertMediaFn = null
  fileType.value = ''
}

watch(
  () => props.modelValue,
  (newValue) => {
    if (editorInstance.value && editorContent.value !== (newValue || '')) {
      const editor = editorInstance.value as any
      if (editor.setHtml) {
        editor.setHtml(newValue || '')
      }
    }
  },
  { immediate: true }
)

onBeforeUnmount(() => {
  if (editorInstance.value) {
    editorInstance.value.destroy()
    editorInstance.value = null
  }
})
</script>

<style lang="scss" scoped>
.editor-container {
  @apply border border-br flex flex-col;

  .editor-toolbar {
    @apply border-b border-br;
  }

  .editor-body {
    @apply flex-1 min-h-0;
  }
}

// 编辑器内容样式
:deep(.w-e-text-container) {
  [data-slate-editor] {
    ul {
      list-style: disc;
    }

    ol {
      list-style: decimal;
    }
  }

  h1,
  h2,
  h3,
  h4,
  h5 {
    font-weight: bold;
  }

  h1 {
    font-size: 2em;
  }

  h2 {
    font-size: 1.5em;
  }

  h3 {
    font-size: 1.25em;
  }

  h4 {
    font-size: 1em;
  }

  h5 {
    font-size: 0.875em;
  }

  h6 {
    font-size: 0.75em;
  }
}

.w-e-full-screen-container {
  z-index: 999;
}
</style>
