<template>
  <div class="chat-app">
    <!-- 历史会话侧边栏 -->
    <div class="history-sessions" :class="{ collapsed: !sessionIsShow }">
      <div class="session-header">
        <el-button type="primary" @click="clearCurrent" class="new-session-btn">
          <el-icon><Plus /></el-icon>
          新会话
        </el-button>
      </div>

      <el-card class="session-card" shadow="never">
        <template #header>
          <div class="card-header">
            <el-icon><ChatDotRound /></el-icon>
            <span>当前会话</span>
          </div>
        </template>
        <div class="current-session">
          <el-tooltip :content="sessionName" placement="top">
            <div class="session-name">{{ getShortenedName(sessionName) || '新会话' }}</div>
          </el-tooltip>
        </div>
      </el-card>

      <el-card class="session-card history-card" shadow="never">
        <template #header>
          <div class="card-header">
            <el-icon><Clock /></el-icon>
            <span>历史会话</span>
          </div>
        </template>
        <el-scrollbar class="history-scroll">
          <div class="history-list">
            <div
              v-for="(session, index) in historySessions"
              :key="index"
              class="history-item"
              :class="{ active: session.ID === sessionID }"
              @click="loadSession(session.ID)"
            >
              <el-tooltip :content="session.Name" placement="top">
                <span class="history-name">{{ getShortenedName(session.Name) }}</span>
              </el-tooltip>
            </div>
          </div>
        </el-scrollbar>
      </el-card>
    </div>

    <!-- 折叠按钮 -->
    <div class="toggle-sidebar" @click="showSession">
      <el-icon v-if="sessionIsShow"><DArrowLeft /></el-icon>
      <el-icon v-else><DArrowRight /></el-icon>
    </div>

    <!-- 聊天区域 -->
    <div class="chat-container">
      <!-- 顶部工具栏 -->
      <div class="chat-header">
        <el-select v-model="selectModel" placeholder="选择模型" class="model-select">
          <el-option v-for="item in ModelList" :key="item.ID" :label="item.Type + ' - ' + item.Description" :value="item.ID" />
        </el-select>

        <el-dropdown trigger="click" class="params-dropdown">
          <el-button link>
            <el-icon><Setting /></el-icon>
            模型参数
            <el-icon><ArrowDown /></el-icon>
          </el-button>
          <template #dropdown>
            <div class="dropdown-content">
              <div class="model-params">
                <div class="params-tip">
                  <el-icon><InfoFilled /></el-icon>
                  <span>建议仅调整 temperature 或 top_p 其中之一</span>
                </div>
                <!-- 温度参数 -->
                <div class="param-item">
                  <div class="param-label">
                    <span>温度 (Temperature)</span>
                    <el-tooltip effect="dark" placement="top" content="采样温度，控制生成随机性（0: 保守，2: 随机）">
                      <el-icon class="tip-icon"><QuestionFilled /></el-icon>
                    </el-tooltip>
                  </div>
                  <div class="param-control">
                    <el-slider v-model="temperature" :min="0" :max="2" :step="0.1" :show-tooltip="false" />
                    <span class="param-value">{{ temperature }}</span>
                  </div>
                </div>

                <!-- Top P 参数 -->
                <div class="param-item">
                  <div class="param-label">
                    <span>Top P</span>
                    <el-tooltip effect="dark" placement="top" content="限制候选词范围（0: 严格，1: 宽松）">
                      <el-icon class="tip-icon"><QuestionFilled /></el-icon>
                    </el-tooltip>
                  </div>
                  <div class="param-control">
                    <el-slider v-model="topP" :min="0" :max="1" :step="0.1" :show-tooltip="false" />
                    <span class="param-value">{{ topP }}</span>
                  </div>
                </div>
              </div>
            </div>
          </template>
        </el-dropdown>
      </div>

      <!-- 消息列表 -->
      <div class="chat-messages" ref="messagesContainer">
        <!-- 空状态 -->
        <div v-if="messages.length === 0" class="empty-state">
          <div class="empty-icon">
            <el-icon :size="80"><ChatLineRound /></el-icon>
          </div>
          <div class="empty-text">开始一段对话吧</div>
          <div class="empty-hint">输入消息或选择文件，与 AI 进行交流</div>
        </div>

        <!-- 消息列表 -->
        <div v-else class="messages-list">
          <div v-for="(message, index) in messages" :key="index" :class="['message-item', message.role]">
            <div class="message-avatar">
              <el-icon v-if="message.role === 'assistant'" class="ai-icon"><Promotion /></el-icon>
              <el-icon v-else class="user-icon"><User /></el-icon>
            </div>
            <div class="message-wrapper">
              <div class="message-content">
                <div v-html="renderMarkdown(message, index)" class="markdown-body"></div>
              </div>
              <div class="message-actions">
                <el-tooltip content="复制" placement="top">
                  <el-button type="text" :icon="DocumentCopy" @click="copyMessage(message.content)" />
                </el-tooltip>
                <el-tooltip content="保存为文件" placement="top">
                  <el-button type="text" :icon="Document" @click="MessageTextToDoc(message.content)" />
                </el-tooltip>
              </div>
            </div>
          </div>

          <!-- 加载状态 -->
          <div v-if="loading" class="message-item assistant">
            <div class="message-avatar">
              <el-icon class="ai-icon"><Promotion /></el-icon>
            </div>
            <div class="message-wrapper">
              <div class="message-content">
                <div class="typing-indicator">
                  <span></span>
                  <span></span>
                  <span></span>
                </div>
                <div class="typing-text">正在思考... ({{ currentAIMessage.length }} 字符)</div>
              </div>
            </div>
          </div>
        </div>
      </div>

      <!-- 输入区域 -->
      <div class="chat-input-wrapper">
        <!-- 已选文件 -->
        <div v-if="selectedFiles.length > 0" class="selected-files">
          <el-tag
            v-for="(file, index) in selectedFiles"
            :key="index"
            closable
            @close="removeFile(index)"
            class="file-tag"
          >
            <el-icon><Document /></el-icon>
            {{ file.UserFileName }}
          </el-tag>
        </div>

        <div class="input-area">
          <div class="input-tools">
            <el-tooltip content="选择文件" placement="top">
              <el-button type="text" :icon="FolderOpened" @click="handleSelectFileVisible" />
            </el-tooltip>
          </div>

          <el-input
            v-model="inputMessage"
            type="textarea"
            placeholder="输入消息... (Enter 发送，Shift+Enter 换行)"
            @keydown="handleKeydown"
            class="chat-textarea"
            :autosize="{ minRows: 1, maxRows: 6 }"
          />

          <el-button
            type="primary"
            :icon="loading ? VideoPause : Check"
            @click="sendMessage"
            class="send-btn"
          >
            {{ loading ? '停止' : '发送' }}
          </el-button>
        </div>
      </div>
    </div>

    <!-- 文件对话框 -->
    <el-dialog v-model="selectFileVisible" title="从上传文件中选择" width="50%" class="file-dialog">
      <div class="dialog-search">
        <el-input placeholder="搜索文件" v-model="searchFileQuery" prefix-icon="Search" clearable />
        <el-button type="primary" @click="uploadMessageFile" class="upload-btn">
          <el-icon><Upload /></el-icon>
          上传文件
        </el-button>
      </div>
      <div class="file-list">
        <el-checkbox-group v-model="selectedFiles">
          <div v-for="(item, index) in filteredFiles" :key="index" class="file-item">
            <el-checkbox :label="item" />
            <div class="file-info">
              <el-icon class="file-icon">
                <Picture v-if="item.UploadType === 'image'" />
                <Document v-else />
              </el-icon>
              <span class="file-name">{{ item.UserFileName }}</span>
            </div>
          </div>
        </el-checkbox-group>
      </div>
      <div class="footer-bar">
        <span class="selected-count">已选 {{ selectedFiles.length }} 个文件</span>
        <div>
          <el-button @click="selectFileVisible = false">取消</el-button>
          <el-button type="primary" @click="handleSelectFileConfirm">确认添加</el-button>
        </div>
      </div>
    </el-dialog>

    <!-- 上传文件对话框 -->
    <el-dialog title="上传文件" v-model="uploadFileVisible" width="50%" :before-close="handleUploadFileClose">
      <UploadFile />
    </el-dialog>

    <!-- 文本创建文件对话 -->
    <el-dialog title="文本创建文件" v-model="textToDocFileVisible" width="70%" class="doc-dialog" :before-close="handleMessageTextToDOCClose">
      <div class="doc-header">
        <el-input v-model="textToDocFileName" placeholder="输入文件名..." class="doc-name-input">
          <template #append>
            <el-select v-model="selectFileDocType" placeholder="类型">
              <el-option label="docx" value="docx" />
              <el-option label="txt" value="txt" />
              <el-option label="md" value="md" />
            </el-select>
          </template>
        </el-input>
      </div>
      <div ref="vditorRef" class="vditor-container"></div>
      <div class="doc-footer">
        <el-button @click="textToDocFileVisible = false">取消</el-button>
        <el-button type="primary" @click="HandleTextToDocFile">确认创建</el-button>
      </div>
    </el-dialog>
  </div>
