<script setup lang="ts">
import { cloneDeep } from 'lodash-es'
import { nanoid } from 'nanoid'
import { onMounted, ref, toRaw } from 'vue'
import { type ToolbarAllConfig, useEditorToolbarConfig } from './config/editor-toolbar-config'
import EditorToolItem from './editor-tool-item.vue'
import { useI18n } from 'vue-i18n'

const emit = defineEmits<{
  downloadFile: []
}>()

const { toolbarAllConfig } = useEditorToolbarConfig()
const { t } = useI18n()

const currentToolbarString = 'ndo redo removeFormat | blocks bold italic underline strikethrough | align'

const toolbarConfigList = ref<Map<string, Map<string, ToolbarAllConfig['key']>>>(new Map())
const currentShowPopoverToolItem = ref<ToolbarAllConfig['key'] | null>(null)

defineExpose({
  editorInit,
  resetShowPopoverStatus,
  updateUndoManagerStatus,
  updateToolbarActive,
})

function toolbarStringParser() {
  const toolbarConfigListDraft: Map<string, Map<string, ToolbarAllConfig['key']>> = new Map()

  currentToolbarString.split('|').forEach((toolGroupString) => {
    const toolGroup: Map<string, ToolbarAllConfig['key']> = new Map()
    const toolGroupId = nanoid()

    toolGroupString
      .split(' ')
      .filter((toolItem) => toolItem)
      .forEach((toolItemName) => {
        if (toolbarAllConfig[toolItemName])
          toolGroup.set(
            toolItemName,
            cloneDeep({ ...toRaw(toolbarAllConfig[toolItemName]), toolGroupId }) as unknown as ToolbarAllConfig['key'],
          )
      })

    toolbarConfigListDraft.set(toolGroupId, toolGroup)
  })

  toolbarConfigList.value = toolbarConfigListDraft
}

onMounted(() => {
  toolbarStringParser()

  document.body.addEventListener(
    'click',
    (event) => {
      const targetElement = event.target as unknown as any

      if (targetElement) {
        if (
          (targetElement.localName === 'i' && targetElement.classList.contains('iconfont')) ||
          (targetElement.localName === 'div' && targetElement.classList.contains('tool-item'))
        )
          return
      }

      resetShowPopoverStatus()
    },
    true,
  )
})

function editorInit() {}

function traversalSearchToolItemConfig(name: string): Promise<ToolbarAllConfig['key']> {
  return new Promise((resolve, reject) => {
    try {
      toolbarConfigList.value.forEach((toolGroup) => {
        toolGroup.forEach((toolItem) => {
          if (name === toolItem.name) {
            resolve(toolItem)
            throw new Error('LoopInterrupt')
          }
        })
      })

      reject(new Error('NoMatchingContent'))
    } catch (err) {
      reject(new Error('NoMatchingContent'))
    }
  })
}

function updateToolbarActive() {
  toolbarConfigList.value.forEach((toolGroup) => {
    toolGroup.forEach((toolItem) => {
      if (toolItem.submenuCmd && toolItem.submenuCmd.length > 0) {
        toolItem.submenuCmd.forEach((toolChildItem) => {
          window.tinymce.activeEditor?.queryCommandState(toolChildItem.command)
            ? (toolChildItem.isActive = true)
            : (toolChildItem.isActive = false)
        })

        return
      }

      window.tinymce.activeEditor?.queryCommandState(toolItem.command)
        ? (toolItem.isActive = true)
        : (toolItem.isActive = false)
    })
  })
}

function handleExecuteCommand(toolItem: ToolbarAllConfig['key']) {
  const toolGroup = toolbarConfigList.value.get(toolItem.toolGroupId)

  if (toolGroup) {
    const currentToolItem = toolGroup.get(toolItem.name)

    if (currentToolItem && currentToolItem.submenuCmd && currentToolItem.submenuCmd.length > 0) {
      currentShowPopoverToolItem.value = currentToolItem
      currentToolItem.isShowPopover = !currentToolItem.isShowPopover
      return
    }

    if (currentToolItem) {
      window.tinymce.activeEditor?.execCommand(currentToolItem.command)

      if (['Redo', 'Undo'].includes(toolItem.command)) updateUndoManagerStatus()
    }
  }
}

function handleSubmenuCmdClick(toolItemChildCmd: NonNullable<ToolbarAllConfig['key']['submenuCmd']>[0]) {
  toolItemChildCmd.isActive = true
  window.tinymce.activeEditor?.execCommand(toolItemChildCmd.command)
}

function resetShowPopoverStatus() {
  if (currentShowPopoverToolItem.value) {
    currentShowPopoverToolItem.value.isShowTooltip && (currentShowPopoverToolItem.value.isShowTooltip = false)
    currentShowPopoverToolItem.value.isShowPopover &&
      (currentShowPopoverToolItem.value.isShowPopover = !currentShowPopoverToolItem.value.isShowPopover)
  }
}

function updateUndoManagerStatus() {
  traversalSearchToolItemConfig('ndo').then((toolItem) => {
    window.tinymce.activeEditor?.undoManager.hasUndo() ? (toolItem.isDisabled = false) : (toolItem.isDisabled = true)
  })

  traversalSearchToolItemConfig('redo').then((toolItem) => {
    window.tinymce.activeEditor?.undoManager.hasRedo() ? (toolItem.isDisabled = false) : (toolItem.isDisabled = true)
  })
}

function handleToolItemMouseenter(toolItem: ToolbarAllConfig['key']) {
  const toolGroup = toolbarConfigList.value.get(toolItem.toolGroupId)

  if (toolGroup) {
    const currentToolItem = toolGroup.get(toolItem.name)

    if (currentToolItem && currentToolItem.submenuCmd) return

    currentToolItem && (currentToolItem.isShowTooltip = true)
  }
}

function handleToolItemMouseleave(toolItem: ToolbarAllConfig['key']) {
  const toolGroup = toolbarConfigList.value.get(toolItem.toolGroupId)

  if (toolGroup) {
    const currentToolItem = toolGroup.get(toolItem.name)

    if (currentToolItem && currentToolItem.submenuCmd) return

    currentToolItem && (currentToolItem.isShowTooltip = false)
  }
}

function handleDownloadFile() {
  emit('downloadFile')
}
</script>

<template>
  <div class="editor-toolbar flex h-full flex-wrap">
    <div v-for="([, toolGroup], index) in toolbarConfigList" :key="index" class="flex items-center px-3">
      <EditorToolItem
        :tool-group="toolGroup"
        @on-execute-command="handleExecuteCommand"
        @on-submenu-cmd-click="handleSubmenuCmdClick"
        @on-tool-item-mouseenter="handleToolItemMouseenter"
        @on-tool-item-mouseleave="handleToolItemMouseleave"
      />
    </div>

    <div class="ml-auto mr-[10px]">
      <n-tooltip trigger="hover">
        <template #trigger>
          <div
            class="rounded-[6px] px-2 transition-[background] duration-300 ease-linear hover:bg-[#cce2fa]"
            @click="handleDownloadFile"
          >
            <i class="iconfont icon-download"></i>
          </div>
        </template>
        {{ t('common_module.download') }}
      </n-tooltip>
    </div>
  </div>
</template>

<style lang="scss" scoped>
.editor-toolbar {
  :global(div.editor-toolbar-popover) {
    padding: 8px !important;
  }
}
</style>
