<template>
  <!-- 数字人智能问答 -->
  <div class="home-container">
    <!-- 展开收起侧边栏 -->
    <div
      class="icon-expand"
      :style="{
        backgroundColor: drawerVisible ? '#44449c' : '#7F70C840',
        left: drawerVisible ? '18%' : '0',
      }"
      @click="toggleDrawer"
    >
      <span
        class="vertical-lines"
        :style="{
          color: drawerVisible ? '#8a78d0' : 'white',
        }"
        >||</span
      >
    </div>

    <!-- 左侧折叠面板 -->
    <LeftPanel ref="leftPanelRef" v-if="drawerVisible" />

    <!-- 原左侧折叠面板和右侧AI问答 -->
    <div class="content-wrapper">
      <div class="left-group2">
        <div class="title-box">
          <div class="box-icon" @click="goBack">
            <el-icon class="left-icon"><ArrowLeftBold /></el-icon>
            {{ personName }}
          </div>
        </div>
        <div class="selected-image">
          <img :src="selectedImage" alt="" />
        </div>
      </div>
      <!-- 右侧AI问答 -->
      <div class="number-people">
        <div class="content-box">
          <!-- AI对话框 -->
          <div class="chat-dialog">
            <!-- 对话消息列表 -->
            <div class="message-list" ref="messageListRef">
              <div v-for="(item, index) in messageList" :key="index">
                <!-- AI消息 -->
                <div class="ai-message" v-if="item.type !== 'user'">
                  <MarkdownView class="left-text" :content="item.content" />
                  <!-- {{item.content}} -->
                </div>

                <!-- 用户消息 -->
                <div class="user-message" v-if="item.type === 'user'">
                  {{ item.content }}
                </div>
              </div>
            </div>
            <!-- 默认消息 -->
            <DefaultMessage
              v-if="showDefaultMessages"
              @select-message="handleDefaultMessageSelect"
              :category="route.query.category"
              :quest-tip="route.query.default"
            />
            <!-- 输入框和发送按钮 -->
            <div class="input-section">
              <input
                type="text"
                v-model="prompt"
                placeholder="问我任何问题..."
                @keyup.enter="handleSendByKeydown"
              />
              <button @click="handleSendByButton">发送</button>
            </div>
          </div>
        </div>
      </div>
    </div>
  </div>
</template>

<script setup>
import {ref, onMounted, computed, watch, nextTick} from "vue";
import { CreateDialogue, sendChatMessageStream } from "@/api/questions.js";
import { useRouter, useRoute } from "vue-router";
import { saveRecord } from '@/api/personalized/index.js'
// 导入全局状态
import { globalState } from '@/utils/globalState.js'


import MarkdownView from "@/components/MarkdownView/index.vue";
import {
  Document,
  Menu as IconMenu,
  Location,
  Setting,
  ArrowLeftBold,
  MagicStick,
  ChatLineRound,
  Fold,
  Expand,
  Picture,
  Tickets,
  User,
} from "@element-plus/icons-vue";

import DefaultMessage from "@/components/DefaultMessage/index.vue";

// 导入图片
// import question from '@/assets/icon/question.png'
// import painting from '@/assets/icon/painting.png'
// import human from '@/assets/icon/human.png'

import LeftPanel from "@/components/LeftPanel.vue";
const leftPanelRef = ref(null);


// 默认消息控制
const showDefaultMessages = ref(true);
const handleDefaultMessageSelect = (message) => {
  prompt.value = message;
  handleSendByButton();
  showDefaultMessages.value = false;
};

// 添加抽屉显示状态
const drawerVisible = ref(true);
// 添加切换抽屉显示状态的函数
const toggleDrawer = () => {
  drawerVisible.value = !drawerVisible.value;
};

// 处理菜单展开和关闭
const handleOpen = () => {};
const handleClose = () => {};

// 返回上一页
const goBack = () => {
  router.push("/ai-laboratory");
};
const router = useRouter();
const route = useRoute();

const personId = ref(route.query.id);
const personName = ref(route.query.name);
const personIntroduce = ref(route.query.message);
const personImage = ref(route.query.image);