</template>

<script setup lang="ts" name="gen-chat">
import { ref, onMounted, onUnmounted, reactive, nextTick, watch } from "vue";
import {
  Check,
  DocumentCopy,
  Document,
  Plus,
  ChatDotRound,
  Clock,
  DArrowLeft,
  DArrowRight,
  Setting,
  ArrowDown,
  QuestionFilled,
  ChatLineRound,
  Promotion,
  User,
  FolderOpened,
  VideoPause,
  Upload,
  Picture,
  InfoFilled,
} from "@element-plus/icons-vue";
import { ElMessage } from "element-plus";
import MarkdownIt from "markdown-it";
import hljs from "highlight.js";
import "highlight.js/styles/github.css";
import markdownItHighlightjs from "markdown-it-highlightjs";
import markdownItKatex from "markdown-it-katex";
import mermaidPlugin from "@agoose77/markdown-it-mermaid";
import { fetchEventSource } from '@microsoft/fetch-event-source';
import "katex/dist/katex.min.css";
import Vditor from 'vditor';
import 'vditor/dist/index.css';

import { WSMessage, GenMessage } from "@/types/im";
import { GetMessageService } from "@/api/im";
import { FindUserFileService } from "@/api/file";
import { Model } from "@/types/model";
import { UserUISettings } from '@/types/user';
import { File, fileUrl } from "@/types/file";
import { Session } from "@/types/session";
import { FindSessionService } from "@/api/session";
import { SetMessageTextToDocService } from "@/api/tool";
import UploadFile from "@/components/upload-file.vue";
import { updateUserUIconfigInfoService } from "@/api/user";
import { FindModelListByFunctionName } from "@/api/function";

