<script setup lang="ts">
import { computed, provide, readonly, ref, useTemplateRef } from 'vue'
import { useI18n } from 'vue-i18n'
import { throttle } from 'lodash-es'
import { Down } from '@icon-park/vue-next'
import CustomLoading from './custom-loading.vue'
import MusicWavesLoading from './music-waves-loading.vue'
import MarkdownRender from '@/components/markdown-render/markdown-render.vue'
import EditorDrawer from '@/components/editor-drawer/editor-drawer.vue'
import ExecutePluginRender from '@/components/execute-plugin-render/execute-plugin-render.vue'
import ExecuteCodeRender from '@/components/execute-code-render/execute-code-render.vue'
import { PersonalAppConfigState } from '@/store/types/personal-app-config'
import { useLayoutConfig } from '@/composables/useLayoutConfig'
import { useUserStore } from '@/store/modules/user'
import { copyToClip } from '@/utils/copy'
import SmartForms from '@/views/personal-space/personal-app-setting/components/agent-config/agent-preview/components/smart-forms/index.vue'

interface Props {
  messageItemId: string
  messageItem: ConversationMessageItem
  agentApplicationConfig: PersonalAppConfigState
}

const { t } = useI18n()

const props = defineProps<Props>()

const emit = defineEmits<{
  audioPlay: []
  audioPause: []
  showKnowledgeResult: []
}>()

const userStore = useUserStore()

const { isMobile } = useLayoutConfig()

const markdownRenderRef = useTemplateRef<InstanceType<typeof MarkdownRender>>('markdownRenderRef')

provide('messageItemId', props.messageItemId)

const isShowReasoningContent = ref(true)
const isShowEditorDrawer = ref(false)
const editorDrawerContent = ref('')

const displaySmartFormsList = readonly(['travelForm'])

const useAvatar = computed(() => {
  return userStore.userInfo.avatarUrl || 'https://gsst-poe-sit.gz.bcebos.com/data/20240910/1725952917468.png'
})

const assistantAvatar = computed(() => {
  return (
    props.agentApplicationConfig.baseInfo.agentAvatar ||
    'https://gsst-poe-sit.gz.bcebos.com/data/20240911/1726041369632.webp'
  )
})

const isAgentMessage = computed(() => {
  return props.messageItem.role === 'assistant'
})

const currentBubbleTextColor = computed(() => {
  return isAgentMessage.value ? '#192338' : '#fff'
})

const isShowSmartForms = computed(() => {
  if (props.messageItem?.pluginResult?.displayFormat) {
    return displaySmartFormsList.includes(props.messageItem?.pluginResult?.displayFormat)
  }
  return false
})

const messageAuthor = computed(() => {
  return isAgentMessage.value ? props.messageItem.modelName || 'AI' : userStore.userInfo.nickName
})

const timbreEnabled = computed(() => {
  return (
    !!props.agentApplicationConfig.voiceConfig.timbreId || !!props.agentApplicationConfig.digitalhumanConfig?.timbreId
  )
})

const isShowAudioControl = computed(() => {
  return isAgentMessage.value && !props.messageItem.isVoiceLoading && timbreEnabled.value
})

const isPlayableAudio = computed(() => {
  return isShowAudioControl.value && !!props.messageItem.voiceFragmentUrlList.length
})

const isShowVoiceLoading = computed(() => {
  return (
    isAgentMessage.value &&
    (props.messageItem.isAnswerResponseLoading || (props.messageItem.isVoiceLoading && timbreEnabled.value))
  )
})

const isDeepSeekR1 = computed(() => {
  return props.agentApplicationConfig.commModelConfig.largeModel === 'DeepSeek'
})

function handleAudioControl() {
  if (!isPlayableAudio.value) {
    return
  }

  if (props.messageItem.isVoicePlaying) {
    emit('audioPause')
  } else {
    emit('audioPlay')
  }
}

function handleShowReasoningContentSwitch() {
  isShowReasoningContent.value = !isShowReasoningContent.value
}

function handleContentEdit() {
  isShowEditorDrawer.value = true

  let content = ''

  markdownRenderRef.value && (content = markdownRenderRef.value.getRenderTextContent())

  editorDrawerContent.value = content
}

