<script setup lang="ts">
import type { SelectGroupOption, SelectOption } from "naive-ui";
import type { Message } from "@/interfaces";
import { throttle } from "lodash-es";
import AIAvatar from "@/assets/ai_avatar.png";
import { ExclamationTriangleIcon, microphone, TrashIcon } from "@/assets/Icons";
import UserAvatar from "@/assets/user_avatar.jpg";
import markdown from "@/components/markdown.vue";
import { useAsrStore, useChatStore, useLayoutStore } from "@/stores";

const chatStore = useChatStore();
const { historyMessages, completing, modelList, modelInfo, thinking } =
  storeToRefs(chatStore);
const asrStore = useAsrStore();
const { isRecording } = storeToRefs(asrStore);
const layoutStore = useLayoutStore();
const { hiddenLeftSidebar, simpleMode } = storeToRefs(layoutStore);

const scrollbarRef = ref<HTMLElement | null>(null);
const options = ref<Array<SelectGroupOption | SelectOption>>([]);
// NCollapse 组件的折叠状态
const collapseActive = ref<string[]>(
  historyMessages.value.map((msg, idx) => String(msg.id ?? idx))
);

// 过滤出type为voice的聊天消息
const filteredMessages = computed(() =>
  historyMessages.value.filter((msg) => msg.type === "voice")
);

const getName = (msg: Message, idx: number) => String(msg.id ?? idx);

// TODO: bugfix: 未能正确展开
watch(
  historyMessages,
  (newVal, oldVal) => {
    // 取所有name
    const newNames = newVal.map((msg, idx) => getName(msg, idx));
    const oldNames = oldVal ? oldVal.map((msg, idx) => getName(msg, idx)) : [];
    // 找出新增的name
    const addedNames = newNames.filter((name) => !oldNames.includes(name));
    // 保留原有已展开项
    const currentActive = collapseActive.value.filter((name) =>
      newNames.includes(name)
    );
    // 新增的默认展开
    collapseActive.value = [...currentActive, ...addedNames];
  },
  { immediate: true, deep: true }
);

// 处理折叠项的点击事件，切换折叠状态
const handleItemHeaderClick = (name: string) => {
  if (collapseActive.value.includes(name)) {
    collapseActive.value = collapseActive.value.filter((n) => n !== name);
  } else {
    collapseActive.value.push(name);
  }
};

// 处理选中模型的 ID
const selectedModelId = computed({
  get: () => modelInfo.value?.model_id ?? null,
  set: (id: string | null) => {
    for (const vendor of modelList.value) {
      const found = vendor.models.find((model) => model.model_id === id);
      if (found) {
        modelInfo.value = found;
        return;
      }
    }
    modelInfo.value = null;
  }
});

// 监听模型列表变化，更新选项
watch(
  () => modelList.value,
  (newVal) => {
    if (newVal) {
      options.value = newVal.map((vendor) => ({
        type: "group",
        label: vendor.vendor,
        key: vendor.vendor,
        children: vendor.models.map((model) => ({
          label: model.model_name,
          value: model.model_id,
          type: model.model_type
        }))
      }));

      if (newVal.length > 0 && newVal[0].models.length > 0) {
        modelInfo.value = newVal[0].models[0];
      }
    }
  },
  { immediate: true, deep: true }
);

// 开关语音输入
const toggleRecording = throttle(() => {
  if (isRecording.value) {
    asrStore.stopRecording();
  } else {
    asrStore.startRecording();
  }
}, 500);

watch(completing, (newVal) => {
  if (newVal) {
    nextTick(() => {
      scrollbarRef.value?.scrollTo({ top: 99999, behavior: "smooth" });
    });
  }
});

onMounted(() => {
  chatStore.getModelList();
});
</script>