interface Message {
  role: "user" | "assistant";
  content: string;
  finished?: boolean;
}

interface FileMessage {
  file_content: File;
  file_type: string | null;
}

interface GenerationMessage {
  text: string;
  file_content: FileMessage[];
}

const md = new MarkdownIt();
md.use(markdownItHighlightjs, {
  hljs,
  auto: true,
  code: true,
});
md.renderer.rules.image = function (tokens, idx, options, env, self) {
  const token = tokens[idx];
  token.attrSet('width', '400');
  token.attrSet('style', 'max-width: 100%; height: auto; border-radius: 8px;');
  return self.renderToken(tokens, idx, options, env, self);
};
md.use(markdownItKatex);
md.use(mermaidPlugin);

const historySessions = ref<Session[]>([]);
const loading = ref(false);
const canStop = ref(false);
const isUserScrolling = ref<boolean>(false);
const messages = reactive<Message[]>([]);
const inputMessage = ref("");
const currentAIMessage = ref("");
const sessionID = ref(0);
const messagesContainer = ref<HTMLDivElement | null>(null);
const sessionIsShow = ref(true);
const sessionName = ref("");
const ModelList = ref<Model[]>([]);
const selectModel = ref(0);
const temperature = ref(0.8);
const topP = ref(0.9);
const selectedFiles = ref<File[]>([]);
const selectFileVisible = ref(false);
const searchFileQuery = ref("");
const filteredFiles = ref<File[]>([]);
const uploadFileVisible = ref(false);
const textToDocFileVisible = ref(false);
const selectFileDocType = ref("docx");
const textToDocFileName = ref("");
const textToDocFileContent = ref("");
const vditor = ref();
const vditorRef = ref(null);
const userUIconfigInfo = ref<UserUISettings>({} as UserUISettings);
const historyMsgHtml = ref([]);

// 监听需要保存的配置
watch(
  [selectModel, temperature, topP, sessionID],
  () => {
    updateUserUIconfigInfo();
  }
);

const renderMarkdown = (message: Message, index: number) => {
  if (message.finished === false) {
    return message.content;
  }
  if (historyMsgHtml.value[index]) {
    return historyMsgHtml.value[index];
  }
  const html = md.render(message.content);
  historyMsgHtml.value.push(html);
  return html;
};

const scrollToBottom = () => {
  nextTick(() => {
    if (messagesContainer.value) {
      messagesContainer.value.scrollTop = messagesContainer.value.scrollHeight;
    }
  });
};

const copyCode = (code: string) => {
  navigator.clipboard.writeText(code).then(() => {
    ElMessage.success("代码已复制到剪贴板");
  });
};

const removeFile = (index: number) => {
  selectedFiles.value.splice(index, 1);
};

const handleSelectFileVisible = async () => {
  await getFileListData();
  selectFileVisible.value = true;
};

const handleUploadFileClose = async () => {
  uploadFileVisible.value = false;
  await getFileListData();
};

const handleMessageTextToDOCClose = async () => {
  textToDocFileVisible.value = false;
};

const uploadMessageFile = () => {
  uploadFileVisible.value = true;
};

const handleSelectFileConfirm = () => {
  selectFileVisible.value = false;
};

