<script setup lang="ts">
import { computed, inject, onMounted, onUnmounted, ref, useTemplateRef, watch } from 'vue'
import { Emitter } from 'mitt'
import { useI18n } from 'vue-i18n'
import OverwriteMessageTipModal from './overwrite-message-tip-modal.vue'
import { fetchCustomEventSource } from '@/composables/useEventSource'
import { usePersonalAppConfigStore } from '@/store/modules/personal-app-config'
import { UploadStatus } from '@/enums/upload-status'
import { useDialogueFile } from '@/composables/useDialogueFile'

interface Props {
  messageList: ConversationMessageItem[]
  continuousQuestionStatus: 'default' | 'close'
}

const { t } = useI18n()

const props = defineProps<Props>()

const emit = defineEmits<{
  addMessageItem: [value: ConversationMessageItem]
  updateSpecifyMessageItem: [messageItemIndex: number, newObj: Partial<ConversationMessageItem>]
  deleteLastMessageItem: []
  updatePageScroll: []
  clearAllMessage: []
  createContinueQuestions: [value: string]
  updateContinuousQuestionStatus: [value: 'default' | 'close']
}>()

const personalAppConfigStore = usePersonalAppConfigStore()

const { uploadFileList, handleLimitUpload, handleUpload, handleRemoveFile } = useDialogueFile()

const messageTipModalRef = useTemplateRef<InstanceType<typeof OverwriteMessageTipModal>>('messageTipModalRef')

const emitter = inject<Emitter<MittEvents>>('emitter')

const inputMessageContent = ref('')
const isAnswerResponseWait = ref(false)

let controller: AbortController | null = null

const agentId = computed(() => {
  return personalAppConfigStore.baseInfo.agentId
})

const isCreateContinueQuestions = computed(() => {
  return props.continuousQuestionStatus === 'default'
})

const isAllowClearMessage = computed(() => {
  return props.messageList.length > 0
})

const isSendBtnDisabled = computed(() => {
  return !inputMessageContent.value.trim()
})

const isInputMessageDisabled = computed(() => {
  return uploadFileList.value.some((fileItem) => fileItem.status !== UploadStatus.FINISHED)
})

const isEnableDocumentParse = computed(() => {
  return personalAppConfigStore.knowledgeConfig.isDocumentParsing === 'Y'
})

const isUploadFileDisabled = computed(() => {
  return uploadFileList.value.length === 1
})

const uploadFileIcon = (type: string) => {
  return `https://gsst-poe-sit.gz.bcebos.com/icon/${type}.svg`
}

watch(
  () => isEnableDocumentParse.value,
  () => {
    uploadFileList.value = []
  },
)

onUnmounted(() => {
  blockMessageResponse()
  emitter?.off('selectQuestion')
})

onMounted(() => {
  emitter?.on('selectQuestion', (featuredQuestion) => {
    inputMessageContent.value = featuredQuestion
    handleMessageSend()
  })
})

function messageItemFactory() {
  return {
    timestamp: Date.now(),
    role: 'user',
    textContent: '',
    isEmptyContent: false,
    isTextContentLoading: false,
    isAnswerResponseLoading: false,
  } as const
}

function handleMessageSend() {
  if (!inputMessageContent.value.trim() || isAnswerResponseWait.value || isInputMessageDisabled.value) return ''

  const messages: {
    content: {
      type: string
      text: string
      image_url: {
        url: ''
      }
    }[]
    role: string
  }[] = []

  emit('updateContinuousQuestionStatus', personalAppConfigStore.commConfig.continuousQuestionStatus)
  emit('addMessageItem', { ...messageItemFactory(), textContent: inputMessageContent.value })
  emit('updatePageScroll')

  props.messageList.forEach((messageItem) => {
    messages.push({
      content: [
        {
          type: 'text',
          text: messageItem.textContent,
          image_url: {
            url: '',
          },
        },
      ],
      role: messageItem.role,
    })
  })

  inputMessageContent.value = ''
  isAnswerResponseWait.value = true

  emit('addMessageItem', {
    ...messageItemFactory(),
    role: 'assistant',
    isTextContentLoading: true,
    isAnswerResponseLoading: true,
  })
  emit('updatePageScroll')

  const currentMessageIndex = props.messageList.length - 1
  let replyTextContent = ''

  controller = new AbortController()

  fetchCustomEventSource({
    path: '/api/rest/agentApplicationInfoRest/preview.json',
    payload: {
      agentId: agentId.value,
      fileUrls: uploadFileList.value.map((item) => item.url),
      messages,
    },
    controller,
    onMessage: (data: any) => {
      if (data === '[DONE]') {
        emit('updateSpecifyMessageItem', currentMessageIndex, {
          isEmptyContent: !replyTextContent,
          isTextContentLoading: false,
          isAnswerResponseLoading: false,
        })
        isCreateContinueQuestions.value && emit('createContinueQuestions', replyTextContent)
        emit('updatePageScroll')
        blockMessageResponse()
        return
      }

      if (data) {
        replyTextContent += data

        emit('updateSpecifyMessageItem', currentMessageIndex, {
          textContent: replyTextContent,
          isTextContentLoading: false,
        })
        emit('updatePageScroll')
      }
    },
    onRequestError: () => {
      errorMessageResponse()
    },
    onError: () => {
      errorMessageResponse()
    },
    onFinally: () => {
      controller = null
    },
  })
}

