<script setup lang="ts">
import { computed, ref, watch } from "vue";

import { api } from "../services/api";
import type { KnowledgeVersionContent } from "../types/api";

const props = defineProps<{
  versionId: number | null;
  targetSectionId?: number | null;
  highlightKeyword?: string;
}>();

const loading = ref(false);
const error = ref("");
const content = ref<KnowledgeVersionContent | null>(null);
const activeSectionId = ref<number | null>(null);
let requestSequence = 0;

const activeSection = computed(() => (
  content.value?.sections.find((section) => section.id === activeSectionId.value)
  ?? content.value?.sections[0]
  ?? null
));

const characterCount = computed(() => (
  content.value?.sections.reduce((total, section) => total + section.content.length, 0) ?? 0
));

watch(() => props.versionId, loadVersion, { immediate: true });
watch(() => props.targetSectionId, selectTargetSection);

async function loadVersion(versionId: number | null) {
  const sequence = ++requestSequence;
  content.value = null;
  activeSectionId.value = null;
  error.value = "";
  if (!versionId) return;

  loading.value = true;
  try {
    const result = await api.knowledgeVersionContent(versionId);
    if (sequence !== requestSequence) return;
    content.value = result;
    activeSectionId.value = props.targetSectionId && result.sections.some((section) => section.id === props.targetSectionId)
      ? props.targetSectionId
      : result.sections[0]?.id ?? null;
  } catch (loadError) {
    if (sequence !== requestSequence) return;
    error.value = loadError instanceof Error ? loadError.message : "知识库内容加载失败";
  } finally {
    if (sequence === requestSequence) loading.value = false;
  }
}

function selectTargetSection(sectionId?: number | null) {
  if (!sectionId || !content.value?.sections.some((section) => section.id === sectionId)) return;
  activeSectionId.value = sectionId;
}

function highlightedParts(text: string) {
  const keyword = (props.highlightKeyword || "").trim();
  if (!keyword) return [{ text, match: false }];
  const parts: Array<{ text: string; match: boolean }> = [];
  const source = text || "";
  const lowerSource = source.toLowerCase();
  const lowerKeyword = keyword.toLowerCase();
  let cursor = 0;
  while (cursor < source.length) {
    const index = lowerSource.indexOf(lowerKeyword, cursor);
    if (index < 0) {
      parts.push({ text: source.slice(cursor), match: false });
      break;
    }
    if (index > cursor) parts.push({ text: source.slice(cursor, index), match: false });
    parts.push({ text: source.slice(index, index + keyword.length), match: true });
    cursor = index + keyword.length;
  }
  return parts.length ? parts : [{ text: source, match: false }];
}

</script>

<template>
  <section class="content-preview" v-loading="loading">
    <header class="content-preview-toolbar">
      <div>
        <h4>知识库内容预览</h4>
        <p>查看当前最新版实际进入检索链路的章节内容。</p>
      </div>
    </header>

    <el-alert v-if="error" :title="error" type="error" :closable="false" show-icon>
      <template #default><el-button link type="primary" @click="loadVersion(versionId)">重新加载</el-button></template>
    </el-alert>

    <el-empty v-else-if="!loading && !versionId" description="该知识库暂无可预览版本" />
    <el-empty v-else-if="!loading && content && content.sections.length === 0" description="当前版本没有可预览的章节内容" />

    <template v-else-if="content && activeSection">
      <div class="content-preview-summary">
        <span>V{{ content.version.versionNo }}</span>
        <span>{{ content.sections.length }} 个章节</span>
        <span>{{ content.cards.length }} 张知识卡</span>
        <span>约 {{ characterCount.toLocaleString() }} 字</span>
      </div>

      <div class="content-preview-layout">
        <aside class="content-outline" aria-label="章节目录">
          <strong>章节目录</strong>
          <button
            v-for="section in content.sections"
            :key="section.id"
            type="button"
            :class="{ active: section.id === activeSection.id }"
            :title="section.title"
            @click="activeSectionId = section.id"
          >
            <span>{{ section.sectionKey }}</span>
            <em>{{ section.title }}</em>
          </button>
        </aside>

        <article class="content-article">
          <div class="content-article-head">
            <div><small>{{ activeSection.sectionKey }}</small><h3>{{ activeSection.title }}</h3></div>
            <span>源内容位置 {{ activeSection.sourceStart }}–{{ activeSection.sourceEnd }}</span>
          </div>
          <pre><template v-for="(part, index) in highlightedParts(activeSection.content)" :key="index"><mark v-if="part.match">{{ part.text }}</mark><span v-else>{{ part.text }}</span></template></pre>
        </article>
      </div>

      <el-collapse class="content-card-panel">
        <el-collapse-item :title="`查看知识卡（${content.cards.length}）`" name="cards">
          <el-empty v-if="content.cards.length === 0" description="当前版本尚未生成知识卡" :image-size="72" />
          <el-table v-else :data="content.cards" max-height="360">
            <el-table-column prop="title" label="标题" min-width="180" />
            <el-table-column prop="summary" label="摘要" min-width="320" show-overflow-tooltip />
            <el-table-column prop="riskLevel" label="风险" width="100" />
          </el-table>
        </el-collapse-item>
      </el-collapse>
    </template>
  </section>