// 渲染实验室携带的人物形象图片
const selectedImage = ref("");
onMounted(() => {
  const image = route.query.image;
  if (image) {
    selectedImage.value = image;
  }
});

// 聊天对话
const activeConversationModelPath = ref(null); // 选中的对话编号
const activeConversationId = ref(null); // 选中的对话编号
const activeConversation = ref(null); // 选中的 Conversation
const conversationInProgress = ref(false); // 对话是否正在进行中。目前只有【发送】消息时，会更新为 true，避免切换对话、删除对话等操作，导致 stream 中断

// 消息列表
const messageRef = ref();
const activeMessageList = ref([]); // 选中对话的消息列表
const activeMessageListLoading = ref(false); // activeMessageList 是否正在加载中
const activeMessageListLoadingTimer = ref(); // activeMessageListLoading Timer 定时器。如果加载速度很快，就不进入加载中
// 消息滚动
const textSpeed = ref(50); // Typing speed in milliseconds
const textRoleRunning = ref(false); // Typing speed in milliseconds

// 发送消息输入框
const isComposing = ref(false); // 判断用户是否在输入
const conversationInAbortController = ref(); // 对话进行中 abort 控制器(控制 stream 对话)
const inputTimeout = ref(); // 处理输入中回车的定时器
const prompt = ref(); // prompt
const enableContext = ref(true); // 是否开启上下文
// 接收 Stream 消息
const receiveMessageFullText = ref("");
const receiveMessageDisplayedText = ref("");
const messageListRef = ref(null);


// =========== 【聊天对话】相关 ===========

/** 获取对话信息 */
const getConversation = async (id) => {
  if (!id) {
    return;
  }
  const conversation = ref({});
  if (!conversation) {
    return;
  }
  conversation.systemMessage = personIntroduce.value;
  activeConversation.value = conversation;
  // activeConversationId.value = personId.value
  activeConversationModelPath.value = personImage.value;
};

// =========== 【发送消息】相关 ===========

/** 处理来自 keydown 的发送消息 */
const handleSendByKeydown = async (event) => {
  // 判断用户是否在输入
  if (isComposing.value) {
    return;
  }
  // 进行中不允许发送
  if (conversationInProgress.value) {
    return;
  }
  const content = prompt.value?.trim();
  if (event.key === "Enter") {
    if (event.shiftKey) {
      // 插入换行
      prompt.value += "\r\n";
      event.preventDefault(); // 防止默认的换行行为
    } else {
      // 发送消息
      await doSendMessage(content);
      event.preventDefault(); // 防止默认的提交行为
    }
  }
};

/** 处理来自【发送】按钮的发送消息 */
const handleSendByButton = () => {
  doSendMessage(prompt.value?.trim());
};

/** 处理 prompt 输入变化 */
const handlePromptInput = (event) => {
  // 非输入法 输入设置为 true
  if (!isComposing.value) {
    // 回车 event data 是 null
    if (event.data == null) {
      return;
    }
    isComposing.value = true;
  }
  // 清理定时器
  if (inputTimeout.value) {
    clearTimeout(inputTimeout.value);
  }
  // 重置定时器
  inputTimeout.value = setTimeout(() => {
    isComposing.value = false;
  }, 400);
};
// TODO注：是不是可以通过 @keydown.enter、@keydown.shift.enter 来实现，回车发送、shift+回车换行；主要看看，是不是可以简化 isComposing 相关的逻辑
const onCompositionstart = () => {
  isComposing.value = true;
};
const onCompositionend = () => {
  setTimeout(() => {
    isComposing.value = false;
  }, 200);
};

// 保存记录
// 年级ID相关
const gradeId = ref('')
// 添加消息计数器变量
const messageCount = ref(0)
onMounted(() => {
   // 从全局状态初始化年级ID
  gradeId.value = globalState.initGradeId()
});

