<script setup lang="ts">
import { ElMessage, ElMessageBox } from "element-plus";
import { computed, nextTick, onMounted, reactive, ref, watch } from "vue";

import { api, streamDebugAgent } from "../services/api";
import type { AdminUser, AgentRuntimeConfig, KnowledgeItem, ModelItem, PromptDetail, PromptHistoryItem, TopicSessionRecord } from "../types/api";
import AgentGenerationParameters from "./AgentGenerationParameters.vue";
import AgentResponseDepthControl from "./AgentResponseDepthControl.vue";
import AdminPagination from "./AdminPagination.vue";
import StreamingMarkdownMessage from "./StreamingMarkdownMessage.vue";

const props = defineProps<{ previewKnowledgeId?: number | null }>();
const emit = defineEmits<{ consumedPreview: [] }>();

const loading = ref(false);
const promptSaving = ref(false);
const runtimeSaving = ref(false);
const historyLoading = ref(false);
const agentDebugging = ref(false);
const agentDebugAbortController = ref<AbortController | null>(null);
const agentPreviewChat = ref<HTMLElement | null>(null);
const activeConfigTab = ref("prompt");
const prompt = ref<PromptDetail | null>(null);
const promptContent = ref("");
const savedPromptContent = ref("");
const models = ref<ModelItem[]>([]);
const knowledge = ref<KnowledgeItem[]>([]);
const debugUsers = ref<AdminUser[]>([]);
const debugUserLoading = ref(false);
const debugTopics = ref<TopicSessionRecord[]>([]);
const debugTopicLoading = ref(false);
const history = ref<PromptHistoryItem[]>([]);
const historyPager = reactive({ page: 1, pageSize: 10, total: 0 });
const historyDetailOpen = ref(false);
const selectedHistory = ref<PromptDetail | null>(null);
const historyDetailLoading = ref(false);
const agentDebugTrace = ref<Record<string, any>[]>([]);
const lastDebugRoute = ref<{ modelName?: string; routeReason?: string } | null>(null);
const agentPreviewMessages = ref<{
  role: "user" | "assistant" | "system";
  content: string;
  reasoning?: string;
  showReasoning?: boolean;
  streaming?: boolean;
}[]>([
  { role: "assistant", content: "选择模型和知识库后，可以在这里调试 Agent 的真实问答效果。" },
]);

const agentForm = reactive({
  modelId: undefined as number | undefined,
  userId: undefined as number | undefined,
  topicSessionId: undefined as number | undefined,
  knowledgeIds: [] as number[],
  temperature: 0.2 as number | null,
  topP: null as number | null,
  topK: null as number | null,
  presencePenalty: null as number | null,
  frequencyPenalty: null as number | null,
  maxToken: 8192 as number | null,
  streamEnabled: 1,
  reasoningVisible: 0,
  responseDepth: 35,
  question: "",
});
const runtimeConfig = ref<AgentRuntimeConfig | null>(null);
const runtimeForm = reactive({
  temperature: null as number | null,
  topP: null as number | null,
  topK: null as number | null,
  presencePenalty: null as number | null,
  frequencyPenalty: null as number | null,
  maxToken: 8192 as number | null,
  streamEnabled: 1,
  reasoningVisible: 0,
  responseDepth: 35,
});

const promptDirty = computed(() => promptContent.value !== savedPromptContent.value);
const selectedModelName = computed(() => {
  const model = models.value.find((item) => item.id === agentForm.modelId);
  return model?.displayName || model?.modelName || "未选择模型";
});
const selectedKnowledgeSummary = computed(() => {
  if (!agentForm.knowledgeIds.length) return "默认使用全部正式开放知识库";
  if (agentForm.knowledgeIds.length === 1) {
    return knowledge.value.find((item) => item.id === agentForm.knowledgeIds[0])?.name || "1 个知识库";
  }
  return `${agentForm.knowledgeIds.length} 个知识库`;
});
const selectedDebugUserLabel = computed(() => {
  if (!agentForm.userId) return "未模拟学员";
  const user = debugUsers.value.find((item) => item.id === agentForm.userId);
  return user ? `${user.name || user.nickname || user.phone} · #${user.id}` : `学员 #${agentForm.userId}`;
});
const selectedDebugTopicLabel = computed(() => {
  if (!agentForm.topicSessionId) return "未指定主题";
  const topic = debugTopics.value.find((item) => item.id === agentForm.topicSessionId);
  return topic ? topic.title : `主题 #${agentForm.topicSessionId}`;
});

