<script setup lang="ts">
import { computed, nextTick, onMounted, ref, shallowRef, watch, watchEffect } from 'vue'
import SceneList from './components/scene-list.vue'
import TemplateMenu from './components/template-menu.vue'
import Quill from 'quill/core'
import 'quill/dist/quill.core.css'
import './formats/index'
import { getQuillOptions } from './quill-opstions'
import textStructureExtractor from './utils/text-structure-extractor'
import { Delta } from 'quill/core'
import type { TemplateMenuConfig } from '@/views/home/components/rich-text-input-box/data/template-menu'
import { debounce } from 'lodash-es'
import type { WorkModeType } from '@/views/home/components/rich-text-input-box/types/index'
import type { UploadImageItem } from '@/composables/useUploadImage'
import { UploadStatus } from '@/enums/upload-status'
import { CloseSmall } from '@icon-park/vue-next'
import { useI18n } from 'vue-i18n'

interface Props {
  isQuestionSubmitBtnDisabled: boolean
  workMode: WorkModeType
  uploadImageList: UploadImageItem[]
}

const props = defineProps<Props>()

const emit = defineEmits<{
  submitQuestion: [question: string]
  workModeSwitch: [workMode: 'ApplicationMode' | 'SceneMode']
  removeUploadImage: [id: string]
}>()

const questionContent = defineModel<string>('questionContent', { default: '' })
const currentSceneConfig = defineModel<{
  agentId: string
  agentTitle: string
  agentDesc: string
  agentAvatar: string
} | null>('currentSceneConfig', {
  default: null,
})
const editorModeEnable = defineModel<boolean>('editorModeEnable', { default: false })

const { t } = useI18n()

const quillInst = shallowRef<Quill | null>(null)
const questionContentDraft = ref('')
const isInputFocus = ref(false)

const showSceneList = ref(false)
const showTemplateMenu = ref(false)
const clickShowTemplateMenu = ref(false)

const uploadImageInfo = computed(() => {
  const imageInfo = props.uploadImageList[0]

  return imageInfo
    ? { id: imageInfo.id, url: imageInfo.url.split('/').reverse()[0], status: imageInfo.status }
    : { url: '', id: '' }
})

const onQuillTextChange = debounce(
  () => {
    // const question = quillContentExtractor(delta)
    const question = quillInst.value?.getText().trim()

    if (question === '@') {
      quillInst.value?.deleteText(0, question.length + 1)
      showSceneList.value = true
      quillInst.value?.blur()
    }

    questionContentDraft.value = question || ''
    questionContent.value = questionContentDraft.value
  },
  300,
  { trailing: true, leading: true },
)

watch(
  () => currentSceneConfig.value,
  (newConfig) => {
    if (newConfig) {
      emit('workModeSwitch', 'SceneMode')

      initQuill()

      nextTick(() => {
        quillInst.value?.focus()
      })
    }
  },
)

watch(
  () => questionContent.value,
  (newQuestion) => {
    if (newQuestion && newQuestion !== questionContentDraft.value) {
      if (quillInst.value) {
        quillInst.value.setContents([
          {
            insert: questionContent.value.trim() || '',
          },
        ])
      }
    }
  },
  { immediate: true },
)

watch(showTemplateMenu, (isShow) => {
  if (!isShow) {
    setTimeout(() => {
      clickShowTemplateMenu.value = false
    }, 200)
  }
})

watchEffect(() => {
  if (quillInst.value) {
    quillInst.value.on('text-change', onQuillTextChange)

    quillInst.value.on('composition-start', () => {
      if (quillInst.value) {
        quillInst.value.root.dataset.placeholder = ''
      }
    })

    quillInst.value.on('composition-end', () => {
      if (quillInst.value) {
        quillInst.value.root.dataset.placeholder = quillInst.value.options.placeholder
      }
    })

    // quillInst.value.clipboard.addMatcher('span.template-input-prompt-container', (node) => {
    //   const spanEl = node as HTMLSpanElement

    //   return new Delta().insert({
    //     'template-input-prompt': {
    //       placeholder: spanEl.dataset.placeholder,
    //       index: spanEl.dataset.index,
    //     },
    //   })
    // })
  }
})

onMounted(() => {
  initQuill()
})

function initQuill() {
  const placeholderMap = {
    common: t('home_module.rich_text_module.placeholder', { symbol: '@' }),
    writing: t('home_module.rich_text_module.writing_placeholder'),
  }

  quillInst.value = new Quill(
    '#rich-text-input-box-editor',
    getQuillOptions({
      placeholder: currentSceneConfig.value?.agentId ? placeholderMap.writing : placeholderMap.common,
      keyboardCallback: {
        enter: () => {
          if (!props.isQuestionSubmitBtnDisabled) {
            handleQuestionSubmit()
          }
        },
        // at: () => {
        //   const text = quillInst.value?.getText().trim()

        //   if (text === '@') {
        //     showSceneList.value = true

        //     quillInst.value?.blur()
        //   }
        // },
      },
    }),
  )
}

function handleShowTemplateMenuSwitch() {
  // nextTick(() => {
  //   if (!showTemplateMenu.value) {
  //     showTemplateMenu.value = true
  //   }
  // })

  if (clickShowTemplateMenu.value) {
    clickShowTemplateMenu.value = false
    return
  }

  showTemplateMenu.value = true
  clickShowTemplateMenu.value = true
}