const doButtonD = () => {
  nextTick(() => {
    const codeBlocks = document.querySelectorAll<HTMLElement>(".markdown-body pre");
    codeBlocks.forEach((pre) => {
      if (pre.querySelector(".code-header")) return;

      const code = pre.querySelector("code");
      const lang = code?.className.match(/language-(\w+)/)?.[1] || "code";

      const header = document.createElement("div");
      header.className = "code-header";
      header.innerHTML = `
        <span class="code-lang">${lang}</span>
        <button class="copy-btn" title="复制代码">
          <svg viewBox="0 0 24 24" width="16" height="16" stroke="currentColor" stroke-width="2" fill="none">
            <rect x="9" y="9" width="13" height="13" rx="2" ry="2"></rect>
            <path d="M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1"></path>
          </svg>
        </button>
      `;

      pre.style.position = "relative";
      pre.style.marginTop = "0";
      pre.insertBefore(header, pre.firstChild);

      header.querySelector(".copy-btn")?.addEventListener("click", () => {
        copyCode(code?.textContent || "");
        ElMessage.success("复制成功");
      });
    });
  });
};

// 处理键盘事件
const handleKeydown = (e: KeyboardEvent) => {
  if (e.key === "Enter" && !e.shiftKey) {
    e.preventDefault();
    sendMessage();
  }
};

onMounted(async () => {
  userUIconfigInfo.value = JSON.parse(
    localStorage.getItem("userUIconfigInfo") || "{}"
  );
  messagesContainer.value = document.querySelector(".chat-messages");
  // 页面加载时获取历史会话
  await fetchHistorySessions();
});

// 获取历史会话
const fetchHistorySessions = async () => {
  try {
    let req = {
      token: localStorage.getItem("token"),
      type: "UserID",
      session_type: 1,
    };
    let result = await FindSessionService(req);
    historySessions.value = result.data;
  } catch (e) {
    console.error("获取历史会话失败:", e);
  }
};

onUnmounted(() => {
  // 清理工作可以在这里添加
});

const doReceiveMessageSSE = (event: any) => {
  let msg: WSMessage = JSON.parse(event.data.replace("data: ", ""));
  const existingMessage = messages.find(
    (m) => m.role === "assistant" && !m.finished
  );
  if (existingMessage) {
    existingMessage.content += msg.msg.msg.response;
  } else {
    messages.push({
      role: "assistant",
      content: msg.msg.msg.response,
      finished: false,
    });
  }

  sessionID.value = msg.session_id;
  currentAIMessage.value += msg.msg.msg.response;
  if (msg.msg.msg.done) {
    const assistantMessage = messages[messages.length - 1];
    assistantMessage.finished = true;
    loading.value = false;
    canStop.value = false;
    currentAIMessage.value = "";
    doButtonD();
  }
  scrollToBottom();
};

const updateUserUIconfigInfo = () => {
  let req: UserUISettings = JSON.parse(localStorage.getItem("userUIconfigInfo") || "{}");
  if (req.user_id == 0) {
    req.user_id = parseInt(localStorage.getItem("user_id") || "0");
  } else {
    req.gen_ai_function.model_id = selectModel.value;
    req.gen_ai_function.temperature = temperature.value;
    req.gen_ai_function.top_p = topP.value;
    req.gen_ai_function.session_id = sessionID.value;
  }
  updateUserUIconfigInfoService(req, localStorage.getItem("token")).then((res) => {
    if (res["code"] === 0) {
      console.log("保存成功");
    }
  });
};

const sendMessage = async () => {
  if (loading.value) {
    ElMessage.info("正在停止生成...");
    return;
  }
  if (inputMessage.value.trim() === "" && selectedFiles.value.length === 0) {
    ElMessage.warning("消息不能为空");
    return;
  }
  await nextTick();
  sendMessageWithFileUseSSE();
};

