<script setup lang="ts">
import { ElMessage } from "element-plus";
import { onMounted, reactive, ref, watch } from "vue";
import { api } from "../services/api";
import type {
  AiLogRecord,
  ChatRecord,
  QuestionInsightSummary,
  SsoClientItem,
} from "../types/api";
import AdminPagination from "./AdminPagination.vue";
import AiLogDetailDrawer from "./AiLogDetailDrawer.vue";
import ChatDetailDrawer from "./ChatDetailDrawer.vue";

type RecordTab = "chats" | "questionInsights" | "aiLogs" | "operationLogs";
const loading = ref(false);
const activeTab = ref<RecordTab>("chats");
const chats = ref<ChatRecord[]>([]);
const ssoClients = ref<SsoClientItem[]>([]);
const aiLogs = ref<AiLogRecord[]>([]);
const operationLogs = ref<Record<string, unknown>[]>([]);
const insights = ref<QuestionInsightSummary | null>(null);
const detailSessionId = ref<number | null>(null);
const chatDetailOpen = ref(false);
const aiLogId = ref<number | null>(null);
const aiLogDetailOpen = ref(false);
const pagers = reactive({
  chats: { page: 1, pageSize: 20, total: 0 },
  aiLogs: { page: 1, pageSize: 20, total: 0 },
  operationLogs: { page: 1, pageSize: 20, total: 0 },
  questionInsights: { page: 1, pageSize: 20, total: 0 },
});
const chatFilters = reactive({
  keyword: "",
  userId: undefined as number | undefined,
  status: "",
  sourceType: "",
  sourceClientId: undefined as number | undefined,
  dateFrom: "",
  dateTo: "",
});
const insightFilters = reactive({
  dateFrom: "",
  dateTo: "",
  minCount: 2,
  maxMessages: 5000,
});

onMounted(async () => {
  await Promise.all([loadTab("chats"), loadSsoClients()]);
});
watch(activeTab, (tab) => loadTab(tab));

async function loadTab(tab: RecordTab = activeTab.value) {
  loading.value = true;
  try {
    if (tab === "chats") {
      const result = await api.chats({
        ...buildChatQuery(),
        page: pagers.chats.page,
        pageSize: pagers.chats.pageSize,
      });
      chats.value = result.items;
      Object.assign(pagers.chats, {
        page: result.page,
        pageSize: result.pageSize,
        total: result.total,
      });
    } else if (tab === "aiLogs") {
      const result = await api.aiLogs({
        page: pagers.aiLogs.page,
        pageSize: pagers.aiLogs.pageSize,
      });
      aiLogs.value = result.items;
      Object.assign(pagers.aiLogs, {
        page: result.page,
        pageSize: result.pageSize,
        total: result.total,
      });
    } else if (tab === "operationLogs") {
      const result = await api.operationLogs({
        page: pagers.operationLogs.page,
        pageSize: pagers.operationLogs.pageSize,
      });
      operationLogs.value = result.items;
      Object.assign(pagers.operationLogs, {
        page: result.page,
        pageSize: result.pageSize,
        total: result.total,
      });
    } else
      await loadInsights(
        pagers.questionInsights.page,
        pagers.questionInsights.pageSize,
      );
  } finally {
    loading.value = false;
  }
}
async function loadSsoClients() {
  try {
    ssoClients.value = await api.ssoClients();
  } catch {
    ssoClients.value = [];
  }
}

