<template>
    <div style="border: 1px solid #e4e4e4; height: 100%">
        <Toolbar
            style="border-bottom: 1px solid #e4e4e4; border-top: 1px solid #e4e4e4"
            :editor="editorRef"
            :defaultConfig="toolbarConfig"
            mode="default"
        />
        <Editor
            v-model="innerHtml"
            :defaultConfig="editorConfig"
            mode="default"
            @onCreated="handleCreated"
            @onChange="handleChange"
            style="height: calc(100% - 42px)"
        />
    </div>
</template>

<script lang="ts" setup>
import '@wangeditor/editor/dist/css/style.css'

import { nextTick, onBeforeUnmount, ref, shallowRef, watch } from 'vue'
import { Editor, Toolbar } from '@wangeditor/editor-for-vue'

const props = withDefaults(defineProps<{ modelValue?: string | null }>(), {
    modelValue: ''
})

const emit = defineEmits<{
    'update:modelValue': [value: string]
}>()

const editorRef = shallowRef<any>()
const innerHtml = ref('<p><br></p>')
const isApplyingExternal = ref(false)

/** 清理 HTML，避免标签间空白文本节点导致 Slate 解析失败 */
function sanitizeEditorHtml(html: string | null | undefined): string {
    if (html == null || html === '') return '<p><br></p>'
    const cleaned = html
        .replace(/>\s+</g, '><')
        .replace(/(<\/li>)\s+(<li>)/g, '$1$2')
        .trim()
    return cleaned || '<p><br></p>'
}

function toSaveHtml(html: string): string {
    return html === '<p><br></p>' ? '' : html
}

function applyHtmlToEditor(html: string | null | undefined) {
    const content = sanitizeEditorHtml(html)
    const editor = editorRef.value
    if (!editor || editor.isDestroyed) return

    try {
        const current = editor.getHtml()
        if (current === content) return
    } catch {
        // ignore getHtml error on half-destroyed editor
    }

    isApplyingExternal.value = true
    try {
        editor.setHtml(content)
        innerHtml.value = content
    } catch {
        try {
            editor.setHtml('<p><br></p>')
            innerHtml.value = '<p><br></p>'
        } catch {
            // editor may already be destroyed
        }
    } finally {
        nextTick(() => {
            isApplyingExternal.value = false
        })
    }
}

watch(
    () => props.modelValue,
    val => {
        applyHtmlToEditor(val)
    }
)

const toolbarConfig = {
    excludeKeys: ['fullScreen', 'emotion']
}

let sever = '/cs-harmonic-boot/csconfiguration/uploadImage'
if (process.env.NODE_ENV === 'development') {
    sever = '/api' + sever
}

const editorConfig = {
    placeholder: '请输入内容...',
    MENU_CONF: {
        uploadImage: {
            server: sever,
            fieldName: 'file',
            compress: true,
            uploadFileName: 'file',
            withCredentials: true,
            headers: {},
            timeout: 0,
            customInsert: (insertImg: (url: string) => void, result: { data: { url: string } }) => {
                insertImg(result.data.url)
            }
        }
    }
}

onBeforeUnmount(() => {
    const editor = editorRef.value
    editorRef.value = undefined
    if (editor == null || editor.isDestroyed) return
    editor.destroy()
})

const handleCreated = (editor: any) => {
    editorRef.value = editor
    nextTick(() => {
        applyHtmlToEditor(props.modelValue)
    })
}

const handleChange = (editor: { getHtml: () => string }) => {
    if (isApplyingExternal.value) return
    const html = editor.getHtml()
    innerHtml.value = html
    emit('update:modelValue', toSaveHtml(html))
}
</script>