const sendMessageWithFileUseSSE = async () => {
  checkTokenIsValidAndRefresh();
  let url = "https://pm.ljsea.top/im/chat_completion";
  let headers = { "token": localStorage.getItem("token") || "" };

  let end_msg: any = {
    msg: inputMessage.value,
    type: "null",
    function: "gen-ai-chat",
    session_id: sessionID.value,
    model_id: selectModel.value,
    temperature: temperature.value,
    top_p: topP.value,
  };

  if (selectedFiles.value.length > 0) {
    let file_contents: FileMessage[] = [];
    for (let i = 0; i < selectedFiles.value.length; i++) {
      let file: File = selectedFiles.value[i];
      let file_type = file.UserFileName.match(/\.(jpg|jpeg|png|gif|bmp|webp)$/i) ? "image_file" : "text_file";
      file_contents.push({
        file_content: file,
        file_type: file_type,
      });
    }
    let msg: GenerationMessage = {
      text: inputMessage.value,
      file_content: file_contents,
    };
    end_msg.msg = JSON.stringify(msg);
    end_msg.is_file = true;
  }

  let pMsgContent = "";
  if (end_msg.is_file) {
    let file_msg: GenerationMessage = JSON.parse(end_msg.msg);
    for (let i = 0; i < file_msg.file_content.length; i++) {
      const fc = file_msg.file_content[i];
      if (fc.file_type === "image_file") {
        pMsgContent += `![${fc.file_content.UserFileName}](${fileUrl}${fc.file_content.file_store_name})\n\n`;
      } else {
        pMsgContent += `📎 文件：[${fc.file_content.UserFileName}](${fileUrl}${fc.file_content.file_store_name})\n\n`;
      }
    }
    pMsgContent += file_msg.text;
  } else {
    pMsgContent = end_msg.msg;
  }

  messages.push({ role: "user", content: pMsgContent, finished: true });
  inputMessage.value = "";
  selectedFiles.value = [];
  loading.value = true;
  canStop.value = true;
  if (sessionID.value === 0) {
    sessionName.value = pMsgContent.slice(0, 50);
  }
  scrollToBottom();

  fetchEventSource(url, {
    method: 'POST',
    headers: {
      'Content-Type': 'application/json',
      ...headers,
    },
    body: JSON.stringify(end_msg),
    openWhenHidden: true,
    onmessage: (event) => {
      try {
        doReceiveMessageSSE(event);
      } catch (e) {
        console.error('Failed to parse SSE data:', e);
      }
    },
    onerror: (error) => {
      ElMessage.error("发送失败! 请刷新页面重试");
      loading.value = false;
      canStop.value = false;
    },
    onclose: () => {
      console.log('SSE connection closed');
    },
  });
};

const loadSession = async (session_id: number) => {
  sessionID.value = session_id;
  messages.length = 0;
  historyMsgHtml.value.length = 0;
  sessionName.value = historySessions.value.find(
    (session) => session.ID === session_id
  )?.Name || "";
  await getMessage(session_id);
  scrollToBottom();
  doButtonD();
};

const clearCurrent = () => {
  sessionID.value = 0;
  messages.length = 0;
  historyMsgHtml.value.length = 0;
  sessionName.value = "新会话";
  ElMessage.success("新会话已创建! 可以开始聊天了");
};

const showSession = async () => {
  if (!sessionIsShow.value) {
    await fetchHistorySessions();
  }
  sessionIsShow.value = !sessionIsShow.value;
};

const getShortenedName = (name: string) => {
  if (!name) return "";
  if (name.length > 20) {
    return name.slice(0, 20) + "...";
  }
  return name;
};

const getMessage = async (session_id: number) => {
  historyMsgHtml.value.length = 0;
  let result: any = {};
  try {
    let req = {
      token: localStorage.getItem("token"),
      session_id: session_id,
    };
    result = await GetMessageService(req);
    if (result["code"] === 0) {
      let data = result["data"];
      for (let i = 0; i < data.length; i++) {
        if (data[i]["Type"] === 3) {
          let msg: GenMessage = data[i];
          let pMsgContent = "";
          if (msg.Status === 3) {
            let file_msg: GenerationMessage = JSON.parse(msg.Msg);
            for (let j = 0; j < file_msg.file_content.length; j++) {
              const fc = file_msg.file_content[j];
              if (fc.file_type === "image_file") {
                pMsgContent += `![${fc.file_content.UserFileName}](${fileUrl}${fc.file_content.file_store_name})\n\n`;
              } else {
                pMsgContent += `📎 文件：[${fc.file_content.UserFileName}](${fileUrl}${fc.file_content.file_store_name})\n\n`;
              }
            }
            pMsgContent += file_msg.text;
          } else {
            pMsgContent = msg.Msg;
          }
          messages.push({
            role: "user",
            content: pMsgContent,
            finished: true,
          });
        } else if (data[i]["Type"] === 4) {
          messages.push({
            role: "assistant",
            content: data[i]["Msg"],
            finished: true,
          });
        }
      }
    }
  } catch (e) {
    console.log(e);
  }
};

const MessageTextToDoc = async (content: string) => {
  textToDocFileContent.value = content;
  textToDocFileVisible.value = true;
  await nextTick();
  vditor.value = new Vditor(vditorRef.value, {
    mode: 'sv',
    height: '500px',
    width: '100%',
    cache: { enable: false },
    value: textToDocFileContent.value,
  });
};

const copyMessage = (content: string) => {
  navigator.clipboard.writeText(content).then(() => {
    ElMessage.success("复制成功");
  }).catch(() => {
    ElMessage.error("复制失败");
  });
};

const checkTokenIsValidAndRefresh = () => {
  let last_refresh = localStorage.getItem("refresh_time");
  let now = Date.now();
  let isValid = false;
  if (last_refresh) {
    let diff = now - parseInt(last_refresh);
    if (diff < 60 * 60 * 1000) {
      isValid = true;
    }
  }
  if (!isValid) {
    GetModelListByFunctionName();
  }
};