async function changePage(tab: RecordTab, page: number, pageSize: number) {
  Object.assign(pagers[tab], { page, pageSize });
  await loadTab(tab);
}
async function loadInsights(
  page = 1,
  pageSize = pagers.questionInsights.pageSize,
) {
  insights.value = await api.questionInsights({
    dateFrom: formatDateTime(insightFilters.dateFrom, "start"),
    dateTo: formatDateTime(insightFilters.dateTo, "end"),
    minCount: insightFilters.minCount,
    maxMessages: insightFilters.maxMessages,
    page,
    pageSize,
  });
  Object.assign(pagers.questionInsights, {
    page: insights.value.page,
    pageSize: insights.value.pageSize,
    total: insights.value.total,
  });
}
async function searchChats() {
  pagers.chats.page = 1;
  await loadTab("chats");
}
async function resetChatFilters() {
  Object.assign(chatFilters, {
    keyword: "",
    userId: undefined,
    status: "",
    sourceType: "",
    sourceClientId: undefined,
    dateFrom: "",
    dateTo: "",
  });
  await searchChats();
}
async function refreshInsights() {
  pagers.questionInsights.page = 1;
  loading.value = true;
  try {
    const result = await api.refreshQuestionInsights({
      dateFrom: formatDateTime(insightFilters.dateFrom, "start"),
      dateTo: formatDateTime(insightFilters.dateTo, "end"),
      maxMessages: insightFilters.maxMessages,
    });
    await loadInsights(1);
    ElMessage.success(
      result.processedMessages
        ? `新增清洗 ${result.processedMessages} 条消息，得到 ${result.acceptedQuestions} 个有效问题${result.hasMore ? "；仍有历史消息待清洗" : ""}`
        : "没有新增消息，已直接使用持久化清洗结果统计",
    );
  } catch (error) {
    ElMessage.error(
      error instanceof Error ? error.message : "问题洞察刷新失败",
    );
  } finally {
    loading.value = false;
  }
}
async function resetInsightFilters() {
  Object.assign(insightFilters, {
    dateFrom: "",
    dateTo: "",
    minCount: 2,
    maxMessages: 5000,
  });
  await refreshInsights();
}
function openChat(sessionId: number) {
  detailSessionId.value = sessionId;
  chatDetailOpen.value = true;
}
function openAiLog(row: AiLogRecord) {
  aiLogId.value = row.id;
  aiLogDetailOpen.value = true;
}
function buildChatQuery() {
  return {
    keyword: chatFilters.keyword,
    userId: chatFilters.userId,
    status: chatFilters.status,
    sourceType: chatFilters.sourceType,
    sourceClientId: chatFilters.sourceClientId,
    dateFrom: formatDateTime(chatFilters.dateFrom, "start"),
    dateTo: formatDateTime(chatFilters.dateTo, "end"),
  };
}
function formatDateTime(value: string, boundary: "start" | "end") {
  if (!value) return "";
  const [date, time = ""] = value.trim().replace("T", " ").split(" ");
  if (!date) return "";
  const [hour = "00", minute = "00", second] = time.split(":");
  return `${date} ${hour.padStart(2, "0")}:${minute.padStart(2, "0")}:${(second ?? (boundary === "end" ? "59" : "00")).padStart(2, "0")}`;
}
function formatMoney(value?: number | null, currency = "CNY") {
  return typeof value === "number"
    ? `${currency || "CNY"} ${value.toFixed(6)}`
    : "-";
}
</script>

