<script setup lang="ts">
import type { ChatTimeTimelineItem } from '@easyflow/types';

import { onBeforeUnmount, onMounted, ref } from 'vue';
import { useRoute, useRouter } from 'vue-router';

import { ArrowLeft, Minus, Plus } from '@element-plus/icons-vue';
import {
  ChatTimeHistoryMapper,
  ChatTimeTimelineBuilder,
  createChatVariantSwitchController,
} from '@easyflow/utils';
import {
  ElAside,
  ElAvatar,
  ElButton,
  ElContainer,
  ElIcon,
  ElMain,
  ElMessage,
  ElSpace,
} from 'element-plus';
import { tryit } from 'radash';

import { api } from '#/api/request';
import defaultBotAvatar from '#/assets/defaultBotAvatar.png';
import { Card, CardDescription, CardTitle } from '#/components/card';
import { ChatBubbleList, ChatSender } from '#/components/chat';
import { $t } from '#/locales';

onMounted(async () => {
  getUserUsed();
  getBotDetail();
});
onBeforeUnmount(() => {
  if (prefetchTimer) {
    clearTimeout(prefetchTimer);
  }
});
const router = useRouter();
const route = useRoute();
const usedList = ref<any[]>([]);
const botInfo = ref<any>({});
const btnLoading = ref(false);
const conversationId = ref('');
const senderRef = ref<InstanceType<typeof ChatSender>>();
function getUserUsed() {
  api.get('/userCenter/botRecentlyUsed/list').then((res) => {
    usedList.value = res.data.map((item: any) => item.botId);
  });
}
function getBotDetail() {
  api
    .get('/userCenter/bot/getDetail', {
      params: {
        id: route.params.id,
      },
    })
    .then((res) => {
      botInfo.value = res.data;
    });
  api.get('/userCenter/bot/generateConversationId').then((res) => {
    conversationId.value = res.data;
  });
}
function addBotToRecentlyUsed(botId: any) {
  btnLoading.value = true;
  api
    .post('/userCenter/botRecentlyUsed/save', {
      botId,
    })
    .then((res) => {
      btnLoading.value = false;
      if (res.errorCode === 0) {
        ElMessage.success($t('message.success'));
        getUserUsed();
      }
    });
}
function removeBotFromRecentlyUsed(botId: any) {
  btnLoading.value = true;
  api
    .get('/userCenter/botRecentlyUsed/removeByBotId', {
      params: {
        botId,
      },
    })
    .then((res) => {
      btnLoading.value = false;
      if (res.errorCode === 0) {
        ElMessage.success($t('message.success'));
        getUserUsed();
      }
    });
}
const messageList = ref<ChatTimeTimelineItem[]>([]);
const variantSwitchStateVersion = ref(0);
let prefetchTimer: ReturnType<typeof setTimeout> | undefined;
const variantSwitchController = createChatVariantSwitchController<any, ChatTimeTimelineItem>({
  mapRecords: (records) => ChatTimeHistoryMapper.fromHistoryRecords(records),
  onError: () => ElMessage.error('答案版本切换失败'),
  onStateChange: () => {
    variantSwitchStateVersion.value += 1;
  },
  replaceRound(items, roundId, nextItems) {
    ChatTimeTimelineBuilder.replaceRoundMessages(items, roundId, nextItems);
  },
});
function mutateMessages(mutator: (messages: ChatTimeTimelineItem[]) => void) {
  const next = [...messageList.value];
  mutator(next);
  messageList.value = next;
  schedulePrefetchVisibleVariants();
}

async function handleRegenerate(item: ChatTimeTimelineItem) {
  if (!item.roundId) {
    return;
  }
  const prompt = resolveRoundPrompt(String(item.roundId));
  if (!prompt) {
    return;
  }
  senderRef.value?.sendMessage({
    prompt,
    regenerateRoundId: String(item.roundId),
  });
}

async function handleSelectVariant(
  item: ChatTimeTimelineItem,
  direction: 'next' | 'previous',
) {
  if (!item.roundId || !conversationId.value) {
    return;
  }
  const current = Number(item.variantIndex || item.selectedVariantIndex || 1);
  const variantIndex = direction === 'previous' ? current - 1 : current + 1;
  const sessionId = conversationId.value;
  await variantSwitchController.switchVariant({
    fetchVariants: () => fetchRoundVariants(sessionId, item.roundId!),
    items: messageList.value,
    persistVariant: async () => {
      const [, res] = await tryit(api.post)(
        `/userCenter/chatHistory/sessions/${sessionId}/rounds/${item.roundId}/selectVariant`,
        {
          variantIndex,
        },
      );
      if (res?.errorCode !== 0 || !res?.data) {
        throw new Error(String((res as any)?.message || '答案版本切换失败'));
      }
      return res.data;
    },
    roundId: item.roundId,
    sessionId,
    targetVariantIndex: variantIndex,
  });
}