const GetModelListByFunctionName = async () => {
  let req = {
    function: "gen-ai-chat",
    token: localStorage.getItem("token"),
  };
  try {
    let result = await FindModelListByFunctionName(req);
    if (result["code"] === 0) {
      ModelList.value = result.data;
      if (userUIconfigInfo.value.gen_ai_function?.model_id) {
        selectModel.value = userUIconfigInfo.value.gen_ai_function.model_id;
        temperature.value = userUIconfigInfo.value.gen_ai_function.temperature || 0.8;
        topP.value = userUIconfigInfo.value.gen_ai_function.top_p || 0.9;
        sessionID.value = userUIconfigInfo.value.gen_ai_function.session_id || 0;
        if (sessionID.value !== 0) {
          getMessage(sessionID.value);
        }
      } else if (ModelList.value.length > 0) {
        selectModel.value = ModelList.value[0].ID;
      }
    } else {
      ElMessage.error(result["msg"]);
    }
  } catch (e) {
    console.log(e);
  }
};

GetModelListByFunctionName();

const getFileListData = async () => {
  let req = {
    token: localStorage.getItem("token"),
    type: "all",
  };
  let result = await FindUserFileService(req);
  if (result["code"] === 0) {
    filteredFiles.value = result["data"];
  } else {
    ElMessage.error(result["msg"]);
  }
};

const HandleTextToDocFile = async () => {
  if (textToDocFileName.value.trim() === "") {
    ElMessage.warning("文件名不能为空");
    return;
  }
  let req = {
    token: localStorage.getItem("token"),
    file_name: textToDocFileName.value,
    text: vditor.value.getValue(),
    file_type: selectFileDocType.value,
  };
  let result = await SetMessageTextToDocService(req);
  if (result["code"] === 0) {
    ElMessage.success("文件已加入创建队列，请在文件列表中查看");
    textToDocFileVisible.value = false;
  } else {
    ElMessage.error(result["msg"]);
  }
};
</script>

<style scoped>
.chat-app {
  display: flex;
  height: 100%;
  background-color: #f7f8fa;
}

/* 侧边栏 */
.history-sessions {
  width: 280px;
  height: 100%;
  display: flex;
  flex-direction: column;
  background: #fff;
  border-right: 1px solid #e5e6eb;
  transition: all 0.3s ease;
}

.history-sessions.collapsed {
  width: 0;
  overflow: hidden;
  border-right: none;
}

.session-header {
  padding: 16px;
  border-bottom: 1px solid #e5e6eb;
}

.new-session-btn {
  width: 100%;
}

.session-card {
  margin: 12px;
  border-radius: 8px;
}

.session-card :deep(.el-card__header) {
  padding: 12px 16px;
  background: #f7f8fa;
  border-bottom: none;
}

.card-header {
  display: flex;
  align-items: center;
  gap: 8px;
  font-weight: 600;
  color: #1d2129;
}

.current-session {
  padding: 8px 0;
}