onMounted(load);

watch(() => props.previewKnowledgeId, (knowledgeId) => {
  if (knowledgeId && knowledge.value.length) applyPreviewKnowledge(knowledgeId);
});

async function load() {
  loading.value = true;
  try {
    const [promptResult, modelRows, knowledgeRows, formalConfig] = await Promise.all([
      api.prompt(), api.models(), api.knowledgeOptions(), api.agentRuntimeConfig(),
    ]);
    applyPrompt(promptResult);
    models.value = modelRows;
    knowledge.value = knowledgeRows;
    agentForm.modelId = modelRows.find((item) => item.isDefault === 1)?.id
      ?? modelRows.find((item) => item.enabled === 1)?.id
      ?? modelRows[0]?.id;
    applyRuntimeConfig(formalConfig);
    applyDebugModelDefaults(agentForm.modelId);
    agentForm.knowledgeIds = knowledgeRows
      .filter((item) => item.status === 1 && item.lifecycleStatus === "active")
      .map((item) => item.id);
    if (props.previewKnowledgeId) applyPreviewKnowledge(props.previewKnowledgeId);
    void searchDebugUsers("");
    await loadHistory();
  } catch (error) {
    ElMessage.error(errorMessage(error, "Agent 配置加载失败"));
  } finally {
    loading.value = false;
  }
}

async function searchDebugUsers(keyword: string) {
  debugUserLoading.value = true;
  try {
    const result = await api.users({ keyword, page: 1, pageSize: 20 });
    debugUsers.value = result.items;
  } catch {
    debugUsers.value = [];
  } finally {
    debugUserLoading.value = false;
  }
}

async function handleDebugUserChange(userId?: number) {
  agentForm.topicSessionId = undefined;
  debugTopics.value = [];
  clearAgentPreview("模拟学员已切换，可以选择其中一个主题继续调试。");
  if (!userId) return;
  debugTopicLoading.value = true;
  try {
    await loadDebugTopics(userId);
  } catch (error) {
    ElMessage.error(errorMessage(error, "学员主题加载失败"));
  } finally {
    debugTopicLoading.value = false;
  }
}

async function loadDebugTopics(userId: number, keyword = "") {
  const selected = debugTopics.value.find((item) => item.id === agentForm.topicSessionId);
  const result = await api.userTopics(userId, { keyword, page: 1, pageSize: 100 });
  debugTopics.value = selected && !result.items.some((item) => item.id === selected.id)
    ? [selected, ...result.items]
    : result.items;
}

async function searchDebugTopics(keyword: string) {
  if (!agentForm.userId) return;
  debugTopicLoading.value = true;
  try {
    await loadDebugTopics(agentForm.userId, keyword);
  } catch (error) {
    ElMessage.error(errorMessage(error, "学员主题搜索失败"));
  } finally {
    debugTopicLoading.value = false;
  }
}

function handleDebugTopicChange() {
  clearAgentPreview(
    agentForm.topicSessionId
      ? "模拟主题已切换，下一条调试会加载该主题的摘要和最近对话。"
      : "已恢复通用学员模拟，不加载具体主题对话。",
  );
}

function debugTopicOptionLabel(topic: TopicSessionRecord) {
  const statusLabel = topic.status === "active" ? "进行中" : topic.status === "completed" ? "已完成" : topic.status;
  const summaryLabel = topic.summaryAvailable ? "有摘要" : "无摘要";
  return `${topic.title} · ${statusLabel} · ${topic.messageCount} 条消息 · ${summaryLabel}`;
}