function resolveRoundPrompt(roundId: string) {
  const target = [...messageList.value].reverse().find(
    (item) => item.role === 'user' && item.roundId === roundId,
  );
  return String(target?.content || '').trim();
}

async function fetchRoundVariants(sessionId: string, roundId: string | number) {
  const [, res] = await tryit(api.get)(
    `/userCenter/chatHistory/sessions/${sessionId}/rounds/${roundId}/variants`,
  );
  if (res?.errorCode !== 0) {
    throw new Error(String((res as any)?.message || '答案版本加载失败'));
  }
  return res?.data || [];
}

function schedulePrefetchVisibleVariants() {
  if (prefetchTimer) {
    clearTimeout(prefetchTimer);
  }
  prefetchTimer = setTimeout(() => {
    prefetchVisibleVariants();
  }, 120);
}

function prefetchVisibleVariants() {
  if (!conversationId.value) {
    return;
  }
  const prefetchedRoundIds = new Set<string>();
  for (const item of messageList.value) {
    if (
      item.role !== 'assistant' ||
      !item.roundId ||
      Number(item.variantCount || 0) <= 1 ||
      prefetchedRoundIds.has(String(item.roundId))
    ) {
      continue;
    }
    prefetchedRoundIds.add(String(item.roundId));
    variantSwitchController.prefetchVariants({
      fetchVariants: () => fetchRoundVariants(conversationId.value, item.roundId!),
      roundId: item.roundId,
      sessionId: conversationId.value,
    });
  }
}

function currentSwitchingRoundIds() {
  void variantSwitchStateVersion.value;
  if (!conversationId.value) {
    return [];
  }
  return Array.from(
    new Set(
      messageList.value
        .filter(
          (item) =>
            item.roundId &&
            variantSwitchController.isSwitching(
              conversationId.value,
              item.roundId,
            ),
        )
        .map((item) => String(item.roundId)),
    ),
  );
}
</script>

<template>
  <ElContainer class="bg-background-deep h-full p-6 pr-0">
    <ElMain
      class="border-border bg-background !flex flex-col rounded-xl border !p-6"
    >
      <ElSpace :size="16" class="cursor-pointer" @click="router.back()">
        <ElIcon :size="24"><ArrowLeft /></ElIcon>
        <ElSpace :size="12">
          <ElAvatar :size="36" :src="botInfo.icon || defaultBotAvatar" />
          <h1 class="text-base font-semibold">
            {{ botInfo.title }}
          </h1>
        </ElSpace>
      </ElSpace>
      <div class="relative mx-auto w-full max-w-[884px] flex-1">
        <Card
          v-if="messageList.length === 0"
          class="absolute left-1/2 top-1/2 max-w-[340px] -translate-x-1/2 -translate-y-1/2 flex-col items-center gap-0"
        >
          <ElAvatar :size="64" :src="botInfo.icon || defaultBotAvatar" />
          <CardTitle class="mt-4">{{ botInfo.title }}</CardTitle>
          <CardDescription class="mt-2.5 text-center text-[#566882]">
            {{ botInfo.description }}
          </CardDescription>
        </Card>
        <ChatBubbleList
          v-else
          :bot="botInfo"
          :messages="messageList"
          allow-regenerate
          allow-variant-switch
          :switching-round-ids="currentSwitchingRoundIds()"
          @regenerate="handleRegenerate"
          @select-next-variant="handleSelectVariant($event, 'next')"
          @select-previous-variant="handleSelectVariant($event, 'previous')"
        />
        <ChatSender
          ref="senderRef"
          class="absolute bottom-5 left-0 w-full"
          :bot="botInfo"
          :conversation-id="conversationId"
          :mutate-messages="mutateMessages"
        />
      </div>
    </ElMain>
    <ElAside width="407px" class="px-3 pt-10">
      <Card class="mx-auto max-w-[340px] flex-col items-center gap-0">
        <ElAvatar :size="64" :src="botInfo.icon || defaultBotAvatar" />
        <CardTitle class="mt-4">{{ botInfo.title }}</CardTitle>
        <CardDescription class="mt-2.5 text-center text-[#566882]">
          {{ botInfo.description }}
        </CardDescription>
        <ElButton
          v-if="!usedList.includes(botInfo.id)"
          :loading="btnLoading"
          class="mt-8 !h-9 w-full"
          type="primary"
          :icon="Plus"
          @click="addBotToRecentlyUsed(botInfo.id)"
        >
          添加到聊天助理
        </ElButton>
        <ElButton
          v-else
          :loading="btnLoading"
          class="mt-8 !h-9 w-full"
          type="primary"
          :icon="Minus"
          @click="removeBotFromRecentlyUsed(botInfo.id)"
        >
          从聊天助理中移除
        </ElButton>
      </Card>
    </ElAside>
  </ElContainer>
</template>
