<template>
  <!-- 原左侧折叠面板和右侧AI问答 -->
  <div class="content-wrapper">
      <div class="people-image">
        <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" @scroll="handleScroll">
              <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"
              />
                <!-- 语音输入按钮 -->
                <VoiceInput
                    @voiceRecognized="handleVoiceRecognized"
                    lang="zh-CN"
                    maxDuration="10"
                />

              <!-- 终止问答按钮 -->
              <div
                v-if="conversationInProgress"
                @click="handleStopButtonClick"
                class="stop-btn"
                title="终止问答"
              >
                <img :src="stopicon" alt="停止" />
              </div>
              <button
                v-if="!conversationInProgress"
                @click="handleSendByButton"
              >
                发送
              </button>
            </div>
          </div>
        </div>
      </div>
    </div>
</template>

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

import VoiceInput from '../voice/VoiceInput.vue'


// 终止按钮
import stopicon from "@/assets/icon/stopicon.png";

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

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

// 定义props
const props = defineProps({
  //根据需求传输
  isCourse: { type: Boolean, default: false},
  cacheDataKey: { type: String, default: localStorage.getItem('token') + "_ai_textToText" },
  cacheDataHistoryKey: { type: String, default: localStorage.getItem('token') + "_ai_textToText_history" },
  preDialogueList: { type: Array, default: () => []},
  replySupplement: { type: String, default: ''},

  personId: { type: Number},
  personName: { type: String },
  personImage: { type: String},
  personIntroduce: { type: String},
})

// 定义emits
const emits = defineEmits(['saveProgress'])

//历史记录缓存集合
const cacheDataHistoryList = ref([]);

// 默认消息控制
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 = () => {
  // 停止语音播放
  stopPlayback();
  router.push("/ai-laboratory");
};
const router = useRouter();
const route = useRoute();

const personId = ref(props.personId);
const personName = ref(props.personName);
const personImage = ref(props.personImage);
const personIntroduce = ref(props.personIntroduce);

// 渲染实验室携带的人物形象图片
const selectedImage = ref("");

// 聊天对话
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 userScrolled = ref(false)//是否用户手动滚动

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

/** 获取对话信息 */
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;


  // 获取对话消息列表【后面补充接口，现在取的浏览器缓存】
  // activeMessageList.value = await ChatMessageApi.getChatMessageListByConversationId(
  //     activeConversationId.value
  // )

  // 取缓存历史记录
  let cacheDataHistoryStr = localStorage.getItem(props.cacheDataHistoryKey);
  console.log("cacheDataHistoryStr", cacheDataHistoryStr);
  if (cacheDataHistoryStr) {
    cacheDataHistoryList.value = JSON.parse(cacheDataHistoryStr) || [];
    activeMessageList.value.push(...cacheDataHistoryList.value);
  }else{
    // 加入预置对话
    activeMessageList.value.push(...props.preDialogueList);
    cacheDataHistoryList.value.push(...props.preDialogueList);
    localStorage.setItem(props.cacheDataHistoryKey, JSON.stringify(cacheDataHistoryList.value));
  }
};

// 语音输入识别结果处理
const handleVoiceRecognized = (text) => {
  prompt.value += text;
};

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

/** 处理来自 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 doSendMessage = async (content) => {
  // 校验
  if (content.length < 1) {
    console.error("发送失败，原因：内容为空！");
    return;
  }
  if (activeConversationId.value == null) {
    console.error("请刷新创建新对话!");
    return;
  }

  // 通过emit事件通知父组件保存进度
  emits('saveProgress', "aiCount", 1)
  console.log(props.isCourse);
  if (props.isCourse){
    emits('saveProgress', "course", 100)
  }

  // 清空输入框
  prompt.value = "";

  // 同步历史记录缓存
  cacheDataHistoryList.value.push({
    type: "user",
    content: content,
    createTime: new Date(),
  });
  localStorage.setItem(props.cacheDataHistoryKey, JSON.stringify(cacheDataHistoryList.value));


  // 执行发送
  await doSendMessageStream({
    conversationId: activeConversationId.value,
    content: content,
  });
};


import { useAudioPlayer } from '@/api/tts/useAudioPlayer';
import {Message} from "@/utils/message/Message.js";

// 解构 stopPlayback 方法
const { playAudioChunk,stopPlayback } = 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.2 开始滚动
    textRoll();

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

    // 销毁语音读取
    stopPlayback();

    await sendChatMessageStream(
      userMessage.conversationId,
      userMessage.content, null,
      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;
      },
      () => {
        console.log(`结束对话！ `)
        stopStream();
      }
    );
  } catch (error) {
    console.error('发送消息失败:', error)
    stopStream()
  }
};

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

  // 设置为 false
  conversationInProgress.value = false;
};

/** 清空消息列表 */
const clearMessageList = () => {
  activeMessageList.value = [];
  prompt.value = "";
  receiveMessageFullText.value = "";
  receiveMessageDisplayedText.value = "";
};

/** 处理终止按钮点击 */
const handleStopButtonClick = async () => {
  // 手动点击时停止语音播放
  stopPlayback();
  // 调用stopStream停止流式传输
  await stopStream();
};