<template>
  <div
    class="p-8 !pr-4 h-full w-full flex flex-col gap-4 border-l-[24px] border-l-[#FAFAFA] transition-all ease-in-out text-base"
    :class="{ '!border-l-0': hiddenLeftSidebar || simpleMode }"
  >
    <!-- 历史消息区 -->
    <NScrollbar ref="scrollbarRef" class="flex-1 pr-4 relative">
      <div class="flex items-start mb-4">
        <span class="rounded-lg overflow-hidden !w-16 !min-w-16 !h-16">
          <avatar :avatar="AIAvatar" />
        </span>
        <div class="text-base w-full max-w-full ml-2 flex flex-col items-start">
          <span class="text-base font-bold mb-4">助手：</span>
          <span class="text-base"
            >你好，我是你的智能助手，请问有什么可以帮助你的吗？</span
          >
          <NDivider />
        </div>
      </div>
      <!-- 默认消息↑ 历史消息↓ -->
      <div
        v-for="(msg, idx) in filteredMessages"
        :key="idx"
        class="flex items-start mb-4"
      >
        <!-- 头像↓ -->
        <span
          v-if="msg.role === 'user'"
          class="rounded-lg overflow-hidden !w-16 !min-w-16 !h-16"
        >
          <avatar :avatar="UserAvatar" />
        </span>
        <span v-else class="rounded-lg overflow-hidden">
          <avatar :avatar="AIAvatar" />
        </span>
        <!-- 头像↑ 名称↓ -->
        <div class="text-base w-full max-w-full ml-2 flex flex-col items-start">
          <span class="text-base font-bold">{{
            msg.role === "user" ? "你：" : "助手："
          }}</span>
          <!-- 使用信息 -->
          <div
            v-if="msg.role !== 'user'"
            class="text-[12px] text-[#7A7A7A] mb-[2px]"
          >
            Tokens: <span class="mr-1">{{ msg.usage?.total_tokens }}</span>
          </div>
          <div class="w-full max-w-full">
            <NCollapse
              v-if="msg.thinking?.trim()"
              :expanded-names="collapseActive[idx]"
            >
              <NCollapseItem
                :title="
                  thinking && idx === historyMessages.length - 1
                    ? '思考中...'
                    : '已深度思考'
                "
                :name="getName(msg, idx)"
                @item-header-click="
                  () => handleItemHeaderClick(getName(msg, idx))
                "
              >
                <div
                  class="text-[#7A7A7A] mb-4 border-l-2 border-[#E5E5E5] ml-2 pl-2"
                >
                  <markdown :content="msg.thinking || ''" />
                </div>
              </NCollapseItem>
            </NCollapse>
            <!-- 内容↓ 思维链↑ -->
            <markdown :content="msg.content || ''" />
            <div v-if="msg.role !== 'user'" class="mt-2">
              <tts :text="msg.content || ''" :message-id="msg.id!" />
            </div>
            <NDivider />
          </div>
        </div>
      </div>
      <div
        v-if="isRecording"
        class="absolute inset-0 pointer-events-none flex items-center justify-center text-[#7A7A7A] text-2xl bg-white/80"
      >
        正在语音输入...
      </div>
    </NScrollbar>
    <!-- 操作区 -->
    <div class="flex justify-between items-center gap-2">
      <div class="flex items-center gap-2">
        <NSelect
          v-model:value="selectedModelId"
          label-field="label"
          value-field="value"
          children-field="children"
          filterable
          :options="options"
        />
      </div>
      <div class="flex items-center gap-2">
        <NPopconfirm
          :positive-button-props="{ type: 'error' }"
          positive-text="清除"
          negative-text="取消"
          @positive-click="chatStore.clearHistoryMessages('voice')"
          @negative-click="() => {}"
        >
          <template #icon>
            <ExclamationTriangleIcon class="!w-6 !h-6 text-[#d03050]" />
          </template>
          <template #trigger>
            <NButton :disabled="isRecording || completing" type="warning">
              <template v-if="!simpleMode"> 清除历史 </template>
              <TrashIcon
                class="!w-4 !h-4"
                :class="{
                  'ml-1': !simpleMode
                }"
              />
            </NButton>
          </template>
          <span>确定要清除历史消息吗？</span>
        </NPopconfirm>

        <NButton :disabled="completing" @click="toggleRecording">
          <template v-if="!simpleMode">
            {{ isRecording ? "停止输入" : "语音输入" }}
          </template>
          <microphone
            class="!w-4 !h-4"
            :class="{
              'ml-1': !simpleMode
            }"
          />
        </NButton>
      </div>
    </div>
  </div>
</template>