</template>

<style scoped>
.content-preview { min-height: 360px; }
.content-preview-toolbar { display: flex; align-items: flex-start; justify-content: space-between; gap: 20px; margin-bottom: 16px; }
.content-preview-toolbar h4 { margin: 0; font-size: 17px; color: #203b32; }
.content-preview-toolbar p { margin: 6px 0 0; color: #71817b; font-size: 13px; }
.content-preview-summary { display: flex; flex-wrap: wrap; gap: 8px; margin-bottom: 12px; }
.content-preview-summary span { padding: 5px 10px; border-radius: 999px; background: #f0f6f3; color: #526860; font-size: 12px; }
.content-preview-layout { display: grid; grid-template-columns: 250px minmax(0, 1fr); height: clamp(420px, 62vh, 680px); min-height: 0; overflow: hidden; border: 1px solid #dfe8e5; border-radius: 12px; background: #fff; }
.content-outline { min-width: 0; min-height: 0; height: 100%; overflow-y: auto; overscroll-behavior: contain; scrollbar-gutter: stable; padding: 14px 10px; border-right: 1px solid #e5ece9; background: #f7faf9; }
.content-outline > strong { display: block; padding: 0 10px 10px; color: #455c53; font-size: 13px; }
.content-outline button { display: grid; grid-template-columns: auto minmax(0, 1fr); align-items: center; width: 100%; gap: 8px; padding: 10px; border: 0; border-radius: 8px; background: transparent; color: #53645e; text-align: left; cursor: pointer; }
.content-outline button:hover { background: #eaf3ef; }
.content-outline button.active { background: #dcefe7; color: #176746; }
.content-outline button span { font-size: 11px; color: #7c8d87; }
.content-outline button em { overflow: hidden; font-style: normal; font-size: 13px; font-weight: 600; text-overflow: ellipsis; white-space: nowrap; }
.content-article { min-width: 0; min-height: 0; height: 100%; overflow-y: auto; overscroll-behavior: contain; scrollbar-gutter: stable; padding: 24px 28px; }
.content-article-head { display: flex; align-items: flex-start; justify-content: space-between; gap: 20px; padding-bottom: 16px; border-bottom: 1px solid #edf1ef; }
.content-article-head small { color: #26815f; }
.content-article-head h3 { margin: 5px 0 0; color: #203b32; font-size: 20px; }
.content-article-head > span { color: #88958f; font-size: 12px; white-space: nowrap; }
.content-article pre { margin: 20px 0 0; white-space: pre-wrap; overflow-wrap: anywhere; color: #354840; font: inherit; font-size: 14px; line-height: 1.85; }
.content-article mark { padding: 0 2px; border-radius: 3px; background: #fff1a8; color: inherit; }
.content-card-panel { margin-top: 16px; }
@media (max-width: 900px) {
  .content-preview-toolbar { align-items: stretch; flex-direction: column; }
  .content-preview-layout { grid-template-columns: 1fr; height: auto; min-height: 0; overflow: visible; }
  .content-outline { display: flex; height: auto; gap: 8px; overflow-x: auto; overflow-y: hidden; border-right: 0; border-bottom: 1px solid #e5ece9; }
  .content-outline > strong { display: none; }
  .content-outline button { min-width: 180px; width: 180px; }
  .content-article { height: auto; max-height: 58vh; padding: 20px; }
  .content-article-head { flex-direction: column; gap: 8px; }
}
</style>