function errorMessageResponse() {
  emit('updateSpecifyMessageItem', props.messageList.length - 1, {
    isTextContentLoading: false,
    textContent: '',
  })
  emit('deleteLastMessageItem')
  emit('deleteLastMessageItem')
  blockMessageResponse()
}

function handleClearAllMessage() {
  if (!isAllowClearMessage.value) return

  emit('clearAllMessage')
}

function blockMessageResponse() {
  controller?.abort()
  isAnswerResponseWait.value = false
}

function handleSelectFile(cb: () => void) {
  if (isUploadFileDisabled.value) {
    messageTipModalRef.value?.handleShowModal().then(() => {
      cb()
    })
    return
  }

  cb()
}

defineExpose({
  blockMessageResponse,
})
</script>

<template>
  <div class="mb-3 mt-5 px-5">
    <div class="flex items-end gap-2.5">
      <div class="flex-1">
        <ul v-show="uploadFileList.length > 0" class="mb-1.5 grid gap-1.5">
          <li
            v-for="uploadFileItem in uploadFileList"
            :key="uploadFileItem.id"
            class="group relative flex h-[42px] w-full items-center overflow-hidden rounded-[10px] border bg-white/70"
            :class="uploadFileItem.status === 'error' ? 'border-error-font-color' : 'border-transparent'"
          >
            <div class="flex w-full items-center justify-between px-3.5">
              <div class="flex w-full items-center overflow-hidden">
                <img :src="uploadFileIcon(uploadFileItem.type!)" class="h-7 w-7" />

                <div class="mx-2.5 flex flex-1 flex-col overflow-hidden">
                  <n-ellipsis>
                    {{ uploadFileItem.name }}
                  </n-ellipsis>
                </div>
              </div>

              <n-progress
                v-show="!['finished', 'error'].includes(uploadFileItem.status)"
                class="left-13.5 w-[calc(100%-78px)]! absolute bottom-0"
                type="line"
                rail-color="#F3F3F3"
                :height="4"
                :percentage="uploadFileItem.percentage"
                :show-indicator="false"
              />

              <div v-show="['finished', 'error'].includes(uploadFileItem.status)" class="hidden group-hover:block">
                <n-popover trigger="hover" placement="top-end" :show-arrow="false">
                  <template #trigger>
                    <i
                      class="iconfont icon-close cursor-pointer hover:opacity-80"
                      :class="uploadFileItem.status === 'error' ? 'text-error-font-color' : 'text-font-color'"
                      @click="handleRemoveFile(uploadFileItem.id)"
                    />
                  </template>
                  <span>{{ t('common_module.dialogue_module.cancel_associate_file_tip') }}</span>
                </n-popover>
              </div>
            </div>
          </li>
        </ul>

        <div class="relative flex-1">
          <n-input
            v-model:value="inputMessageContent"
            :placeholder="t('common_module.dialogue_module.question_input_placeholder')"
            :disabled="isInputMessageDisabled"
            class="rounded-xl! shadow-[0_1px_#09122105,0_1px_1px_#09122105,0_3px_3px_#09122103,0_9px_9px_#09122103]! py-[4px] pr-[50px]"
            @keydown.enter="handleMessageSend"
          />

          <div
            class="bg-px-send-png absolute bottom-2 right-[20px] h-[24px] w-[24px]"
            :class="
              isSendBtnDisabled || isAnswerResponseWait || isInputMessageDisabled ? 'opacity-60' : 'cursor-pointer'
            "
            @click="handleMessageSend"
          />
        </div>
      </div>

      <n-upload
        :show-file-list="false"
        accept=".doc, .pdf, .docx, .txt, .md"
        abstract
        @before-upload="handleLimitUpload"
        @change="handleUpload"
      >
        <n-upload-trigger #="{ handleClick }" abstract>
          <n-popover style="width: 210px" trigger="hover">
            <template #trigger>
              <div
                v-show="isEnableDocumentParse"
                class="h-7.5 w-7.5 hover:text-theme-color text-font-color mb-1 flex cursor-pointer items-center justify-center rounded-full bg-white"
                @click="handleSelectFile(handleClick)"
              >
                <i class="iconfont icon-upload flex h-4 w-4 items-center justify-center" />
              </div>
            </template>

            <span class="text-xs"> {{ t('common_module.dialogue_module.upload_file_limit') }} </span>
          </n-popover>
        </n-upload-trigger>
      </n-upload>

      <n-popover trigger="hover">
        <template #trigger>
          <div
            class="h-7.5 w-7.5 mb-1 flex cursor-pointer items-center justify-center rounded-full bg-white"
            @click="handleClearAllMessage"
          >
            <i
              class="iconfont icon-clear text-base leading-none"
              :class="
                isAllowClearMessage ? 'hover:text-theme-color text-font-color' : 'cursor-not-allowed text-[#b8babf]'
              "
            />
          </div>
        </template>
        <span class="text-xs">
          {{ t('common_module.dialogue_module.clear_message_popover_message') }}
        </span>
      </n-popover>
    </div>

    <div class="mt-[9px] pl-2">
      <span class="text-xs text-[#84868c]">
        {{ t('common_module.dialogue_module.generate_warning_message') }}
      </span>
    </div>
  </div>

  <OverwriteMessageTipModal ref="messageTipModalRef" />
</template>
