<script setup lang="ts">
import { computed, nextTick, onMounted, ref, useTemplateRef, watch } from 'vue'
import { createEditorConfig } from './config/editor-config'
import EditorToolbar from './editor-toolbar.vue'
import { markdownTransformHtml } from '@/utils/markdown-parse'
import { asBlob } from 'html-docx-js-typescript'
import { downloadFile } from '@/utils/download-file'
import { useI18n } from 'vue-i18n'

interface Props {
  content: string
  height?: number
  disabled?: boolean
}

const props = withDefaults(defineProps<Props>(), {
  content: '',
  height: 700,
  disabled: false,
})
const emit = defineEmits<{
  input: [value: string]
  init: [value: any]
  creationContentRegenerate: []
}>()

defineExpose({
  getWordCount,
  getContent,
})

const editorToolbarRef = useTemplateRef<InstanceType<typeof EditorToolbar>>('editorToolbarRef')
const { t } = useI18n()

let editor: any = {}
let controller: AbortController | null = null

const editorConfig = createEditorConfig()

const isShowEditor = ref(false)
const editorWrapperRef = ref<HTMLDivElement | null>(null)
const modifyInputContainerStyle = ref({
  top: '0px',
})
const articleModifyInputContent = ref('')
const articleContentModifyContainerShow = ref(false)
const articleContentModifyState = ref<'selection' | 'loading' | 'generating' | 'done'>('selection')
const articleContentModifyResponseText = ref('')
const articleContentModifyResponseTextResource = ref('')
const articleContentModifyContainerClientY = ref(0)

const editorContent = computed({
  get() {
    return props.content
  },
  set(newVal) {
    emit('input', newVal)
  },
})

// const editorTitleText = ref('')

watch(articleContentModifyResponseTextResource, (newVal) => {
  if (newVal)
    articleContentModifyResponseText.value = markdownTransformHtml(
      editor.dom ? editor.dom.decode(newVal) : newVal,
    ) as string
})

watch(
  () => props.content,
  (val: string, prevVal: string) => {
    if (editor && editor.getContent && typeof val === 'string' && val !== prevVal && val !== editor.getContent())
      editor.setContent(val)
  },
)

onMounted(() => {
  window.tinymce.init({
    ...editorConfig,
    init_instance_callback: (editorInstance) => {
      isShowEditor.value = true
      editor = editorInstance

      nextTick(() => {
        props.content && editorInstance.setContent(props.content)
      })

      emit('init', editorInstance)
      if (editorToolbarRef.value) editorToolbarRef.value.editorInit()

      editorInstance.addCommand('creationContentRegenerate', () => {
        emit('creationContentRegenerate')
      })

      editorInstance.on('change keyup undo redo', () => {
        editorContent.value = editorInstance.getContent()
      })

      editorInstance.on('click', () => {
        if (editorToolbarRef.value) editorToolbarRef.value.resetShowPopoverStatus()
      })

      editorInstance.on('change keyup click', () => {
        if (editorToolbarRef.value) {
          editorToolbarRef.value.updateUndoManagerStatus()
          editorToolbarRef.value.updateToolbarActive()
        }
      })

      editorInstance.on('mousedown', (e: MouseEvent) => {
        if (e.button !== 0) return

        articleContentModifyContainerClientY.value = e.clientY

        if (articleContentModifyContainerShow.value) {
          if (controller) {
            controller.abort()
            controller = null
          }

          articleContentModifyContainerShow.value = false
          articleContentModifyResponseText.value = ''
          articleContentModifyResponseTextResource.value = ''
          articleContentModifyState.value = 'selection'
          articleModifyInputContent.value = ''
        }

        editorInstance.selection.collapse()
      })

      editorInstance.on('mouseup', (e: MouseEvent) => {
        if (e.button !== 0) return

        const selectionContent = editorInstance.selection.getContent()

        if (selectionContent) {
          const top =
            (e.clientY > articleContentModifyContainerClientY.value
              ? e.clientY
              : articleContentModifyContainerClientY.value) + 130

          const bodyHeight = document.body.offsetHeight

          modifyInputContainerStyle.value.top = `${top > bodyHeight - 400 ? bodyHeight - 400 : top}px`

          articleContentModifyContainerShow.value = true
        }
      })

      editorInstance.on('keydown', () => {
        if (articleContentModifyContainerShow.value) articleContentModifyContainerShow.value = false
      })
    },
  })
})

// function editorTitleTextVerify(value: string) {
//   if (value.startsWith('\n') || value.endsWith('\n')) return false

//   return !value.startsWith(' ') && !value.endsWith(' ')
// }

function getWordCount() {
  const wordcount = window.tinymce.activeEditor!.plugins.wordcount

  return wordcount.body.getWordCount()
}

function getContent() {
  if (!isShowEditor.value) return ''

  const content = editor.getContent()
  const parser = window.tinymce.html.DomParser({ validate: false })

  parser.addNodeFilter('mf-confirmation-box', (nodes) => {
    nodes.forEach((node) => {
      node.remove()
    })
  })

  const rootNode = parser.parse(content)

  return window.tinymce.html.Serializer().serialize(rootNode)
}

function onDownloadFile() {
  asBlob(getContent()).then((data) => {
    downloadFile(data as Blob).then(() => {
      window.$message.success(t('common_module.download_success'))
    })
  })
}
</script>

<template>
  <div v-show="isShowEditor" ref="editorWrapperRef" class="relative h-full w-full min-w-[200px]">
    <div
      id="tinymce-app"
      class="box-border flex h-full flex-col overflow-hidden rounded-lg border-[2px] border-solid border-[#eee] bg-white"
    >
      <div class="toolbar box-content bg-white py-1">
        <EditorToolbar ref="editorToolbarRef" @download-file="onDownloadFile" />
      </div>

      <!-- <div class="doc-title px-4 py-2">
        <NInput
          v-model:value="editorTitleText"
          type="textarea"
          :allow-input="editorTitleTextVerify"
          size="large"
          class="font-semibold"
          :autosize="{ minRows: 1 }"
          :maxlength="50"
          show-count
          placeholder="请输入标题..."
        />
      </div> -->
      <div class="h-[10px]"></div>

      <div class="grow">
        <textarea class="tinymce-body" />
      </div>
    </div>
  </div>
  <div v-show="!isShowEditor" class="flex h-full w-full items-center justify-center">
    <n-spin size="large" />
  </div>
</template>

<style lang="scss" scoped>
#tinymce-app {
  .toolbar {
    box-shadow:
      0 2px 2px -2px rgba(34, 47, 62, 0.1),
      0 8px 8px -4px rgba(34, 47, 62, 0.07);
  }

  :deep(.n-input) {
    .n-input-wrapper {
      --n-caret-color: #000;

      padding: 0;
      font-size: 18px;
    }

    .n-input__border,
    .n-input__state-border {
      display: none;
    }
  }

  :deep(.tox-tinymce) {
    border: none;
  }
}
</style>
