<template>
  <div style="height: 100%">
    <!-- 对话内容-->
    <div class="message-content" ref="messageContent">
      <ReadingCreateMessage id="readingMessageContent" v-for="(item, index) in chatInfo" :key="index" :chatInfo="item" :index="index"
                            @removeIndex="removeIndex(index)"  @refresh="refresh"/>
    </div>

    <!-- 文字窗口-->
    <div>
      <div class="tool-bar">
        <div class="label">
          <!--          <img src="../assets/images/writing/start.png">
                    <div>AI写作助手</div>-->
        </div>
        <div class="clean" @click="cleanChat">
          <img src="../assets/images/writing/brush.png">
          <div>清除对话</div>
        </div>
      </div>

      <div class="text-box">
        <div class="quote-box" v-if="quoteMsg">
          <div class="vertical-line"></div>
          <div class="quote-info" :title="quoteMsg">{{ quoteMsg }}</div>
          <div class="quote-close" @click="clearQuote"><img src="@/assets/images/close.png" alt=""></div>
        </div>
        <textarea
            v-model.trim="textarea"
            class="box-textarea"
            :class="quoteMsg ? 'quote-textarea' : ''"
            type="textarea"
            maxlength="1000"
            @input="handleInput"
            @keydown.enter="keyDown"
            placeholder="请输入你想提的问题，字数不能超过1000字"/>
        <div>
          <img v-if="textarea&&!sendStatus" style="width: 38px" src="../assets/images/writing/send-blue.png" @click="send('','0')">
          <img v-if="!textarea&&!sendStatus" src="../assets/images/writing/send-gray.png">
          <img v-if="sendStatus" src="../assets/images/chat/stopChat.png" @click="handleStop"></img>
        </div>
      </div>

      <div class="bottom">以上内容均由AI生成, 仅供参考和借鉴。</div>
    </div>
  </div>
</template>

<script setup lang='ts'>
import {inject, onMounted, reactive, ref} from "vue";
import {
  deleteChatMessageById,
  delHistoryChatById,
  fetchChatAPI,
  fetchConversationId,
  interrupt,
  listChatMessage,
  listFileChatHistory
} from "@/api";
import {generateAuthInfo} from "@/utils/request/headerUtils";
import ReadingCreateMessage from "@/components/ReadingCreateMessage.vue";
import {withLoading} from "@/utils/loading";
import {ElMessage} from "element-plus";
import {debounce} from "@/utils";
// 引用内容
const quoteMsg = inject("quoteMsg");
const updateQuoteMsg = inject("updateQuoteMsg");
/**
 * 清除引用信息
 */
const clearQuote = () => {
  updateQuoteMsg('');
}

//const title = inject('aiboxTitle');
const textarea = ref("");
const firstChat = ref(true);
const sendStatus = ref(false);
const chatStatus = ref(false);
const chatNumber = ref(0);
const chatId = ref('');
const historyParam = history.state;
const conversationId = ref('');
const chatInfo = reactive([]);
let controller = null;
const baseURL = import.meta.env.VITE_GLOB_API_CTX;

const cleanChat = async () => {
  if(chatId.value){
    try {
      withLoading(await delHistoryChatById(chatId.value));
      chatInfo.length = 0;
      chatId.value = '';
      firstChat.value = true;
    } catch (error: any) {
      ElMessage.error(error && error.message ? error.message : '未知错误');
    }
  }
}

const removeIndex = async (index) => {
  try {
    await deleteChatMessageById(chatInfo[index].user.conversationId);
    chatInfo.splice(index, 1);
  } catch (error: any) {
    ElMessage.error(error && error.message ? error.message : '未知错误');
  }
};

const readingBoxSend = (quote: string, type: string) => {
  send(quote, type);
}
defineExpose({
  readingBoxSend
})