const handleContentCopy = throttle(
  () => {
    copyToClip(props.messageItem.textContent).then(() => {
      window.$message.success(t('common_module.copy_success_message'))
    })
  },
  1000,
  { leading: true, trailing: false },
)
</script>

<template>
  <div
    class="mb-5 flex last:mb-0"
    :class="[isMobile ? 'flex-row-reverse' : 'flex-row', isAgentMessage && isMobile ? 'justify-end' : 'justify-start']"
  >
    <NImage
      v-show="!isMobile"
      :src="isAgentMessage ? assistantAvatar : useAvatar"
      preview-disabled
      :width="32"
      :height="32"
      object-fit="cover"
      class="mr-2 mt-1.5 h-8 w-8 flex-shrink-0 rounded-full"
    />

    <div
      v-if="!isShowSmartForms"
      class="flex flex-col overflow-x-auto"
      :class="[isMobile && !isAgentMessage ? 'items-end' : 'items-start', isMobile ? 'w-full' : '']"
    >
      <!-- 大模型深度思考 -->
      <template v-if="isAgentMessage && isDeepSeekR1">
        <div class="my-[7px] select-none text-[14px]">
          <div class="inline-flex cursor-pointer" @click="handleShowReasoningContentSwitch">
            <span v-if="messageItem.isTextContentLoading" class="mr-[6px]">
              {{ t('common_module.deep_thinking', { modelName: agentApplicationConfig.commModelConfig.largeModel }) }}
            </span>
            <span v-else class="mr-[6px]">
              {{ t('common_module.have_thought_deeply') }}
            </span>
            <Down
              theme="outline"
              size="21"
              fill="#333"
              :stroke-width="3"
              class="transition-[rotate] duration-100 ease-linear"
              :class="{ '-rotate-180': isShowReasoningContent }"
            />
          </div>
        </div>

        <n-collapse-transition :show="isShowReasoningContent">
          <div
            v-if="messageItem.reasoningContent"
            class="my-[14px] border-l-[1px] border-solid border-l-[#ccc] p-[13px]"
          >
            <MarkdownRender
              ref="markdownRenderRef"
              :raw-text-content="
                messageItem.reasoningContent
                  ? messageItem.reasoningContent
                  : t('common_module.dialogue_module.empty_message_content')
              "
              color="#999"
            />
          </div>
        </n-collapse-transition>
      </template>

      <!-- 模型内容 -->
      <div class="flex min-w-[80px] flex-col" :class="[isMobile ? 'max-w-[calc(100%-20px)]' : 'max-w-full']">
        <div
          class="w-full flex-wrap rounded-xl border border-[#9EA3FF] px-4 py-[11px]"
          :class="[isAgentMessage ? 'bg-white text-[#333]' : 'user-content-container bg-[#777EF9] text-white']"
        >
          <img
            v-show="!isAgentMessage && messageItem.imageUrl"
            :src="messageItem.imageUrl"
            class="max-h-[120px]! mb-[11px] rounded-[10px] object-contain"
          />

          <!-- 插件返回结果 -->
          <div v-show="isAgentMessage && messageItem?.pluginResult?.pluginName" class="mb-[11px] w-full">
            <ExecutePluginRender
              :display-format="messageItem.pluginResult?.displayFormat || 'none'"
              :name="messageItem.pluginResult?.pluginName!"
              :content="messageItem.pluginResult?.pluginContent!"
              :arguments="messageItem.pluginResult?.arguments!"
              :plugin-loading="messageItem.isTextContentLoading"
            />
          </div>

          <div v-if="messageItem.isTextContentLoading" class="py-1.5 pl-4">
            <CustomLoading />
          </div>

          <div v-else>
            <!-- 数据库问答结果 -->
            <div v-show="messageItem.dbChainSQLContent" class="mb-[10px] w-full">
              <ExecuteCodeRender
                :title="t('common_module.database_QA_executed_successfully')"
                :raw-text-content="messageItem.dbChainSQLContent"
              />
            </div>

            <p class="break-all">
              <MarkdownRender
                ref="markdownRenderRef"
                :raw-text-content="
                  messageItem.isEmptyContent
                    ? t('common_module.dialogue_module.empty_message_content')
                    : messageItem.textContent
                "
                :color="currentBubbleTextColor"
              />
            </p>

            <div
              v-show="isShowVoiceLoading || messageItem.isAnswerResponseLoading"
              class="mt-4 px-4"
              :class="isShowAudioControl && !isMobile ? 'mb-2.5' : 'mb-[5px]'"
            >
              <CustomLoading />
            </div>
          </div>

          <!-- pc端语音播放 -->
          <div
            v-show="isShowAudioControl && !isMobile"
            class="text-font-color ml-[-4px] mt-1.5 flex h-6 items-center gap-0.5"
            :class="isPlayableAudio ? 'hover:text-theme-color cursor-pointer hover:opacity-80' : 'cursor-not-allowed'"
            @click="handleAudioControl"
          >
            <i v-if="!messageItem.isVoicePlaying" class="iconfont icon-play text-[24px]" />
            <div
              v-else
              class="mx-1.5 my-3 h-[12px] w-[12px] bg-[url(@/assets/images/playing.gif)] bg-[length:100%_100%]"
            />

            <span
              v-show="isPlayableAudio"
              class="text-[12px]"
              :class="messageItem.isVoicePlaying ? 'text-theme-color' : ''"
            >
              {{ messageItem.isVoicePlaying ? t('common_module.stop_playing') : t('common_module.start_playing') }}
            </span>
            <n-popover style="max-width: 310px">
              <template #trigger>
                <span v-show="!isPlayableAudio" class="text-[12px]"> {{ t('common_module.unplayable') }} </span>
              </template>
              {{ t('common_module.unplayable_tip') }}
            </n-popover>
          </div>

          <!-- 移动端语音播放 -->
          <div v-show="isShowAudioControl && isMobile" class="mt-[13px] flex items-center gap-2">
            <div
              class="h-[18px] w-[18px] cursor-pointer"
              :class="messageItem.isVoicePlaying ? 'bg-svg-pause' : 'bg-svg-play'"
              @click="handleAudioControl"
            />

            <MusicWavesLoading v-show="messageItem.isVoicePlaying && isPlayableAudio" bar-bg-color="#333" />

            <n-popover style="max-width: 310px">
              <template #trigger>
                <span v-show="!isPlayableAudio" class="text-[12px]"> {{ t('common_module.unplayable') }} </span>
              </template>
              {{ t('common_module.unplayable_tip') }}
            </n-popover>
          </div>
        </div>

        <!-- 仅pc端展示操作 -->
        <div v-show="!isMobile" class="flex w-full items-center justify-between">
          <div
            v-show="isAgentMessage && messageItem.knowledgeContentResult.length"
            class="flex-center rounded-theme h-8 cursor-pointer gap-[5px] px-[13px] font-['Microsoft_YaHei_UI'] text-[#0B7DFF] hover:opacity-80"
            @click="emit('showKnowledgeResult')"
          >
            <i class="iconfont icon-knowledge" />
            <span>{{ t('common_module.knowledge') }}</span>
          </div>

          <div
            v-show="isAgentMessage && messageItem.textContent && !messageItem.isAnswerResponseLoading"
            class="py-[10px] pr-[14px] text-end"
          >
            <i
              class="iconfont icon-fuzhi hover:text-theme-color mr-[14px] transform cursor-pointer text-[14px]"
              @click="handleContentCopy"
            />
            <i
              class="iconfont icon-edit-document hover:text-theme-color transform cursor-pointer text-[14px]"
              @click="handleContentEdit"
            />
          </div>
        </div>
      </div>
    </div>

    <SmartForms
      v-else
      :message-author="messageAuthor"
      :is-agent-message="isAgentMessage"
      :message-item="messageItem"
      :current-bubble-text-color="currentBubbleTextColor"
    />
  </div>

  <EditorDrawer v-model:is-show-editor-drawer="isShowEditorDrawer" v-model:content-edit="editorDrawerContent" />
</template>

<style lang="scss" scoped>
:deep(.user-content-container) {
  a {
    color: #fff !important;
  }
}

:deep(.markdown-render-container .markdown-render-inner) {
  table {
    color: #fff !important;
  }
}
</style>