.session-name {
  padding: 8px 12px;
  background: #f2f3f5;
  border-radius: 6px;
  color: #4e5969;
  font-size: 14px;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.history-card {
  flex: 1;
  display: flex;
  flex-direction: column;
  margin-top: 0;
}

.history-scroll {
  flex: 1;
  min-height: 0;
}

.history-list {
  display: flex;
  flex-direction: column;
  gap: 4px;
}

.history-item {
  padding: 10px 12px;
  border-radius: 6px;
  cursor: pointer;
  transition: all 0.2s;
  color: #4e5969;
  font-size: 14px;
}

.history-item:hover {
  background: #f2f3f5;
}

.history-item.active {
  background: #e8f3ff;
  color: #1677ff;
}

.history-name {
  display: block;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

/* 折叠按钮 */
.toggle-sidebar {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 20px;
  cursor: pointer;
  color: #86909c;
  transition: all 0.2s;
  background: #fff;
  border-right: 1px solid #e5e6eb;
}

.toggle-sidebar:hover {
  color: #4e5969;
  background: #f7f8fa;
}

/* 聊天容器 */
.chat-container {
  flex: 1;
  display: flex;
  flex-direction: column;
  height: 100%;
  min-width: 0;
}

/* 顶部工具栏 */
.chat-header {
  display: flex;
  align-items: center;
  gap: 16px;
  padding: 12px 24px;
  background: #fff;
  border-bottom: 1px solid #e5e6eb;
}

.model-select {
  width: 300px;
}

/* 消息列表 */
.chat-messages {
  flex: 1;
  overflow-y: auto;
  padding: 24px;
}

/* 空状态 */
.empty-state {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  height: 100%;
  color: #86909c;
}

.empty-icon {
  color: #c9cdd4;
  margin-bottom: 16px;
}

.empty-text {
  font-size: 20px;
  font-weight: 600;
  color: #1d2129;
  margin-bottom: 8px;
}

.empty-hint {
  font-size: 14px;
  color: #86909c;
}

/* 消息列表 */
.messages-list {
  max-width: 1000px;
  margin: 0 auto;
  display: flex;
  flex-direction: column;
  gap: 24px;
}

.message-item {
  display: flex;
  gap: 12px;
}

.message-item.user {
  flex-direction: row-reverse;
}

.message-avatar {
  flex-shrink: 0;
  width: 40px;
  height: 40px;
  border-radius: 8px;
  display: flex;
  align-items: center;
  justify-content: center;
}

.ai-icon {
  width: 100%;
  height: 100%;
  padding: 8px;
  background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
  color: #fff;
  border-radius: 8px;
  box-sizing: border-box;
}

.user-icon {
  width: 100%;
  height: 100%;
  padding: 8px;
  background: linear-gradient(135deg, #11998e 0%, #38ef7d 100%);
  color: #fff;
  border-radius: 8px;
  box-sizing: border-box;
}

.message-wrapper {
  max-width: calc(100% - 80px);
  display: flex;
  flex-direction: column;
  gap: 8px;
}

.message-item.user .message-wrapper {
  align-items: flex-end;
}

.message-content {
  padding: 16px 20px;
  border-radius: 12px;
  background: #fff;
  box-shadow: 0 2px 8px rgba(0, 0, 0, 0.04);
  line-height: 1.6;
  word-break: break-word;
}

.message-item.user .message-content {
  background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
  color: #fff;
}

.message-actions {
  display: flex;
  gap: 4px;
  opacity: 0;
  transition: opacity 0.2s;
}

.message-item:hover .message-actions {
  opacity: 1;
}

/* 打字指示器 */
.typing-indicator {
  display: flex;
  gap: 6px;
  padding: 8px 0;
}

.typing-indicator span {
  width: 8px;
  height: 8px;
  border-radius: 50%;
  background: #86909c;
  animation: typing 1.4s infinite;
}

.typing-indicator span:nth-child(2) {
  animation-delay: 0.2s;
}

.typing-indicator span:nth-child(3) {
  animation-delay: 0.4s;
}

@keyframes typing {
  0%, 60%, 100% {
    transform: translateY(0);
    opacity: 0.4;
  }
  30% {
    transform: translateY(-6px);
    opacity: 1;
  }
}

.typing-text {
  color: #86909c;
  font-size: 14px;
}

/* 输入区域 */
.chat-input-wrapper {
  padding: 16px 24px;
  background: #fff;
  border-top: 1px solid #e5e6eb;
}

.selected-files {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
  margin-bottom: 12px;
}

.file-tag {
  display: flex;
  align-items: center;
  gap: 4px;
}

.input-area {
  max-width: 1000px;
  margin: 0 auto;
  display: flex;
  gap: 12px;
  align-items: flex-end;
}

.input-tools {
  display: flex;
  gap: 4px;
  padding-bottom: 8px;
}

.chat-textarea {
  flex: 1;
}

.chat-textarea :deep(.el-textarea__inner) {
  border-radius: 12px;
  padding: 12px 16px;
  resize: none;
}

.send-btn {
  padding: 12px 24px;
  border-radius: 10px;
  font-weight: 500;
}

/* 文件对话框 */
.file-dialog :deep(.el-dialog__body) {
  padding: 0;
}

.dialog-search {
  display: flex;
  gap: 12px;
  padding: 16px 20px;
  border-bottom: 1px solid #e5e6eb;
}

.dialog-search .el-input {
  flex: 1;
}

.file-list {
  max-height: 400px;
  overflow-y: auto;
  padding: 12px 0;
}

.file-item {
  display: flex;
  align-items: center;
  gap: 12px;
  padding: 10px 20px;
  cursor: pointer;
  transition: background 0.2s;
}

.file-item:hover {
  background: #f7f8fa;
}

.file-info {
  display: flex;
  align-items: center;
  gap: 8px;
  flex: 1;
}

.file-icon {
  color: #86909c;
}

.file-name {
  color: #1d2129;
}

.footer-bar {
  display: flex;
  justify-content: space-between;
  align-items: center;
  padding: 16px 20px;
  border-top: 1px solid #e5e6eb;
}

.selected-count {
  color: #86909c;
}

/* 文档对话框 */
.doc-dialog :deep(.el-dialog__body) {
  padding: 0;
}

.doc-header {
  padding: 16px 20px;
  border-bottom: 1px solid #e5e6eb;
}

.doc-name-input {
  width: 400px;
}

.vditor-container {
  min-height: 500px;
}

.doc-footer {
  display: flex;
  justify-content: flex-end;
  gap: 12px;
  padding: 16px 20px;
  border-top: 1px solid #e5e6eb;
}

/* 参数下拉 */
.dropdown-content {
  width: 360px;
  padding: 8px;
}

.model-params {
  padding: 8px;
}

.params-tip {
  display: flex;
  align-items: center;
  gap: 6px;
  padding: 8px 12px;
  margin-bottom: 12px;
  background: #e8f3ff;
  border-radius: 6px;
  color: #1677ff;
  font-size: 13px;
}

.param-item {
  margin-bottom: 20px;
}

.param-label {
  display: flex;
  align-items: center;
  gap: 6px;
  margin-bottom: 8px;
  color: #4e5969;
  font-size: 14px;
}

.tip-icon {
  color: #86909c;
  cursor: help;
}

.param-control {
  display: flex;
  align-items: center;
  gap: 12px;
}

.param-control .el-slider {
  flex: 1;
}

.param-value {
  min-width: 40px;
  text-align: right;
  font-weight: 600;
  color: #1677ff;
}
</style>

<style>
/* Markdown 样式 */
.markdown-body {
  font-size: 15px;
  line-height: 1.7;
}

.markdown-body p {
  margin: 8px 0;
}

.markdown-body pre {
  margin: 16px 0;
  border-radius: 8px;
  overflow: hidden;
}

.markdown-body code {
  font-family: 'JetBrains Mono', 'Fira Code', monospace;
  font-size: 14px;
}

.markdown-body pre code {
  display: block;
  padding: 16px;
  padding-top: 12px;
  overflow-x: auto;
}

.markdown-body :not(pre) > code {
  background: #f2f3f5;
  padding: 2px 6px;
  border-radius: 4px;
  color: #d63384;
}

.code-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 8px 16px;
  background: #1e1e1e;
  border-bottom: 1px solid #333;
}

.code-lang {
  color: #888;
  font-size: 12px;
  text-transform: uppercase;
}

.copy-btn {
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 4px;
  background: transparent;
  border: none;
  color: #888;
  cursor: pointer;
  border-radius: 4px;
  transition: all 0.2s;
}

.copy-btn:hover {
  color: #fff;
  background: #333;
}

.markdown-body blockquote {
  margin: 12px 0;
  padding: 8px 16px;
  border-left: 4px solid #667eea;
  background: #f7f8fa;
  color: #4e5969;
  border-radius: 0 6px 6px 0;
}

.markdown-body ul,
.markdown-body ol {
  padding-left: 24px;
  margin: 12px 0;
}

.markdown-body li {
  margin: 4px 0;
}

.markdown-body h1,
.markdown-body h2,
.markdown-body h3,
.markdown-body h4,
.markdown-body h5,
.markdown-body h6 {
  margin: 16px 0 8px;
  font-weight: 600;
  color: #1d2129;
}

.markdown-body h1 {
  font-size: 24px;
  border-bottom: 1px solid #e5e6eb;
  padding-bottom: 8px;
}

.markdown-body h2 {
  font-size: 20px;
}

.markdown-body h3 {
  font-size: 18px;
}

.markdown-body a {
  color: #667eea;
  text-decoration: none;
}

.markdown-body a:hover {
  text-decoration: underline;
}

.markdown-body table {
  width: 100%;
  border-collapse: collapse;
  margin: 12px 0;
}

.markdown-body th,
.markdown-body td {
  border: 1px solid #e5e6eb;
  padding: 8px 12px;
  text-align: left;
}

.markdown-body th {
  background: #f7f8fa;
  font-weight: 600;
}

.message-item.user .markdown-body :not(pre) > code {
  background: rgba(255, 255, 255, 0.2);
  color: #fff;
}

.message-item.user .markdown-body a {
  color: #fff;
  text-decoration: underline;
}

/* 滚动条样式 */
.chat-messages::-webkit-scrollbar,
.history-scroll::-webkit-scrollbar,
.file-list::-webkit-scrollbar {
  width: 6px;
}

.chat-messages::-webkit-scrollbar-track,
.history-scroll::-webkit-scrollbar-track,
.file-list::-webkit-scrollbar-track {
  background: transparent;
}

.chat-messages::-webkit-scrollbar-thumb,
.history-scroll::-webkit-scrollbar-thumb,
.file-list::-webkit-scrollbar-thumb {
  background: #c9cdd4;
  border-radius: 3px;
}

.chat-messages::-webkit-scrollbar-thumb:hover,
.history-scroll::-webkit-scrollbar-thumb:hover,
.file-list::-webkit-scrollbar-thumb:hover {
  background: #86909c;
}
</style>