/** 真正执行【发送】消息操作 */
const doSendMessage = async (content) => {
  // 校验
  if (content.length < 1) {
    console.error("发送失败，原因：内容为空！");
    return;
  }
  if (activeConversationId.value == null) {
    console.error("还没创建对话，不能发送!");
    return;
  }
   // 递增消息计数器
  messageCount.value++
  // 发送saveRecord请求 保存消息次数
  try{
    await saveRecord({
        brpNjId: gradeId.value,
        brpType: "aiCount",
        brpProgress: messageCount.value
      });
  }catch(error){
    console.error('保存记录失败:', error);
  }
  // 清空输入框
  prompt.value = "";
  // 执行发送
  await doSendMessageStream({
    conversationId: activeConversationId.value,
    content: content,
  });
};


import { useAudioPlayer } from '@/components/TTS/useAudioPlayer';

const { playAudioChunk } = useAudioPlayer();

/** 真正执行【发送】消息操作 */
const doSendMessageStream = async (userMessage) => {
  // 创建 AbortController 实例，以便中止请求
  conversationInAbortController.value = new AbortController();
  // 标记对话进行中
  conversationInProgress.value = true;
  // 设置为空
  receiveMessageFullText.value = "";

  try {
    // 1.1 先添加两个假数据，等 stream 返回再替换
    activeMessageList.value.push({
      id: -1,
      conversationId: activeConversationId.value,
      type: "user",
      content: userMessage.content,
      createTime: new Date(),
    });
    activeMessageList.value.push({
      id: -2,
      conversationId: activeConversationId.value,
      type: "assistant",
      content: "思考中...",
      createTime: new Date(),
    });

    // 1.3 开始滚动
    textRoll();

    // 2. 发送 event stream
    let isFirstChunk = true; // 是否是第一个 chunk 消息段

    await sendChatMessageStream(
      userMessage.conversationId,
      userMessage.content,
      conversationInAbortController.value,
      enableContext.value,
      async (res) => {
        const { code, data, msg } = JSON.parse(res.data);
        if (code !== 0) {
          console.log(`对话异常! ${msg}`);
          return;
        }

        // 根据事件类型处理
        if (data.eventType === 'TEXT') {

          // 如果内容为空，就不处理。
          if (data.receive?.content === '') {
            return
          }

          // 处理文本消息
          receiveMessageFullText.value += data.receive.content;

          // 首次返回需要添加一个 message 到页面，后面的都是更新
          if (isFirstChunk) {
            isFirstChunk = false;
            // 弹出两个假数据
            activeMessageList.value.pop();
            activeMessageList.value.pop();
            // 更新返回的数据
            activeMessageList.value.push(data.send);
            activeMessageList.value.push(data.receive);
          }
        } else if (data.eventType === 'AUDIO') {
          // 处理音频消息
          await playAudioChunk(data.audioData);
        }
      },
      (error) => {
        console.log(`对话异常! ${error}`);
        stopStream();
        // 需要抛出异常，禁止重试
        throw error;
      },
      () => {
        stopStream();
      }
    );
  } catch {}
};

/** 停止 stream 流式调用 */
const stopStream = async () => {
  // tip：如果 stream 进行中的 message，就需要调用 controller 结束
  if (conversationInAbortController.value) {
    conversationInAbortController.value.abort();
  }
  // 设置为 false
  conversationInProgress.value = false;
};

/**
 * 消息列表
 *
 * 和 {@link #getMessageList()} 的差异是，把 systemMessage 考虑进去
 */
const messageList = computed(() => {
  if (activeMessageList.value.length > 0) {
    return activeMessageList.value;
  }

  // 没有消息时，如果有 systemMessage 则展示它
  if (activeConversation.value?.systemMessage) {
    let systemMessage = {
      id: 0,
      type: "system",
      content: activeConversation.value.systemMessage,
    };
    activeMessageList.value.push(systemMessage);
    return [systemMessage];
  }
  return [];
});

// ============== 【消息滚动】相关 =============

/** 滚动到 message 底部 */
const scrollToBottom = async (isIgnore = false) => {
  await nextTick();
  if (messageListRef.value) {
    messageListRef.value.scrollTop = messageListRef.value.scrollHeight;
  }
};