function applyRuntimeConfig(value: AgentRuntimeConfig) {
  runtimeConfig.value = value;
  Object.assign(runtimeForm, {
    temperature: value.temperature,
    topP: value.topP,
    topK: value.topK,
    presencePenalty: value.presencePenalty,
    frequencyPenalty: value.frequencyPenalty,
    maxToken: value.maxToken,
    streamEnabled: value.streamEnabled,
    reasoningVisible: value.reasoningVisible,
    responseDepth: value.responseDepth ?? 35,
  });
}

function applyDebugModelDefaults(modelId?: number) {
  const model = models.value.find((item) => item.id === modelId);
  if (!model) return;
  Object.assign(agentForm, {
    temperature: model.temperature ?? null,
    topP: model.topP ?? null,
    topK: model.topK ?? null,
    presencePenalty: model.presencePenalty ?? null,
    frequencyPenalty: model.frequencyPenalty ?? null,
    maxToken: model.maxToken ?? (model.enabled === 1 ? runtimeConfig.value?.maxToken : null) ?? 8192,
    streamEnabled: model.streamEnabled ?? 1,
    reasoningVisible: runtimeConfig.value?.reasoningVisible ?? 0,
    responseDepth: runtimeConfig.value?.responseDepth ?? 35,
  });
}

async function saveRuntimeConfig() {
  if (!runtimeConfig.value?.modelId) return ElMessage.error("请先在模型管理中启用一个正式模型");
  if (!runtimeForm.maxToken) return ElMessage.warning("最大输出长度不能为空");
  runtimeSaving.value = true;
  try {
    const saved = await api.saveAgentRuntimeConfig({
      temperature: runtimeForm.temperature,
      topP: runtimeForm.topP,
      topK: runtimeForm.topK,
      presencePenalty: runtimeForm.presencePenalty,
      frequencyPenalty: runtimeForm.frequencyPenalty,
      maxToken: runtimeForm.maxToken,
      streamEnabled: runtimeForm.streamEnabled,
      reasoningVisible: runtimeForm.reasoningVisible,
      responseDepth: runtimeForm.responseDepth,
    });
    applyRuntimeConfig(saved);
    const model = models.value.find((item) => item.id === saved.modelId);
    if (model) Object.assign(model, runtimeForm);
    if (agentForm.modelId === saved.modelId) applyDebugModelDefaults(saved.modelId ?? undefined);
    ElMessage.success("正式运行参数已保存，将从用户端下一条消息开始生效");
  } catch (error) {
    ElMessage.error(errorMessage(error, "正式运行参数保存失败"));
  } finally {
    runtimeSaving.value = false;
  }
}

function applyPreviewKnowledge(knowledgeId: number) {
  if (knowledge.value.some((item) => item.id === knowledgeId)) {
    agentForm.knowledgeIds = [knowledgeId];
    activeConfigTab.value = "debug";
  }
  emit("consumedPreview");
}

function applyPrompt(value: PromptDetail) {
  prompt.value = value;
  promptContent.value = value.promptContent;
  savedPromptContent.value = value.promptContent;
}

async function savePrompt() {
  if (!promptContent.value.trim()) return ElMessage.warning("主提示词不能为空");
  promptSaving.value = true;
  try {
    applyPrompt(await api.savePrompt(promptContent.value.trim()));
    ElMessage.success("主提示词已保存为新版本");
    await loadHistory(1);
  } catch (error) {
    ElMessage.error(errorMessage(error, "主提示词保存失败"));
  } finally {
    promptSaving.value = false;
  }
}

async function resetPrompt() {
  try {
    await ElMessageBox.confirm(
      "恢复默认提示词会新增一个版本，现有历史不会被删除。确认继续？",
      "恢复默认提示词",
      { type: "warning", confirmButtonText: "确认恢复", cancelButtonText: "取消" },
    );
  } catch {
    return;
  }
  promptSaving.value = true;
  try {
    applyPrompt(await api.resetPrompt());
    ElMessage.success("已恢复默认提示词并保存为新版本");
    await loadHistory(1);
  } catch (error) {
    ElMessage.error(errorMessage(error, "恢复默认提示词失败"));
  } finally {
    promptSaving.value = false;
  }
}