<template>
  <section class="feature-page">
    <div class="page-head">
      <h2>记录审计</h2>
      <p>聊天、AI 请求和后台操作记录。</p>
    </div>
    <el-tabs v-model="activeTab">
      <el-tab-pane label="聊天记录" name="chats">
        <div class="record-filter">
          <el-input
            v-model="chatFilters.keyword"
            placeholder="搜索标题、手机号、姓名、聊天内容"
            clearable
          /><el-input-number
            v-model="chatFilters.userId"
            :min="1"
            placeholder="用户ID"
          /><el-select
            v-model="chatFilters.status"
            placeholder="消息状态"
            clearable
            ><el-option label="全部状态" value="" /><el-option
              label="已完成"
              value="FINISHED" /><el-option
              label="生成中"
              value="GENERATING" /><el-option
              label="已停止"
              value="STOPPED" /><el-option label="失败" value="FAILED"
          /></el-select>
          <el-select v-model="chatFilters.sourceType" placeholder="会话来源" clearable @change="chatFilters.sourceClientId = undefined">
            <el-option label="直接访问" value="direct" />
            <el-option label="第三方应用" value="sso" />
          </el-select>
          <el-select v-if="chatFilters.sourceType === 'sso'" v-model="chatFilters.sourceClientId" placeholder="来源应用" clearable>
            <el-option v-for="client in ssoClients" :key="client.id" :label="client.name" :value="client.id" />
          </el-select>
          <div class="record-date-range" aria-label="时间范围">
            <label class="record-date-field"
              ><span>开始时间</span
              ><input
                v-model="chatFilters.dateFrom"
                type="datetime-local"
                aria-label="开始时间" /></label
            ><span class="record-date-sep">至</span
            ><label class="record-date-field"
              ><span>结束时间</span
              ><input
                v-model="chatFilters.dateTo"
                type="datetime-local"
                aria-label="结束时间"
            /></label>
          </div>
          <div class="record-filter-actions">
            <el-button type="primary" @click="searchChats">搜索</el-button
            ><el-button @click="resetChatFilters">重置</el-button
            ><el-button @click="api.exportChats(buildChatQuery())"
              >导出</el-button
            >
          </div>
        </div>
        <el-table v-loading="loading" :data="chats" stripe
          ><el-table-column
            prop="id"
            label="会话ID"
            width="90"
          /><el-table-column
            prop="userPhone"
            label="手机号"
            width="140"
          /><el-table-column
            prop="userName"
            label="用户"
            width="120"
          /><el-table-column
            prop="sourceName"
            label="会话来源"
            min-width="160"
            show-overflow-tooltip
          /><el-table-column
            prop="title"
            label="会话标题"
            min-width="220"
            show-overflow-tooltip
          /><el-table-column
            prop="messageCount"
            label="消息数"
            width="90"
          /><el-table-column
            prop="lastMessageAt"
            label="最后消息"
            width="180"
          /><el-table-column label="操作" width="100" fixed="right"
            ><template #default="{ row }"
              ><el-button size="small" @click="openChat(row.id)"
                >详情</el-button
              ></template
            ></el-table-column
          ></el-table
        >
        <AdminPagination
          :page="pagers.chats.page"
          :page-size="pagers.chats.pageSize"
          :total="pagers.chats.total"
          @change="(page, size) => changePage('chats', page, size)"
        />
      </el-tab-pane>
      <el-tab-pane label="问题洞察" name="questionInsights">
        <div class="record-filter question-insight-filter">
          <div class="record-date-range" aria-label="问题时间范围">
            <label class="record-date-field"
              ><span>开始时间</span
              ><input
                v-model="insightFilters.dateFrom"
                type="datetime-local"
                aria-label="问题开始时间" /></label
            ><span class="record-date-sep">至</span
            ><label class="record-date-field"
              ><span>结束时间</span
              ><input
                v-model="insightFilters.dateTo"
                type="datetime-local"
                aria-label="问题结束时间"
            /></label>
          </div>
          <label class="insight-number-field"
            ><span>最低频次</span
            ><el-input-number
              v-model="insightFilters.minCount"
              :min="1"
              :max="50"
              controls-position="right" /></label
          ><label class="insight-number-field"
            ><span>单次清洗上限</span
            ><el-input-number
              v-model="insightFilters.maxMessages"
              :min="100"
              :max="20000"
              :step="500"
              controls-position="right"
          /></label>
          <div class="record-filter-actions">
            <el-button
              type="primary"
              :loading="loading"
              @click="refreshInsights"
              >刷新并统计</el-button
            ><el-button @click="resetInsightFilters">重置</el-button>
          </div>
        </div>
        <p class="question-insight-help">
          清洗结果会持久化保存；点击“刷新并统计”只处理尚未清洗的用户消息，再按当前时间范围聚合，翻页不会重新扫描聊天原文。
        </p>
        <section v-if="insights" class="question-insight-summary">
          <div>
            <span>纳入清洗消息</span
            ><strong>{{ insights.summary.scannedMessages }}</strong>
          </div>
          <div>
            <span>有效问题</span
            ><strong>{{ insights.summary.cleanedQuestions }}</strong>
          </div>
          <div>
            <span>过滤低价值</span
            ><strong>{{ insights.summary.filteredMessages }}</strong>
          </div>
          <div>
            <span>高频问题组</span
            ><strong>{{ insights.summary.visibleClusterCount }}</strong>
          </div>
        </section>
        <section v-loading="loading" class="question-insight-list">
          <article
            v-for="cluster in insights?.items || []"
            :key="`${cluster.rank}-${cluster.normalized}`"
            class="question-insight-card"
          >
            <header>
              <div>
                <small>TOP {{ cluster.rank }}</small>
                <h3>{{ cluster.title }}</h3>
              </div>
              <div class="question-insight-metrics">
                <span>{{ cluster.count }} 次</span
                ><span>{{ cluster.userCount }} 人</span
                ><span>{{ cluster.sessionCount }} 个会话</span>
              </div>
            </header>
            <div class="question-insight-tags">
              <el-tag size="small" effect="plain">{{
                cluster.categoryLabel
              }}</el-tag
              ><el-tag
                v-if="cluster.needsKnowledgeFollowUp"
                size="small"
                type="warning"
                effect="plain"
                >需补知识/查召回</el-tag
              ><el-tag
                v-if="cluster.noHitCount"
                size="small"
                type="danger"
                effect="plain"
                >无命中 {{ cluster.noHitCount }}</el-tag
              ><el-tag
                v-if="cluster.failedCount"
                size="small"
                type="danger"
                effect="dark"
                >失败 {{ cluster.failedCount }}</el-tag
              ><el-tag
                v-for="term in cluster.topTerms"
                :key="term"
                size="small"
                type="success"
                effect="plain"
                >{{ term }}</el-tag
              >
            </div>
            <p class="question-insight-action">{{ cluster.suggestedAction }}</p>
            <el-collapse
              ><el-collapse-item
                title="查看相似问法和原始样例"
                :name="cluster.normalized"
                ><div class="question-variants">
                  <span v-for="variant in cluster.variants" :key="variant.text"
                    >{{ variant.text }} × {{ variant.count }}</span
                  >
                </div>
                <div class="question-samples">
                  <article
                    v-for="sample in cluster.samples"
                    :key="sample.messageId"
                  >
                    <div>
                      <strong>{{
                        sample.userName ||
                        sample.userPhone ||
                        `用户 #${sample.userId}`
                      }}</strong
                      ><span>{{ sample.createdAt }}</span>
                    </div>
                    <p>清洗后：{{ sample.cleaned }}</p>
                    <pre>{{ sample.raw }}</pre>
                    <el-button
                      link
                      type="primary"
                      @click="openChat(sample.sessionId)"
                      >查看原会话</el-button
                    >
                  </article>
                </div></el-collapse-item
              ></el-collapse
            >
          </article>
          <el-empty
            v-if="insights && insights.items.length === 0"
            description="当前条件下暂无达到频次的问题组"
            :image-size="72"
          /><el-empty
            v-else-if="!insights && !loading"
            description="选择时间范围后点击统计问题"
            :image-size="72"
          />
        </section>
        <AdminPagination
          :page="pagers.questionInsights.page"
          :page-size="pagers.questionInsights.pageSize"
          :total="pagers.questionInsights.total"
          @change="(page, size) => changePage('questionInsights', page, size)"
        />
      </el-tab-pane>
      <el-tab-pane label="AI 请求" name="aiLogs"
        ><el-table v-loading="loading" :data="aiLogs" stripe
          ><el-table-column
            prop="sessionId"
            label="会话ID"
            width="90"
          /><el-table-column
            prop="modelName"
            label="模型"
            width="160"
          /><el-table-column
            prop="knowledgeIds"
            label="知识库"
            width="120"
          /><el-table-column
            prop="retrieveCount"
            label="命中"
            width="80"
          /><el-table-column label="片段" width="80"
            ><template #default="{ row }">{{
              row.retrievedChunks?.length || 0
            }}</template></el-table-column
          ><el-table-column
            prop="totalToken"
            label="Token"
            width="90"
          /><el-table-column label="估算成本" width="130"
            ><template #default="{ row }">{{
              formatMoney(row.estimatedCost, row.currency || "CNY")
            }}</template></el-table-column
          ><el-table-column
            prop="costMs"
            label="耗时(ms)"
            width="100"
          /><el-table-column
            prop="status"
            label="状态"
            width="100"
          /><el-table-column
            prop="errorMessage"
            label="错误"
            min-width="220"
            show-overflow-tooltip
          /><el-table-column label="操作" width="100" fixed="right"
            ><template #default="{ row }"
              ><el-button size="small" @click="openAiLog(row)"
                >详情</el-button
              ></template
            ></el-table-column
          ></el-table
        ><AdminPagination
          :page="pagers.aiLogs.page"
          :page-size="pagers.aiLogs.pageSize"
          :total="pagers.aiLogs.total"
          @change="(page, size) => changePage('aiLogs', page, size)"
      /></el-tab-pane>
      <el-tab-pane label="操作日志" name="operationLogs"
        ><el-table v-loading="loading" :data="operationLogs" stripe
          ><el-table-column prop="module" label="模块" /><el-table-column
            prop="action"
            label="动作" /><el-table-column
            prop="result"
            label="结果" /><el-table-column
            prop="createdAt"
            label="时间" /></el-table
        ><AdminPagination
          :page="pagers.operationLogs.page"
          :page-size="pagers.operationLogs.pageSize"
          :total="pagers.operationLogs.total"
          @change="(page, size) => changePage('operationLogs', page, size)"
      /></el-tab-pane>
    </el-tabs>
    <ChatDetailDrawer v-model="chatDetailOpen" :session-id="detailSessionId" />
    <AiLogDetailDrawer v-model="aiLogDetailOpen" :log-id="aiLogId" />
  </section>
</template>