/**
 * 消息列表
 *
 * 和 {@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 [];
});

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

//处理滚动事件，判断用户是否手动滚动
const handleScroll = () => {
  if (messageListRef.value) {
    const { scrollTop, scrollHeight, clientHeight } = messageListRef.value
    // 当用户滚动距离底部超过50px时，认为是手动滚动
    userScrolled.value = scrollTop + clientHeight < scrollHeight - 50
  }
}

/** 滚动到 message 底部 */
const scrollToBottom = async (isIgnore = false) => {
  // 如果用户手动滚动过，不自动滚动
  if (userScrolled.value) return

  await nextTick();
  if (messageListRef.value) {
    requestAnimationFrame(() => {
      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 && props.replySupplement) {
          activeMessageList.value.push({
            type: "system",
            content: props.replySupplement,
          });
        }

        // 同步缓存历史记录
        if (!conversationInProgress.value) {
          cacheDataHistoryList.value.push({
            type: "system",
            content: receiveMessageFullText.value,
            createTime: new Date(),
          });
          localStorage.setItem(props.cacheDataHistoryKey, JSON.stringify(cacheDataHistoryList.value));
        }

        // 不是对话中可以结束
        if (!conversationInProgress.value) {
          textRoleRunning.value = false;
          clearTimeout(timer);
        } else {
          // 重新设置任务
          timer = setTimeout(task, textSpeed.value);
        }
      }
    };
    let timer = setTimeout(task, textSpeed.value);
  } catch {}
};


// 监听消息列表变化，自动滚动到底部
watch(
    () => messageList.value,
    () => {
      scrollToBottom();
    },
    { deep: true }
);

/** 初始化 **/
onMounted(async () => {

  // 从全局状态初始化年级ID
  gradeId.value = globalState.initGradeId();

  //默认加载没传递数字人表示的话---默认加载小智
  if (!personId.value) {
    let grade = route.query.grade || localStorage.getItem('selectedGrade')
    grade = "小学低年级"
    // 获取小学低年级AI数据
    const juniorAIRes = await teacherList({category: grade + 'AI'})
    const aiPerson = juniorAIRes.data.list.find(
        person => person.name === '小智'
    )
    if (aiPerson) {
      personId.value = aiPerson.id;
      personName.value = aiPerson.name;
      personImage.value = aiPerson.model2dPath;
      personIntroduce.value = aiPerson.systemMessage;
    }
  }

  // 确保selectedImage被设置
  selectedImage.value = personImage.value;

  //创建对话
  let cacheDataKeyData = localStorage.getItem(props.cacheDataKey);
  if (cacheDataKeyData) {
    activeConversationId.value = cacheDataKeyData;
  }else{
    // 智能问答
    CreateDialogue({ roleId: personId.value })
        .then((res) => {
          console.log("创建会话：", res);
          activeConversationId.value = res.data;
          //将会话存入会话缓存
          localStorage.setItem(props.cacheDataKey, activeConversationId.value)
        })
        .catch((error) => {
          console.error("请求出错:", error);
        });
  }

  await getConversation(personId.value);

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

// 路由参数变化监听
watch(
  () => route.query,
  (newQuery, oldQuery) => {
    // 只有当id变化时才更新数据，避免不必要的刷新
    if (newQuery.id && newQuery.id !== oldQuery?.id) {
       // 停止语音播放
      stopPlayback();
      // 更新相关数据
      personId.value = newQuery.id;
      personName.value = newQuery.name;
      personIntroduce.value = newQuery.message;
      personImage.value = newQuery.image;
      selectedImage.value = newQuery.image;

      // 重新初始化对话
      CreateDialogue({ roleId: newQuery.id })
        .then((res) => {
          activeConversationId.value = res.data;
        })
        .catch((error) => {
          console.error("请求出错:", error);
        });

      getConversation(newQuery.id);

      // 重置消息列表和默认消息显示状态
      activeMessageList.value = [];
      showDefaultMessages.value = true;
    }
  },
  { immediate: true, deep: true }
);

// 监听personImage变化，更新selectedImage
watch(
  () => personImage.value,
  (newImage) => {
    if (newImage) {
      selectedImage.value = newImage;
    }
  },
  { immediate: true }
);
// 组件卸载时清理语音资源
onUnmounted(() => {
  stopPlayback();
});

// 暴露方法给父组件
defineExpose({
  stopStream,
  clearMessageList,
  stopPlayback
});

</script>

<style scoped lang="scss">
@use "sass:math";
// 定义rpx转换函数
@function rpx($px) {
  @return math.div($px, 750) * 100vw;
}
.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);
}
// 侧边栏
.people-image {
  width: rpx(130);
  height: 100%;
  display: flex;
  background-color: #ece9fd;
  overflow: hidden;
}
.people-image img {
  width: rpx(120);
  height: auto;
  object-fit: contain;
}
.selected-image {
  flex: 1;
  margin: auto;
  display: flex;
  justify-content: center;
  align-items: center;
}
.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: rpx(7);
  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(5);

  .speech-btn {
    padding: rpx(5) rpx(10);
    background: #fff;
    border: 1px solid #ffce1b;
    border-radius: rpx(5);
    cursor: pointer;
    display: flex;
    align-items: center;

    &.recording {
      background: #ffeeba;
      border-color: #ffc107;

      .el-icon {
        color: #dc3545;
      }
    }

    .el-icon {
      font-size: rpx(8);
      color: #666;
    }
  }

  // 终止按钮样式
  .stop-btn {
    cursor: pointer;
    display: flex;
    align-items: center;
    img {
      width: rpx(20);
      height: rpx(20);
    }
  }
}
.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 0px 2px rgba(0, 0, 0, 0.3);
}
</style>