async function loadHistory(page = historyPager.page, pageSize = historyPager.pageSize) {
  historyLoading.value = true;
  try {
    const result = await api.promptHistory({ page, pageSize });
    history.value = result.items;
    Object.assign(historyPager, { page: result.page, pageSize: result.pageSize, total: result.total });
  } catch (error) {
    ElMessage.error(errorMessage(error, "提示词历史加载失败"));
  } finally {
    historyLoading.value = false;
  }
}

async function openHistory(item: PromptHistoryItem) {
  historyDetailOpen.value = true;
  historyDetailLoading.value = true;
  selectedHistory.value = null;
  try {
    selectedHistory.value = await api.promptHistoryDetail(item.id);
  } catch (error) {
    ElMessage.error(errorMessage(error, "提示词版本加载失败"));
    historyDetailOpen.value = false;
  } finally {
    historyDetailLoading.value = false;
  }
}

async function restoreHistory(id: number) {
  try {
    await ElMessageBox.confirm(
      `确认把版本 #${id} 恢复为当前主提示词？系统会新增一个恢复版本，不会覆盖历史。`,
      "恢复历史版本",
      { type: "warning", confirmButtonText: "确认恢复", cancelButtonText: "取消" },
    );
  } catch {
    return;
  }
  promptSaving.value = true;
  try {
    applyPrompt(await api.restorePrompt(id));
    historyDetailOpen.value = false;
    activeConfigTab.value = "prompt";
    ElMessage.success(`版本 #${id} 已恢复为当前主提示词`);
    await loadHistory(1);
  } catch (error) {
    ElMessage.error(errorMessage(error, "历史版本恢复失败"));
  } finally {
    promptSaving.value = false;
  }
}

async function restoreSelectedHistory() {
  if (selectedHistory.value?.id) await restoreHistory(selectedHistory.value.id);
}

async function debugAgent() {
  if (agentDebugging.value) return;
  if (!agentForm.modelId) return ElMessage.error("请选择调试模型");
  if (!agentForm.question.trim()) return ElMessage.error("请输入调试问题");
  if (!promptContent.value.trim()) return ElMessage.error("主提示词不能为空");
  const question = agentForm.question.trim();
  const conversationHistory = agentPreviewMessages.value
    .slice(1)
    .filter((message) => ["user", "assistant"].includes(message.role) && message.content.trim() && !message.streaming)
    .map((message) => ({ role: message.role, content: message.content.trim() }));
  agentPreviewMessages.value.push({ role: "user", content: question });
  agentPreviewMessages.value.push({ role: "assistant", content: "", streaming: true });
  const assistantIndex = agentPreviewMessages.value.length - 1;
  const currentAssistant = () => agentPreviewMessages.value[assistantIndex];
  agentForm.question = "";
  agentDebugging.value = true;
  agentDebugTrace.value = [];
  lastDebugRoute.value = null;
  agentDebugAbortController.value = new AbortController();
  scrollAgentPreview();
  try {
    await streamDebugAgent(
      {
        promptContent: promptContent.value,
        modelId: agentForm.modelId,
        userId: agentForm.userId || null,
        topicSessionId: agentForm.topicSessionId || null,
        knowledgeIds: agentForm.knowledgeIds,
        question,
        history: conversationHistory,
        temperature: agentForm.temperature,
        topP: agentForm.topP,
        topK: agentForm.topK,
        presencePenalty: agentForm.presencePenalty,
        frequencyPenalty: agentForm.frequencyPenalty,
        maxToken: agentForm.maxToken,
        streamEnabled: agentForm.streamEnabled,
        reasoningVisible: agentForm.reasoningVisible,
        responseDepth: agentForm.responseDepth,
      },
      (chunk) => {
        currentAssistant().content += chunk;
        scrollAgentPreview();
      },
      (chunk) => {
        currentAssistant().reasoning = (currentAssistant().reasoning || "") + chunk;
        scrollAgentPreview();
      },
      (status) => {
        currentAssistant().showReasoning = status.reasoningVisible;
        scrollAgentPreview();
      },
      (result) => {
        agentDebugTrace.value = result.retrievalTrace || [];
        lastDebugRoute.value = { modelName: result.modelName, routeReason: result.routeReason };
        ElMessage.success(`${result.message || "Agent 调试完成"} · ${result.modelName || selectedModelName.value}`);
      },
      agentDebugAbortController.value.signal,
    );
    if (!currentAssistant().content.trim()) currentAssistant().content = "模型未返回正式回答。";
  } catch (error) {
    if (error instanceof DOMException && error.name === "AbortError") {
      currentAssistant().content ||= "已停止生成";
    } else {
      const message = errorMessage(error, "Agent 调试失败");
      currentAssistant().content ||= message;
      ElMessage.error(message);
    }
  } finally {
    currentAssistant().streaming = false;
    agentDebugging.value = false;
    agentDebugAbortController.value = null;
    scrollAgentPreview();
  }
}