/** 自提滚动效果 */
const textRoll = async () => {
  let index = 0;
  try {
    // 只能执行一次
    if (textRoleRunning.value) {
      return;
    }
    // 设置状态
    textRoleRunning.value = true;
    receiveMessageDisplayedText.value = "";
    const task = async () => {
      // 调整速度
      const diff =
        (receiveMessageFullText.value.length -
          receiveMessageDisplayedText.value.length) /
        10;
      if (diff > 5) {
        textSpeed.value = 10;
      } else if (diff > 2) {
        textSpeed.value = 30;
      } else if (diff > 1.5) {
        textSpeed.value = 50;
      } else {
        textSpeed.value = 100;
      }
      // 对话结束，就按 30 的速度
      if (!conversationInProgress.value) {
        textSpeed.value = 10;
      }

      if (index < receiveMessageFullText.value.length) {
        receiveMessageDisplayedText.value += receiveMessageFullText.value[index];
        index++;

        // 更新 message
        const lastMessage =
          activeMessageList.value[activeMessageList.value.length - 1];
        lastMessage.content = receiveMessageDisplayedText.value;
        // 滚动到住下面
        await scrollToBottom();
        // 重新设置任务
        timer = setTimeout(task, textSpeed.value);
      } else {
        // 不是对话中可以结束
        if (!conversationInProgress.value) {
          textRoleRunning.value = false;
          clearTimeout(timer);
        } else {
          // 重新设置任务
          timer = setTimeout(task, textSpeed.value);
        }
      }
    };
    let timer = setTimeout(task, textSpeed.value);
  } catch {}
};

/** 初始化 **/
onMounted(async () => {
  if (personId.value) {
    // 智能问答
    CreateDialogue({ roleId: personId.value })
      .then((res) => {
        console.log("创建会话：", res);
        activeConversationId.value = res.data;
      })
      .catch((error) => {
        console.error("请求出错:", error);
      });

    await getConversation(personId.value);
  }

  // 获取列表数据
  // activeMessageListLoading.value = true
});



</script>

<style scoped lang="scss">
@use "sass:math";
// 定义rpx转换函数
@function rpx($px) {
  @return math.div($px, 750) * 100vw;
}
/* 添加过渡样式 */
.drawer-slide-enter-active,
.drawer-slide-leave-active {
  transition: all 0.3s ease;
}

