<script setup lang="ts">
import { computed, ref, useTemplateRef } from 'vue'
import { useI18n } from 'vue-i18n'
import { CheckOne, Down } from '@icon-park/vue-next'
import CustomLoading from '../custom-loading.vue'
import MusicWavesLoading from './music-waves-loading.vue'
import ExecutePluginRender from '@/components/execute-plugin-render/execute-plugin-render.vue'
import MarkdownRender from '@/components/markdown-render/markdown-render.vue'
import { PersonalAppConfigState } from '@/store/types/personal-app-config'

interface Props {
  role: 'user' | 'assistant'
  messageItem: ConversationMessageItem
  agentApplicationConfig: PersonalAppConfigState
}

const { t } = useI18n()

const props = defineProps<Props>()

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

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

const isShowReasoningContent = ref(true)

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

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

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

const isShowVoiceLoading = computed(() => {
  return (
    props.role === 'assistant' &&
    (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
}
</script>

<template>
  <div class="message-item-wrapper" :class="[role === 'assistant' ? 'justify-end' : 'justify-start']">
    <div class="message-item-container" :class="[role === 'user' ? 'items-end' : 'items-start']">
      <!-- 大模型深度思考 -->
      <template v-if="role === 'assistant' && isDeepSeekR1">
        <div class="deep-seek-title-container">
          <div class="deep-seek-name-container" @click="handleShowReasoningContentSwitch">
            <span v-if="messageItem.isTextContentLoading" class="deep-seek-text">
              {{ t('common_module.deep_thinking', { modelName: agentApplicationConfig.commModelConfig.largeModel }) }}
            </span>
            <span v-else class="deep-seek-text">
              {{ t('common_module.have_thought_deeply') }}
            </span>
            <Down
              theme="outline"
              :size="18"
              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="deep-seek-content-container">
            <MarkdownRender
              ref="markdownRenderRef"
              :raw-text-content="
                messageItem.reasoningContent
                  ? messageItem.reasoningContent
                  : t('common_module.dialogue_module.empty_message_content')
              "
              color="#999"
              :font-size="'3.2vw'"
            />
          </div>
        </n-collapse-transition>
      </template>

      <!-- 模型内容 -->
      <div class="model-content-wrapper">
        <div
          class="model-content-container"
          :class="[
            { 'user-model-content-container': role === 'user' },
            { 'assistant-model-content-container': role === 'assistant' },
          ]"
        >
          <img v-show="role === 'user' && messageItem.imageUrl" :src="messageItem.imageUrl" class="upload-image" />

          <!-- 插件返回结果 -->
          <div v-show="role === 'assistant' && messageItem?.pluginResult?.pluginName" class="plugin-container">
            <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="content-loading">
            <CustomLoading :active-color="'#000DFF'" />
          </div>

          <div v-else>
            <!-- 数据库问答结果 -->
            <div v-show="messageItem.dbChainSQLContent" class="database-container">
              <div class="database-title-container">
                <CheckOne theme="outline" size="16" fill="#40bd23" />
                <span class="database-name">{{ t('common_module.database_QA_executed_successfully') }}</span>
              </div>
              <MarkdownRender
                ref="markdownRenderRef"
                dark-theme
                color="#fff"
                :font-size="'3.2vw'"
                :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="'#333'"
                :font-size="'3.2vw'"
              />
            </p>

            <div v-show="isShowVoiceLoading || messageItem.isAnswerResponseLoading" class="answer-response-loading">
              <CustomLoading :active-color="'#000DFF'" />
            </div>
          </div>

          <!-- 移动端语音播放 -->
          <div v-show="isShowAudioControl" class="audio-control-container">
            <div
              class="audio-control-icon"
              :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"> {{ t('common_module.unplayable') }} </span>
              </template>
              {{ t('common_module.unplayable_tip') }}
            </n-popover>
          </div>
        </div>
      </div>
    </div>
  </div>
</template>

<style lang="scss" scoped>
.message-item-wrapper {
  @apply mb-[15px] flex flex-row-reverse last:mb-0;

  .message-item-container {
    @apply flex w-full flex-col overflow-x-auto;

    .deep-seek-title-container {
      @apply my-[7px] select-none text-[12px];

      .deep-seek-name-container {
        @apply inline-flex cursor-pointer;

        .deep-seek-text {
          @apply mr-[6px];
        }
      }
    }

    .deep-seek-content-container {
      @apply my-[10px] border-l-[1px] border-solid border-l-[#ccc] px-[13px] py-[8px];
    }

    .model-content-wrapper {
      @apply flex min-w-[80px] max-w-full flex-col;

      .model-content-container {
        @apply w-full flex-wrap rounded-[10px] border px-[12px] py-[11px];

        .upload-image {
          @apply max-h-[120px]! mb-[10px] rounded-[10px] object-contain;
        }

        .plugin-container {
          @apply mb-[8px] w-full;
        }

        .database-container {
          @apply mb-[10px] rounded-[10px] bg-[#F3F5F9] p-[14px] pt-0 text-[12px];

          .database-title-container {
            @apply flex items-center gap-[5px] py-[10px];

            .database-name {
              @apply text-gray-font-color text-[12px] leading-4;
            }
          }
        }

        .content-loading {
          @apply py-[6px] pl-[16px];
        }

        .answer-response-loading {
          @apply mb-[5px] mt-[16px] px-[16px];
        }

        .audio-control-container {
          @apply mt-[11px] flex items-center gap-[8px] text-[12px];

          .audio-control-icon {
            @apply h-[16px] w-[16px] cursor-pointer;
          }
        }
      }

      .user-model-content-container {
        @apply rounded-tr-none border-[#DCDEFF] bg-[#DCDEFF] text-white;
      }

      .assistant-model-content-container {
        @apply rounded-tl-none border-[#e8e9eb] bg-white text-[#333];
      }
    }
  }
}

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

:deep(.jv-container.jv-light) {
  font-size: 12px;

  .jv-code {
    padding: 10px 0 0 !important;
  }
}
</style>