function stopDebugAgent() {
  agentDebugAbortController.value?.abort();
}

function scrollAgentPreview() {
  void nextTick(() => {
    const element = agentPreviewChat.value;
    if (element) element.scrollTop = element.scrollHeight;
  });
}

function clearAgentPreview(message = "预览已清空，可以继续发起新的 Agent 调试。") {
  agentPreviewMessages.value = [{ role: "assistant", content: message }];
  agentDebugTrace.value = [];
  lastDebugRoute.value = null;
}

function changeTypeLabel(value?: string) {
  return ({ save: "手动保存", reset: "恢复默认", restore: "历史恢复", default: "系统默认" } as Record<string, string>)[value || ""] || "保存";
}

function changeTypeTag(value?: string) {
  if (value === "reset") return "warning";
  if (value === "restore") return "success";
  return "info";
}

function formatDate(value?: string | null) {
  if (!value) return "尚未保存";
  return new Date(value).toLocaleString("zh-CN", { hour12: false });
}

function errorMessage(error: unknown, fallback: string) {
  return error instanceof Error ? error.message : fallback;
}
</script>

<template>
  <div class="page-head agent-page-head">
    <div>
      <h2>Agent 管理</h2>
      <p>维护主提示词、用户端正式生成参数和历史版本，并验证真实检索与回答效果。</p>
    </div>
    <div class="agent-current-summary">
      <el-tag type="success">当前版本 {{ prompt?.id ? `#${prompt.id}` : "系统默认" }}</el-tag>
      <span>{{ prompt?.updatedByName || "系统默认" }} · {{ formatDate(prompt?.updatedAt) }}</span>
    </div>
  </div>

  <section v-loading="loading" class="agent-workbench agent-workbench-v2">
    <div class="agent-config-panel agent-control-panel">
      <el-tabs v-model="activeConfigTab" class="agent-config-tabs">
        <el-tab-pane label="主提示词" name="prompt">
          <div class="agent-section-intro">
            <div><h3>当前主提示词</h3><p>保存、恢复默认或恢复历史版本时都会新增版本，历史记录不会被覆盖。</p></div>
            <el-tag v-if="promptDirty" type="warning">有未保存修改</el-tag>
          </div>
          <el-input v-model="promptContent" class="agent-prompt-editor" type="textarea" :rows="18" resize="vertical" placeholder="请输入 Agent 主提示词" />
          <div class="agent-editor-meta"><span>{{ promptContent.length }} 字符</span><span>调试会立即使用编辑框中的内容</span></div>
          <div class="actions agent-primary-actions">
            <el-button type="primary" :loading="promptSaving" :disabled="!promptDirty" @click="savePrompt">保存为新版本</el-button>
            <el-button :loading="promptSaving" @click="resetPrompt">恢复默认提示词</el-button>
          </div>
        </el-tab-pane>

        <el-tab-pane label="正式运行配置" name="runtime">
          <div class="agent-section-intro">
            <div><h3>用户端正式运行参数</h3><p>保存后从用户端下一条消息开始生效。当前正式模型：{{ runtimeConfig?.modelName || '未启用模型' }}</p></div>
            <el-button type="primary" :loading="runtimeSaving" :disabled="!runtimeConfig?.modelId" @click="saveRuntimeConfig">保存正式参数</el-button>
          </div>
          <el-alert v-if="!runtimeConfig?.modelId" title="当前没有已启用模型，请先到模型管理中启用一个正式模型。" type="warning" :closable="false" show-icon />
          <el-alert v-else title="最大输出长度默认提升为 8192 Token；设置过低会导致长回答在完成前被模型截断。实际可用上限仍受模型供应商限制。" type="info" :closable="false" show-icon />
          <el-form label-position="top" class="agent-runtime-form">
            <section class="agent-advanced-settings">
              <div class="agent-subsection-title"><h4>正式生成参数</h4><span>用户端正式对话使用</span></div>
              <AgentGenerationParameters
                v-model:temperature="runtimeForm.temperature"
                v-model:top-p="runtimeForm.topP"
                v-model:top-k="runtimeForm.topK"
                v-model:presence-penalty="runtimeForm.presencePenalty"
                v-model:frequency-penalty="runtimeForm.frequencyPenalty"
                v-model:max-token="runtimeForm.maxToken"
                :disabled="!runtimeConfig?.modelId"
              />
              <AgentResponseDepthControl v-model="runtimeForm.responseDepth" :disabled="!runtimeConfig?.modelId" />
              <el-form-item class="agent-stream-setting">
                <div class="agent-stream-setting-copy">
                  <strong>用户端流式输出</strong>
                  <span>开启后回答正文会边生成边展示；关闭后等待模型完成，再一次性显示完整回答。</span>
                </div>
                <el-switch
                  v-model="runtimeForm.streamEnabled"
                  :active-value="1"
                  :inactive-value="0"
                  active-text="开启"
                  inactive-text="关闭"
                  inline-prompt
                  :disabled="!runtimeConfig?.modelId"
                />
              </el-form-item>
              <el-form-item class="agent-stream-setting">
                <div class="agent-stream-setting-copy">
                  <strong>展示思考过程</strong>
                  <span>开启后，用户端和后台调试预览可展开查看模型返回的思考内容；关闭时后端不会下发该内容。</span>
                </div>
                <el-switch
                  v-model="runtimeForm.reasoningVisible"
                  :active-value="1"
                  :inactive-value="0"
                  active-text="开启"
                  inactive-text="关闭"
                  inline-prompt
                  :disabled="!runtimeConfig?.modelId"
                />
              </el-form-item>
            </section>
          </el-form>
        </el-tab-pane>

        <el-tab-pane label="调试配置" name="debug">
          <div class="agent-section-intro"><div><h3>本次调试配置</h3><p>配置只作用于后台预览，不会修改模型和知识库的正式状态。</p></div></div>
          <el-form label-position="top">
            <el-form-item label="调试模型">
              <el-select v-model="agentForm.modelId" placeholder="选择已接入模型" @change="applyDebugModelDefaults">
                <el-option v-for="model in models" :key="model.id" :label="model.displayName || model.modelName" :value="model.id" />
              </el-select>
            </el-form-item>
            <div class="agent-debug-context-grid">
              <el-form-item label="模拟学员（可选）">
                <el-select
                  v-model="agentForm.userId"
                  clearable
                  filterable
                  remote
                  :remote-method="searchDebugUsers"
                  :loading="debugUserLoading"
                  :disabled="agentDebugging"
                  placeholder="不选择则不注入学员权益和近期实修回顾"
                  @change="handleDebugUserChange"
                >
                  <el-option
                    v-for="user in debugUsers"
                    :key="user.id"
                    :label="`${user.name || user.nickname || user.phone} · ${user.phone} · #${user.id}`"
                    :value="user.id"
                  />
                </el-select>
                <div class="agent-form-help">加载该学员的权益和近期实修回顾；只用于保持近期对话连续性，不会消耗额度或改动正式会话。</div>
              </el-form-item>
              <el-form-item label="模拟主题（可选）">
                <el-select
                  v-model="agentForm.topicSessionId"
                  clearable
                  filterable
                  remote
                  :remote-method="searchDebugTopics"
                  :loading="debugTopicLoading"
                  :disabled="!agentForm.userId || agentDebugging"
                  placeholder="选择学员后可加载具体主题"
                  @change="handleDebugTopicChange"
                >
                  <el-option
                    v-for="topic in debugTopics"
                    :key="topic.id"
                    :label="debugTopicOptionLabel(topic)"
                    :value="topic.id"
                  />
                </el-select>
                <div class="agent-form-help">选择后会加载该主题摘要和最近对话，用于验证追问效果。</div>
              </el-form-item>
            </div>
            <el-form-item label="调试知识库">
              <el-select v-model="agentForm.knowledgeIds" class="debug-knowledge-select" multiple filterable collapse-tags collapse-tags-tooltip :max-collapse-tags="2" popper-class="debug-knowledge-popper" placeholder="默认使用全部已开放知识库">
                <el-option v-for="item in knowledge" :key="item.id" :label="`${item.name}${item.status === 0 ? ' · 已关闭（仅本次预览）' : ''}`" :value="item.id" />
              </el-select>
            </el-form-item>
            <section class="agent-advanced-settings">
              <div class="agent-subsection-title"><h4>高级生成参数</h4><span>仅影响本次后台调试</span></div>
              <AgentGenerationParameters
                v-model:temperature="agentForm.temperature"
                v-model:top-p="agentForm.topP"
                v-model:top-k="agentForm.topK"
                v-model:presence-penalty="agentForm.presencePenalty"
                v-model:frequency-penalty="agentForm.frequencyPenalty"
                v-model:max-token="agentForm.maxToken"
              />
              <AgentResponseDepthControl v-model="agentForm.responseDepth" />
              <el-form-item class="agent-stream-setting">
                <div class="agent-stream-setting-copy">
                  <strong>流式输出</strong>
                  <span>开启后后台预览会边生成边展示；关闭后等待模型完成再一次性显示。</span>
                </div>
                <el-switch
                  v-model="agentForm.streamEnabled"
                  :active-value="1"
                  :inactive-value="0"
                  active-text="开启"
                  inactive-text="关闭"
                  inline-prompt
                />
              </el-form-item>
              <el-form-item class="agent-stream-setting">
                <div class="agent-stream-setting-copy">
                  <strong>展示思考过程</strong>
                  <span>开启后本次后台预览可展开查看模型思考内容；不会修改用户端正式配置。</span>
                </div>
                <el-switch
                  v-model="agentForm.reasoningVisible"
                  :active-value="1"
                  :inactive-value="0"
                  active-text="开启"
                  inactive-text="关闭"
                  inline-prompt
                />
              </el-form-item>
            </section>
          </el-form>
        </el-tab-pane>

        <el-tab-pane label="历史版本" name="history">
          <div class="agent-section-intro"><div><h3>主提示词历史</h3><p>查看完整内容或恢复任意版本。恢复操作会作为一个新版本记录。</p></div></div>
          <div v-loading="historyLoading" class="prompt-history-list">
            <el-empty v-if="history.length === 0" description="还没有已保存的提示词版本" :image-size="64" />
            <article v-for="item in history" :key="item.id" class="prompt-history-item" :class="{ current: item.isCurrent }">
              <div class="prompt-history-head">
                <strong>版本 #{{ item.id }}</strong>
                <el-tag v-if="item.isCurrent" type="success" size="small">当前</el-tag>
                <el-tag :type="changeTypeTag(item.changeType)" size="small">{{ changeTypeLabel(item.changeType) }}</el-tag>
                <span>{{ item.updatedByName }} · {{ formatDate(item.updatedAt) }}</span>
              </div>
              <p>{{ item.preview || "空内容" }}</p>
              <div class="prompt-history-foot">
                <span>{{ item.charCount }} 字符<span v-if="item.sourcePromptId"> · 来源 #{{ item.sourcePromptId }}</span></span>
                <div><el-button link type="primary" @click="openHistory(item)">查看完整内容</el-button><el-button v-if="!item.isCurrent" link type="primary" @click="restoreHistory(item.id)">恢复此版本</el-button></div>
              </div>
            </article>
          </div>
          <AdminPagination :page="historyPager.page" :page-size="historyPager.pageSize" :total="historyPager.total" @change="loadHistory" />
        </el-tab-pane>
      </el-tabs>
    </div>

    <aside class="agent-preview-panel">
      <div class="agent-preview-head">
        <div><h3>调试预览</h3><small>{{ selectedKnowledgeSummary }} · {{ selectedDebugUserLabel }} · {{ selectedDebugTopicLabel }}</small></div>
        <div class="agent-preview-head-actions"><span :title="lastDebugRoute?.routeReason || ''">{{ lastDebugRoute?.modelName || selectedModelName }}</span><el-button link :disabled="agentDebugging" @click="clearAgentPreview">清空</el-button></div>
      </div>
      <div ref="agentPreviewChat" class="agent-preview-chat">
        <article v-for="(message, index) in agentPreviewMessages" :key="`${message.role}-${index}`" class="agent-preview-message-row" :class="message.role">
          <div class="agent-preview-avatar">{{ message.role === "user" ? "你" : "AI" }}</div>
          <div class="agent-preview-bubble">
            <strong>{{ message.role === "user" ? "你" : "Agent" }}</strong>
            <template v-if="message.role === 'assistant'">
              <StreamingMarkdownMessage
                :content="message.content"
                :reasoning="message.reasoning"
                :show-reasoning="message.showReasoning"
                :streaming="message.streaming"
              />
            </template>
            <pre v-else>{{ message.content }}</pre>
          </div>
        </article>
      </div>
      <div class="agent-preview-composer">
        <el-input v-model="agentForm.question" type="textarea" :rows="2" resize="none" :disabled="agentDebugging" placeholder="向 Agent 发送测试问题；Enter 发送，Shift+Enter 换行" @keydown.enter.exact.prevent="debugAgent" />
        <el-button :type="agentDebugging ? 'danger' : 'primary'" @click="agentDebugging ? stopDebugAgent() : debugAgent()">{{ agentDebugging ? '停止' : '发送' }}</el-button>
      </div>
    </aside>

    <aside class="agent-trace-panel agent-trace-wide">
      <div class="agent-preview-head"><div><h3>检索追踪</h3><small>按调用顺序查看请求、响应、耗时与错误</small></div><span>本轮 {{ agentDebugTrace.length }} 次 Tool 调用</span></div>
      <div class="agent-trace-list">
        <el-empty v-if="agentDebugTrace.length === 0" description="发送问题后查看目录、检索与章节回读" :image-size="64" />
        <details v-for="(step, index) in agentDebugTrace" :key="index" class="tool-trace-node">
          <summary><strong>{{ index + 1 }}. {{ step.tool }}</strong><el-tag size="small" :type="step.status === 'failed' ? 'danger' : 'success'">{{ step.status || '完成' }}</el-tag><span>{{ step.durationMs ?? 0 }} ms</span></summary>
          <h5>请求</h5><pre>{{ JSON.stringify(step.request ?? {}, null, 2) }}</pre>
          <h5>响应</h5><pre>{{ step.response == null ? '返回为空' : JSON.stringify(step.response, null, 2) }}</pre>
          <el-alert v-if="step.error" :title="step.error" type="error" :closable="false" />
        </details>
      </div>
    </aside>
  </section>

  <el-dialog v-model="historyDetailOpen" width="min(820px, 92vw)" title="主提示词历史版本" destroy-on-close>
    <div v-loading="historyDetailLoading" class="prompt-history-detail">
      <template v-if="selectedHistory">
        <div class="prompt-history-detail-meta"><el-tag :type="changeTypeTag(selectedHistory.changeType)">{{ changeTypeLabel(selectedHistory.changeType) }}</el-tag><strong>版本 #{{ selectedHistory.id }}</strong><span>{{ selectedHistory.updatedByName }} · {{ formatDate(selectedHistory.updatedAt) }} · {{ selectedHistory.charCount }} 字符</span></div>
        <pre>{{ selectedHistory.promptContent }}</pre>
      </template>
    </div>
    <template #footer><el-button @click="historyDetailOpen = false">关闭</el-button><el-button v-if="selectedHistory?.id !== prompt?.id" type="primary" :loading="promptSaving" @click="restoreSelectedHistory">恢复为当前主提示词</el-button></template>
  </el-dialog>
</template>