let send = async (quote: string, type: string) => {
  if (quote && quote.trim()) {
    textarea.value = quote;
  }
  if (textarea.value === "" || sendStatus.value) {
    return;
  }

  sendStatus.value = true;

  //如果是第一次创建对话，先获取对话的id，chatNumber
  if (firstChat.value) {
    await getFetchChatAPI(textarea.value);
  }
  //获取conversationId
  await getFetchConversationId(textarea.value);
  chatStatus.value = true;

  //流式会话
  await getFetchChatAPIProcess(type);
  firstChat.value ? (firstChat.value = false) : "";
  sendStatus.value = false;
};

// 获取对话 chatNumber  chatId，promt是对话
const getFetchChatAPI = async (prompt) => {
  const chatData = {
    prompt,
    type: 99,
    fileId: historyParam.fileId
  };
  try {
    const fetchChatAPIData = await fetchChatAPI(chatData);
    chatNumber.value = fetchChatAPIData.data.chatNumber;
    chatId.value = fetchChatAPIData.data.id;
  } catch (error: any) {
    ElMessage.error(error && error.message ? error.message : '未知错误');
  }
};

//根据所写的问题获取conversationId
const getFetchConversationId = async (prompt) => {
  const messageData = {
    chatNumber: chatNumber.value,
    prompt,
    model: "QIANWEN",
    promptName: "default",
    promptTitle: "default",
    promptPrompt: '请输入你想提的问题，字数不能超过1000字',
    chatId: chatId.value,
  };
  try {
    const fetchConversationIdData = await fetchConversationId(messageData);
    conversationId.value = fetchConversationIdData.data;
  } catch (error: any) {
    ElMessage.error(error && error.message ? error.message : '未知错误');
  }
};

// 对话，流式对话
const getFetchChatAPIProcess = async (type: string) => {
  const info = reactive({
    user: {content: textarea.value, conversationId: "", quote: quoteMsg.value},
    ai: {content: "", question: [], contentStatus: false},
  });
  textarea.value = "";
  chatInfo.push(info);
  autoScroll();

  let aiQuestion = ``;
  if (!controller) {
    controller = new AbortController();
  }
  let headers = generateAuthInfo();
  headers["Content-Type"] = "application/json";
  const response = await fetch(
      `${baseURL}/knowledgeChat/chatSelf?conversationId=${conversationId.value}&promptName=default?type=` + type,
      {
        method: "POST",
        headers: headers,
        signal: controller.signal,
        body: JSON.stringify({
          fileNames: [historyParam.embeddingId],
          conversationId: conversationId.value,
          promptName: "default",
          knowledgeBaseIdList: [historyParam.folderId],
          chatType: type,
          quote: quoteMsg.value
        }),
      }
  );

  const reader = response.body.getReader();
  const decoder = new TextDecoder();
  let done = false;
  let result = "";
  let picTemp = false;
  // 逐块读取流数据
  while (!done) {
    const {value, done: doneReading} = await reader.read();
    done = doneReading;
    result += decoder.decode(value, {stream: true});

    // 分割数据并逐条展示
    const lines = result.split("\n");
    for (let i = 0; i < lines.length - 1; i++) {
      let lineObj = JSON.parse(lines[i]);
      if (
          !info.user.conversationId ||
          info.user.conversationId != lineObj.conversationId
      ) {
        info.user.conversationId = lineObj.conversationId;
      }
      if (lineObj.text) {
        let index = info.ai.content.indexOf("思考中...");
        if (index != -1) {
          let text = info.ai.content.substring(0, index);
          info.ai.content = text;
        }
        if (info.ai.content.indexOf(".png)") != -1 && info.ai.content.indexOf("http") != -1) {
          info.ai.content = info.ai.content.replace("(http", "http");
          info.ai.content = info.ai.content.replace(".png)", ".png");

          picTemp = true;
        }
        info.ai.content += lineObj.text;

      } else if (lineObj.docs) {
        info.ai.content += `\n**参考文献:**`;
        for(let i=0;i<lineObj.docs.length;i++){
          lineObj.docs[i]=lineObj.docs[i].replaceAll(/\(\.files.*?\)/g, "");
          lineObj.docs[i]=lineObj.docs[i].replaceAll(/\(\.\/files.*?\)/g, "");
        }
        if(lineObj.docs.length>0){
          let lineObjDocs=lineObj.docs.join("\n\n\n");
          info.ai.content += '<div class="docs">'+lineObjDocs+'</div>';
        }else{
          info.ai.content += `<div class="docs">${lineObj.docs}</div>`;
        }
      }
    }
    // 保留最后一块数据，等待下一次读取
    result = lines[lines.length - 1];
    // 自动滚动到最新位置
    autoPositionToBottom();
  }
};
const refresh=async (content:string )=>{
  //获取conversationId
  await getFetchConversationId(content);
  sendStatus.value = true;
  chatStatus.value = true;

  textarea.value=content;
  //流式会话
  await getFetchChatAPIProcess('0');
  firstChat.value ? (firstChat.value = false) : "";
  sendStatus.value = false;
}

