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

import { api } from "../services/api";
import type { AgentDebugResult, AgentRuntimeConfig, KnowledgeItem, ModelItem, PromptDetail, PromptHistoryItem } from "../types/api";
import AgentGenerationParameters from "./AgentGenerationParameters.vue";
import AdminPagination from "./AdminPagination.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 activeConfigTab = ref("prompt");
const prompt = ref<PromptDetail | null>(null);
const promptContent = ref("");
const savedPromptContent = ref("");
const models = ref<ModelItem[]>([]);
const knowledge = ref<KnowledgeItem[]>([]);
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 agentPreviewMessages = ref<{ role: "user" | "assistant" | "system"; content: string }[]>([
  { role: "assistant", content: "选择模型和知识库后，可以在这里调试 Agent 的真实问答效果。" },
]);

const agentForm = reactive({
  modelId: 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,
  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,
});

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} 个知识库`;
});

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.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);
    await loadHistory();
  } catch (error) {
    ElMessage.error(errorMessage(error, "Agent 配置加载失败"));
  } finally {
    loading.value = false;
  }
}

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,
  });
}

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,
  });
}

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,
    });
    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 (!agentForm.modelId) return ElMessage.error("请选择调试模型");
  if (!agentForm.question.trim()) return ElMessage.error("请输入调试问题");
  if (!promptContent.value.trim()) return ElMessage.error("主提示词不能为空");
  const question = agentForm.question.trim();
  agentPreviewMessages.value.push({ role: "user", content: question });
  agentForm.question = "";
  agentDebugging.value = true;
  try {
    const result: AgentDebugResult = await api.debugAgent({
      promptContent: promptContent.value,
      modelId: agentForm.modelId,
      knowledgeIds: agentForm.knowledgeIds,
      question,
      temperature: agentForm.temperature,
      topP: agentForm.topP,
      topK: agentForm.topK,
      presencePenalty: agentForm.presencePenalty,
      frequencyPenalty: agentForm.frequencyPenalty,
      maxToken: agentForm.maxToken,
    });
    if (!result.ok) {
      agentPreviewMessages.value.push({ role: "assistant", content: result.message });
      return ElMessage.error(result.message);
    }
    agentPreviewMessages.value.push({ role: "assistant", content: result.answer });
    agentDebugTrace.value = result.retrievalTrace || [];
    ElMessage.success(result.message);
  } catch (error) {
    const message = errorMessage(error, "Agent 调试失败");
    agentPreviewMessages.value.push({ role: "assistant", content: message });
    ElMessage.error(message);
  } finally {
    agentDebugging.value = false;
  }
}

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

function agentMessageParts(content: string) {
  const matched = content.match(/<think>([\s\S]*?)<\/think>/i);
  if (!matched) return { reasoning: "", answer: content };
  return {
    reasoning: matched[1].trim(),
    answer: content.replace(matched[0], "").trim() || "模型未返回正式回答。",
  };
}

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"
              />
            </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>
            <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"
              />
            </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 }}</small></div>
        <div class="agent-preview-head-actions"><span>{{ selectedModelName }}</span><el-button link @click="clearAgentPreview">清空</el-button></div>
      </div>
      <div 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'">
              <details v-if="agentMessageParts(message.content).reasoning" class="agent-preview-thinking"><summary>思考过程</summary><pre>{{ agentMessageParts(message.content).reasoning }}</pre></details>
              <pre>{{ agentMessageParts(message.content).answer }}</pre>
            </template>
            <pre v-else>{{ message.content }}</pre>
          </div>
        </article>
        <article v-if="agentDebugging" class="agent-preview-message-row assistant thinking"><div class="agent-preview-avatar">AI</div><div class="agent-preview-bubble"><strong>Agent</strong><pre>正在思考中...</pre></div></article>
      </div>
      <div class="agent-preview-composer">
        <el-input v-model="agentForm.question" type="textarea" :rows="2" resize="none" placeholder="向 Agent 发送测试问题；Enter 发送，Shift+Enter 换行" @keydown.enter.exact.prevent="debugAgent" />
        <el-button type="primary" :loading="agentDebugging" @click="debugAgent">发送</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>