function quillContentExtractor(delta: Delta) {
  const questionFragmentMap = new Map<number, string>()

  let templateInputPromptIndex = 0

  delta.forEach((op, opIndex) => {
    if (typeof op.insert === 'object' && op.insert['template-input-prompt']) {
      const promptEl = document.querySelector(
        `#rich-text-input-box-editor .template-input-prompt-container.prompt-index-${templateInputPromptIndex} .prompt-content`,
      )
      let promptContent = ''

      if (promptEl) {
        promptContent = promptEl.textContent || ''
      }

      questionFragmentMap.set(opIndex, promptContent)

      templateInputPromptIndex++
    } else {
      questionFragmentMap.set(opIndex, (op.insert as string) || '')
    }
  })

  let question = ''
  questionFragmentMap.forEach((fragment) => (question += fragment))

  return question
}

function handleQuestionSubmit() {
  if (quillInst.value) {
    const delta = quillInst.value.getContents()
    const question = quillContentExtractor(delta)

    emit('submitQuestion', question)

    questionContentDraft.value = ''
    questionContent.value = ''

    quillInst.value.setContents([])
  }
}

function onTemplateConfirm(templateConfig: TemplateMenuConfig['templateList'][0]) {
  const promptArr = textStructureExtractor(templateConfig.template || '')

  const delta = new Delta()

  let templateInputPromptIndex = 0

  promptArr.forEach((promptItem) => {
    if (promptItem.type === 'text') {
      delta.insert(promptItem.content)
    } else if (promptItem.type === 'placeholder') {
      delta.insert({
        'template-input-prompt': {
          placeholder: promptItem.content,
          index: templateInputPromptIndex,
        },
      })

      templateInputPromptIndex++
    }
  })

  quillInst.value?.setContents(delta)
}
</script>

<template>
  <SceneList v-model:show-scene-list="showSceneList" v-model:current-scene-config="currentSceneConfig" />
  <TemplateMenu v-model:show-template-menu="showTemplateMenu" @template-confirm="onTemplateConfirm" />

  <div
    class="hover:border-theme-color rounded-[5px] border border-[#9ea3ff] p-[12px] pr-0 transition duration-300"
    :class="{ 'shadow-[0_0_0_2px_rgba(0,13,255,0.2)]': isInputFocus }"
  >
    <n-scrollbar class="max-h-[140px]">
      <div class="pr-[12px]">
        <div id="rich-text-input-box-editor" class="font-['SourceHanSansCN-Regular'] text-[14px] text-[#333]"></div>
      </div>
    </n-scrollbar>

    <div class="mt-[8px] flex items-center justify-between px-[12px]">
      <div class="pt-[2px]">
        <div
          v-if="uploadImageInfo.url"
          class="relative select-none rounded-[4px] border border-[#e0e0e6] bg-[#fafafc] px-[12px] py-[4px] text-[12px]"
          :class="{ '!border-[#F25744]': uploadImageInfo.status === UploadStatus.ERROR }"
        >
          <n-ellipsis style="max-width: 200px">{{ uploadImageInfo.url }}</n-ellipsis>

          <div
            class="absolute right-[-4px] top-[-4px] flex size-[16px] cursor-pointer items-center justify-center rounded-full bg-[rgba(0,0,0,0.55)] hover:opacity-80"
            @click="() => $emit('removeUploadImage', uploadImageInfo.id)"
          >
            <CloseSmall theme="outline" size="14" fill="#fff" />
          </div>
        </div>
      </div>

      <div class="flex items-center">
        <Transition>
          <div v-show="workMode === 'SceneMode'" class="mr-[15px]">
            <n-tooltip trigger="hover">
              <template #trigger>
                <button
                  class="mr-[5px] h-[24px] w-[32px] rounded-[5px] border border-[#333]/60 transition"
                  :class="[showTemplateMenu ? 'border-[#9EA3FF] text-[#9EA3FF]' : '']"
                  @click="handleShowTemplateMenuSwitch"
                >
                  <i class="iconfont icon-moban1 text-[14px]"></i>
                </button>
              </template>
              {{ t('home_module.rich_text_module.template') }}
            </n-tooltip>

            <n-tooltip trigger="hover">
              <template #trigger>
                <button
                  class="h-[24px] w-[32px] rounded-[5px] border border-[#333]/60 transition"
                  :class="[editorModeEnable ? 'border-[#9EA3FF] text-[#9EA3FF]' : '']"
                  @click="editorModeEnable = !editorModeEnable"
                >
                  <i class="iconfont icon-wendangbianjiqi1 text-[14px]"></i>
                </button>
              </template>
              {{ t('home_module.rich_text_module.message_editor') }}
            </n-tooltip>
          </div>
        </Transition>

        <div>
          <n-button type="primary" :disabled="isQuestionSubmitBtnDisabled" @click="handleQuestionSubmit">
            <i class="iconfont icon-send-icon"></i>
          </n-button>
        </div>
      </div>
    </div>
  </div>
</template>

<style lang="scss" scoped>
#rich-text-input-box-editor {
  :deep(.ql-editor) {
    padding: 0;
    overflow: hidden;
    line-height: 28px;
    overflow-wrap: break-word;

    &::before {
      left: 0;
    }
  }
}

.v-enter-active,
.v-leave-active {
  transition-timing-function: ease-in-out;
  transition-duration: 0.2s;
  transition-property: opacity;
}

.v-enter-from,
.v-leave-to {
  opacity: 0;
}
</style>