const messageContent=ref(null);

const autoScroll=()=>{
  if(messageContent.value){
    setTimeout(()=>{
      messageContent.value.scrollTop = messageContent.value.scrollHeight;
    })
  }
}

/**
 * 监听滚动条
 */
// 标志位：用户是否手动滚动
const isUserScrolled = ref(false);
const handleReadingMessageContentScroll = () => {
  const element = document.getElementById("readingMessageContent");
  if (!element) return;

  element.addEventListener("scroll", () => {
    const scrollTop = element.scrollTop;
    const scrollHeight = element.scrollHeight;
    const clientHeight = element.clientHeight;

    if (scrollTop + clientHeight < scrollHeight - 55) {
      isUserScrolled.value = true; // 用户手动滚动
    } else {
      isUserScrolled.value = false; // 用户滚动到最下方
    }
  });
}
// 滚动条自定位
const autoPositionToBottom = () => {
  const element = document.getElementById("readingMessageContent");
  if (!element || isUserScrolled.value) return;

  element.scrollTop = element.scrollHeight + 55;
}

onMounted(async () => {
  //请求文件对话的dataId
  try {
    let hisResponse = await listFileChatHistory(historyParam.fileId);
    //根据dataId请求获取历史记录
    if (hisResponse.code == 200 && hisResponse.data) {
      chatNumber.value = hisResponse.data;
      firstChat.value = false;
      //请求文件对话的dataId
      let historyList = await listChatMessage({
        chatNumber: chatNumber.value,
        fileType: 1
      });
      let chatInfoBack = historyList.data;
      chatId.value = chatInfoBack[0].chatId;
      for (let i = 0; i < chatInfoBack.length;) {
        let index = chatInfoBack[i + 1].content.indexOf("**参考文献:**");
        let aiStrDoc = "";
        let aisStr = "";
        if (
            chatInfoBack[i + 1].content &&
            chatInfoBack[i + 1].content.indexOf("**参考文献:**") != -1
        ) {
          aiStrDoc = chatInfoBack[i + 1].content.substring(index + 9);
          aiStrDoc=aiStrDoc.replaceAll(/\(\.files.*?\)/g, "");
          aiStrDoc=aiStrDoc.replaceAll(/\(\.\/files.*?\)/g, "");

          aisStr =
              chatInfoBack[i + 1].content.substring(0, index + 9) +
              `<div class="docs">\n${aiStrDoc}</div>`;
        } else {
          aisStr = chatInfoBack[i + 1].content;
        }
        let info = {
          user: {
            content: chatInfoBack[i].content,
            conversationId: chatInfoBack[i].messageId,
          },
          ai: {content: aisStr},
        };
        chatInfo.push(info);
        i = i + 2;
      }
    }
  } catch (error: any) {
    ElMessage.error(error && error.message ? error.message : '未知错误');
  }

  handleReadingMessageContentScroll();
})
let messageInstance = null;

// 自定义的错误消息显示函数
const customErrorMessage = (options) => {
  if (messageInstance) {
    messageInstance.close(); // 如果已有消息实例，则关闭它
  }
  messageInstance = ElMessage.error(options); // 创建新的错误消息实例
};