.drawer-slide-enter-from,
.drawer-slide-leave-to {
  transform: translateX(-100%);
  opacity: 0;
}
.home-container {
  position: fixed;
  top: 0;
  left: 0;
  right: 0;
  bottom: 0;
  display: flex;
  flex-direction: row;
  gap: rpx(0);
  background: linear-gradient(to bottom, #e2ddfc, #f1effd);
}

.icon-expand {
  width: rpx(8);
  height: rpx(35);
  border-top-right-radius: rpx(5);
  border-bottom-right-radius: rpx(5);
  z-index: 9999;
  position: absolute;
  top: 50%;
  left: 18%;
  transform: translateY(-50%);
  background-color: #44449c;
  cursor: pointer; // 添加鼠标指针样式
  clip-path: polygon(0 0, 100% 15%, 100% 85%, 0 100%);
  display: flex;
  justify-content: center;
  align-items: center;
  transition: all 0.3s ease;
}
.icon-expand .vertical-lines {
  color: #8a78d0;
  font-size: rpx(10);
}
.menu-icon {
  width: rpx(11);
  height: rpx(11);
  margin-right: rpx(2);
}
.content-wrapper {
  display: flex;
  flex: 1;
}
.left-group {
  width: rpx(135);
  height: 100%;
  background: linear-gradient(to bottom, #001169, #8a78d0);
}
.mb-2 {
  color: black;
  margin-top: rpx(1);
}
.tac ::v-deep(.el-menu) {
  background-color: transparent;
  border: none;
  width: 100%;
  margin-top: rpx(55);
  margin-left: rpx(10);
}
.el-menu-item {
  width: rpx(115);
  height: rpx(25);
  margin-bottom: rpx(5);
  border-radius: rpx(6);
  color: white;
  font-size: rpx(8);
}
.el-menu-item .el-icon svg {
  font-size: rpx(15);
  color: white;
}

.el-menu ::v-deep(.el-menu-item:hover),
.el-menu ::v-deep(.el-menu-item:focus),
.el-menu ::v-deep(.el-menu-item:active) {
  background: linear-gradient(
    to bottom,
    #ffefb0,
    #ffcc00
  ); /* 设置悬停、聚焦、点击状态下的背景色 */
  box-shadow: 0 8px 8px rgb(0, 0, 0, 0.3);
  color: black;
  font-size: rpx(8);
}
.el-menu .el-menu-item.is-active {
  background: linear-gradient(to bottom, #fee78a, #ffce1b);
  color: black;
  font-size: rpx(8);
  box-shadow: 0 4px 8px rgba(3, 3, 3, 0.3);
}
// 侧边栏
.left-group2 {
  width: rpx(150);
  height: 100%;
  display: flex;
  background-color: #ece9fd;
}
.left-group2 img {
  width: rpx(120);
  // height: auto;
}
.selected-image {
  flex: 1;
  margin: auto;
  margin-left: rpx(-60);
}
.title-box {
  height: rpx(50);
}
.box-icon {
  width: 100%;
  height: 100%;
  flex: 1;
  display: flex; // 添加 flex 布局
  align-items: center; // 垂直居中
  color: black; // 设置图标颜色为白色
  padding-left: rpx(15);
  font-size: rpx(10); // 设置图标大小，可按需调整
  cursor: pointer; // 添加鼠标指针样式
}
.box-icon .left-icon {
  margin-left: rpx(10);
  margin-right: rpx(5); // 设置图标和文字之间的间距 ;
}

.number-people {
  flex: 1;
  height: 100%;
  display: flex;
  background-color: #ece9fd;
}
.content-box {
  flex: 1;
  margin-top: rpx(10);
  margin-bottom: rpx(10);
  margin-right: rpx(10);
  border-radius: rpx(15);
  background: rgba($color: #ffffff, $alpha: 0.5);
}

// 对话框
.chat-dialog {
  display: flex;
  flex-direction: column;
  height: 100%;
}
.message-list {
  flex: 1;
  overflow-y: auto;
  padding: rpx(15);
}
/* 自定义滚动条样式 */
.message-list::-webkit-scrollbar {
  width: rpx(2); /* 滚动条宽度 */
}
.message-list::-webkit-scrollbar-track {
  background: #f1effd; /* 滚动条轨道背景色 */
  border-radius: rpx(4);
}
.message-list::-webkit-scrollbar-thumb {
  background: #e2ddfc; /* 滚动条滑块颜色 */
  border-radius: rpx(4);
}
.message-list::-webkit-scrollbar-thumb:hover {
  background: #e2ddfc; /* 滚动条滑块 hover 状态颜色 */
}
.message-list .user-message {
  background-color: #ffffff;
  margin-left: auto; // 消息靠右显示
  margin-right: 0; // 重置右边距
  margin-bottom: rpx(10);
  max-width: rpx(400);
  font-size: rpx(8);
  width: fit-content; // 宽度随文字内容变化
  border-radius: rpx(5);
  padding: rpx(5);
  text-align: left; // 文字左对齐
}
.message-list .ai-message {
  background-color: #ffdd55;
  margin-left: 0; // 消息靠左显示
  margin-right: auto; // 重置右边距
  margin-bottom: rpx(10);
  width: fit-content;
  max-width: rpx(400);
  padding: rpx(5);
  font-size: rpx(8);
  border-radius: rpx(5);
  text-align: left; // 文字左对齐
}
.input-section {
  display: flex;
  padding: rpx(10);
  gap: rpx(10);
}
.input-section input {
  flex: 1;
  padding: rpx(5);
  font-size: rpx(7);
  border: 1px solid #ccc;
  border-radius: rpx(5);
}
.input-section button {
  padding: rpx(5) rpx(15);
  background: linear-gradient(
    to bottom,
    #fee78a,
    #ffce1b
  ); /* 设置悬停、聚焦、点击状态下的背景色 */
  color: black;
  border: none;
  font-size: rpx(7);
  border-radius: rpx(5);
  cursor: pointer;
  box-shadow: 0 4px 8px rgba(202, 52, 52, 0.3);
}
</style>