const handleInput = (event) => {
  if (textarea.value.length >= 1000 ) {
    // 显示警告框
    customErrorMessage('您已达到最大字数限制，无法继续输入更多内容。');

    // 强制设置textarea的内容为截断后的值
    textarea.value = textarea.value.substring(0, 1000);
  }
};

/**
 * 输入框的回车事件
 * @param e
 */
const keyDown = (e) => {
  if (e.key === 'Enter' && !e.shiftKey) {
    e.preventDefault();
    if (!sendStatus.value) {
      debounce(() => {
        send('','0')
      });
    }
  }
}

const handleStop = async () => {
  controller.abort();
  controller = null;
  let messageData = {
    messageId: conversationId.value
  };
  await interrupt(messageData);
  if (
      chatInfo[chatInfo.length - 1].ai.content == "" ||
      chatInfo[chatInfo.length - 1].ai.content == "思考中..."
  ) {
    chatInfo[chatInfo.length - 1].ai.content = "已停止响应";
  }

  sendStatus.value = false;
};
</script>

<style lang="less" scoped>
.message-content {
  height: calc(100% - 255px);
  overflow-y: auto;
  padding: 20px;

  &::-webkit-scrollbar {
    width: 0;
  }
}

.background-color {
  width: 490px;
  height: 30px;
  margin-left: 20px;
  background: linear-gradient(360deg, #C0D4FD 0%, rgba(199, 219, 255, 0) 100%);
  border-radius: 0px 0px 0px 0px;
  position: fixed;
  bottom: 300px;
}

.tool-bar {
  display: flex;
  justify-content: space-between;
  width: 505px;
  padding-top: 30px;
  height: 65px;
  position:absolute;
  bottom:275px;
  background: linear-gradient( 360deg, #C0D4FD 0%, rgba(199,219,255,0) 100%);
  .label {
    display: flex;
    justify-content: space-around;
    margin-left: 20px;

    img {
      width: 16px;
      height: 16px;
    }

    div {
      font-family: PingFang SC, PingFang SC;
      font-weight: bold;
      font-size: 16px;
      color: #000000;
      line-height: 16px;
      margin-left: 4px;
    }
  }

  .clean {
    width: 84px;
    height: 24px;
    background: #004EA0;
    border-radius: 4px 4px 4px 4px;
    display: flex;
    justify-content: space-around;
    cursor: pointer !important;
    margin-right: 20px;

    img {
      width: 12px;
      height: 12px;
      margin-top: 6px;
    }

    div {
      font-family: Microsoft YaHei, Microsoft YaHei;
      font-weight: 400;
      font-size: 12px;
      color: #FAFBFF;
      line-height: 24px;
    }
  }
}

.text-box {
  //width: 490px;
  height: 190px;
  background: #FFFFFF;
  border-radius: 8px;
  border: 1px solid #D5DDFF;
  margin: 12px 20px 12px 20px;
  .box-textarea {
    outline: none;
    border: none;
    resize: none;
    width: 100%;
    height: calc(100% - 54px);
    padding: 16px;
    line-height: 24px;
    border-radius: 8px;
  }

  img {
    cursor:pointer;
    float: right;
    margin-right: 16px;
  }

  .quote-box {
    display: flex;
    padding: 16px;
    align-items: center;

    .vertical-line {
      width: 2px;
      height: 16px;
      background: #004EA0;
      border-radius: 1px 1px 1px 1px;
      opacity: 0.4;
    }

    .quote-info {
      width: calc(100% - 14px);
      height: 20px;
      font-size: 14px;
      color: #004EA0;
      line-height: 20px;
      margin-left: 12px;
      overflow: hidden;
      text-overflow: ellipsis;
      white-space: nowrap;
    }

    .quote-close {
      height: 16px;

      img {
        width: 14px;
        margin: auto;
        float: none;
        cursor: pointer;
      }
    }
  }

  .quote-textarea {
    padding: 0 16px 16px 16px;
    height: calc(100% - 106px);
  }
}

.bottom {
  font-family: PingFang SC, PingFang SC;
  font-weight: 400;
  font-size: 14px;
  color: #858A94;
  line-height: 30px;
  float: right;
  margin-right: 16px;
}
</style>