<template>
  <!-- ① 基本信息 -->
  <section class="detail-section">
    <div class="detail-head">
      <div class="detail-title-row">
        <span class="detail-kind-icon">{{ kindIcon(detail.knowledge.kind) }}</span>
        <span v-if="!editing" class="detail-title">{{ detail.knowledge.title }}</span>
        <input v-else v-model="editForm.title" class="edit-input edit-input-title" />
      </div>
      <div class="detail-actions" v-if="!editing">
        <button class="btn btn-ghost btn-sm" @click="startEdit">{{ t('knowledge.edit') }}</button>
        <template v-if="topTab === 'inbox'">
          <button class="btn btn-primary btn-sm" :disabled="submitting" @click="emit('publish')">{{ t('knowledge.publish') }}</button>
          <button class="btn btn-ghost btn-sm" :disabled="submitting" @click="emit('reject')">{{ t('knowledge.reject') }}</button>
        </template>
        <button v-else class="btn btn-ghost btn-sm" :disabled="submitting" @click="emit('archive')">{{ t('knowledge.archive') }}</button>
      </div>
      <div class="detail-actions" v-else>
        <button class="btn btn-ghost btn-sm" @click="cancelEdit">{{ t('common.cancel') }}</button>
        <button class="btn btn-primary btn-sm" @click="saveEdit" :disabled="submitting || !editForm.title.trim()">{{ t('common.save') }}</button>
      </div>
    </div>

    <div class="detail-badges">
      <span class="kn-card-status" :class="'st-' + detail.knowledge.status">{{ statusLabel(detail.knowledge.status) }}</span>
      <span v-if="detail.knowledge.confidence" :class="'conf-' + detail.knowledge.confidence">{{ t('knowledge.confidenceBadge', { label: confidenceLabel(detail.knowledge.confidence) }) }}</span>
      <span class="badge-plain">{{ t('knowledge.reuseCount', { n: detail.knowledge.reuse_count }) }}</span>
      <span class="badge-plain">{{ kindLabel(detail.knowledge.kind) }}</span>
    </div>

    <div class="detail-field">
      <label>{{ t('knowledge.contentLabel') }}</label>
      <!-- B-260615-25:知识内容 Markdown 渲染(展示态),复用 useMarkdown composable(同 B-24 TaskDetail);编辑态保持 textarea -->
      <div
        v-if="!editing && detail.knowledge.content"
        ref="contentEl"
        class="detail-content ai-md"
        :class="{ 'content-collapsed': !contentExpanded }"
        v-html="renderedContent"
      ></div>
      <div v-else-if="!editing" class="detail-content">—</div>
      <textarea v-else v-model="editForm.content" class="edit-input edit-textarea"></textarea>
      <!-- P1 内容超长折叠:渲染后高度 > 300px 显示展开/收起 -->
      <button
        v-if="!editing && contentOverflow"
        class="btn btn-ghost btn-sm fold-toggle"
        @click="contentExpanded = !contentExpanded"
      >{{ contentExpanded ? t('common.collapse') : t('common.expand') }}</button>
    </div>

    <div class="detail-field">
      <label>{{ t('knowledge.tagsLabel') }}</label>
      <div v-if="!editing" class="detail-tags">
        <span class="tag" v-for="tag in parseTags(detail.knowledge.tags)" :key="tag">{{ tag }}</span>
        <span v-if="parseTags(detail.knowledge.tags).length === 0" class="muted">{{ t('knowledge.tagsNone') }}</span>
      </div>
      <input v-else v-model="editForm.tagsInput" class="edit-input" :placeholder="t('knowledge.tagsPlaceholder')" />
    </div>
  </section>

  <!-- ② 溯源(P0 折叠:标题点击切换,默认展开)-->
  <section class="detail-section">
    <div class="section-title section-title-toggle" @click="sectionOpen.trace = !sectionOpen.trace">
      <span>{{ t('knowledge.traceTitle') }}</span>
      <span class="section-chevron">{{ sectionOpen.trace ? '▾' : '▸' }}</span>
    </div>
    <div v-show="sectionOpen.trace" class="section-body">
      <div class="trace-row">
        <span class="trace-label">{{ t('knowledge.traceMethod') }}</span>
        <span>{{ originMethod }}</span>
      </div>
      <div class="trace-row" v-if="originConvTitle">
        <span class="trace-label">{{ t('knowledge.traceSource') }}</span>
        <span>{{ originConvTitle }}</span>
      </div>
      <div class="trace-row" v-if="originTime">
        <span class="trace-label">{{ t('knowledge.traceTime') }}</span>
        <span>{{ originTime }}</span>
      </div>
      <div class="detail-field" v-if="reasoningText">
        <label>{{ t('knowledge.reasoningLabel') }}</label>
        <!-- P1 reasoning 折叠:长文本默认收起,避免挤占视口 -->
        <div
          class="reasoning-box"
          :class="{ 'reasoning-collapsed': !reasoningExpanded }"
        >{{ reasoningText }}</div>
        <button
          v-if="reasoningOverflow || reasoningExpanded"
          class="btn btn-ghost btn-sm fold-toggle"
          @click="reasoningExpanded = !reasoningExpanded"
        >{{ reasoningExpanded ? t('common.collapse') : t('common.expand') }}</button>
      </div>
    </div>
  </section>

  <!-- ③ 引用(P0 折叠)-->
  <section class="detail-section">
    <div class="section-title section-title-toggle" @click="sectionOpen.refs = !sectionOpen.refs">
      <span>{{ t('knowledge.refTitle', { n: referenceEvents.length }) }}</span>
      <span class="section-chevron">{{ sectionOpen.refs ? '▾' : '▸' }}</span>
    </div>
    <div v-show="sectionOpen.refs" class="section-body">
      <div v-if="referenceEvents.length === 0" class="muted">{{ t('knowledge.refEmpty') }}</div>
      <div v-else class="ref-list">
        <div v-for="ref in referenceEvents.slice(0, refLimit)" :key="ref.id" class="ref-item">
          <span class="ref-time">{{ relativeTime(ref.timestamp) }}</span>
          <span class="ref-conv">{{ refConvTitle(ref) }}</span>
          <span class="ref-query" v-if="refQuery(ref)">“{{ refQuery(ref) }}”</span>
        </div>
        <button v-if="referenceEvents.length > refLimit" class="btn btn-ghost btn-sm load-more" @click="refLimit += 10">
          {{ t('knowledge.loadMore', { n: referenceEvents.length - refLimit }) }}
        </button>
      </div>
    </div>
  </section>

  <!-- ④ 生命周期时间线(P0 折叠:默认收起,回顾性信息通常无需常驻)-->
  <section class="detail-section">
    <div class="section-title section-title-toggle" @click="sectionOpen.lifecycle = !sectionOpen.lifecycle">
      <span>{{ t('knowledge.lifecycleTitle') }}</span>
      <span class="section-chevron">{{ sectionOpen.lifecycle ? '▾' : '▸' }}</span>
    </div>
    <div v-show="sectionOpen.lifecycle" class="section-body">
    <div class="timeline">
      <div v-for="(node, idx) in timelineNodes" :key="node.id" class="tl-node">
        <div class="tl-dot">{{ node.icon }}</div>
        <div v-if="idx < timelineNodes.length - 1" class="tl-line"></div>
        <div class="tl-body">
          <div class="tl-label">{{ node.label }}</div>
          <div class="tl-time">{{ relativeTime(node.timestamp) }}</div>
          <div class="tl-summary" v-if="node.summary">{{ node.summary }}</div>
        </div>
      </div>
    </div>
    </div>
  </section>
</template>

<script setup lang="ts">
import { ref, computed, watch, nextTick } from 'vue'
import { useI18n } from 'vue-i18n'
import {
  parseTags,
  kindLabel,
  kindIcon,
  knowledgeStatusLabel as statusLabel,
  knowledgeConfidenceLabel as confidenceLabel,
} from '@/stores/knowledge'
import { useRendered } from '@/composables/useMarkdown'
import type { KnowledgeDetailPayload, KnowledgeEventRecord } from '@/api/types'

// 详情面板子组件(Knowledge.vue 拆分,SW-260618-20):
// 接收 detail 渲染只读四段(基本信息/溯源/引用/时间线),内部自管 editing/editForm/refLimit;
// 编辑保存与审核操作通过 emit 回传父级执行 IPC(publish/reject/archive/save)。
const props = defineProps<{
  detail: KnowledgeDetailPayload
  topTab: 'library' | 'inbox'
  submitting: boolean
}>()

const emit = defineEmits<{
  (e: 'save', payload: { id: string; data: { title: string; content: string; tags: string; confidence: string } }): void
  (e: 'publish'): void
  (e: 'reject'): void
  (e: 'archive'): void
}>()

const { t } = useI18n()

// ===== 编辑(内部状态,与原 Knowledge.vue 行为一致)=====
const editing = ref(false)
const editForm = ref({ title: '', content: '', tagsInput: '', confidence: '' })

function startEdit() {
  const k = props.detail.knowledge
  editForm.value = {
    title: k.title,
    content: k.content,
    tagsInput: parseTags(k.tags).join(', '),
    confidence: k.confidence ?? '',
  }
  editing.value = true
}

function cancelEdit() {
  editing.value = false
}

function saveEdit() {
  if (!editForm.value.title.trim()) return
  const tags = editForm.value.tagsInput.split(',').map(t => t.trim()).filter(Boolean)
  emit('save', {
    id: props.detail.knowledge.id,
    data: {
      title: editForm.value.title.trim(),
      content: editForm.value.content,
      tags: JSON.stringify(tags),
      confidence: editForm.value.confidence,  // 空串=清空(后端映射 None),非 undefined
    },
  })
  editing.value = false
}

// ===== Markdown 渲染(B-260615-25,复用模块单例渲染器)=====
const { rendered: renderedContent, ensureLoaded } = useRendered(
  () => props.detail?.knowledge.content ?? '',
)

// 引用列表「加载更多」上限
const refLimit = ref(10)

// ===== 折叠态(P0 溯源/引用/生命周期段折叠 + P1 内容/reasoning 超长折叠)=====
// 段落默认开合:溯源/引用默认展开(常用),生命周期默认收起(回顾性,通常无需常驻)
const sectionOpen = ref({ trace: true, refs: true, lifecycle: false })

// 内容/reasoning 折叠:超阈值(300px / 120px)才显示「展开/收起」按钮
const CONTENT_FOLD_THRESHOLD = 300
const REASONING_FOLD_THRESHOLD = 120
const contentEl = ref<HTMLElement | null>(null)
const contentExpanded = ref(false)
const contentOverflow = ref(false)
const reasoningExpanded = ref(false)
const reasoningOverflow = ref(false)

// 测量内容/reasoning 实际高度,决定是否需折叠按钮(渲染异步,DOM 更新后测)
async function measureOverflow() {
  await nextTick()
  if (contentEl.value) {
    // 临时移除折叠限制测量真实高度
    contentEl.value.style.maxHeight = 'none'
    const h = contentEl.value.scrollHeight
    contentEl.value.style.maxHeight = ''
    contentOverflow.value = h > CONTENT_FOLD_THRESHOLD
    if (!contentOverflow.value) contentExpanded.value = false
  }
  // reasoning 用纯文本高度估算(行数 * 行高 1.6 * 13px ≈ 20.8px/行)
  const rText: string = reasoningText.value || ''
  if (rText) {
    const approxLines = rText.split('\n').reduce<number>((acc, line) => acc + Math.max(1, Math.ceil(line.length / 60)), 0)
    reasoningOverflow.value = approxLines * 21 > REASONING_FOLD_THRESHOLD
    if (!reasoningOverflow.value) reasoningExpanded.value = false
  } else {
    reasoningOverflow.value = false
  }
}

defineExpose({ ensureLoaded })

// ===== 事件解析辅助 =====
function parseContext(e: KnowledgeEventRecord): Record<string, any> {
  if (!e.context_json) return {}
  try { return JSON.parse(e.context_json) } catch { return {} }
}

function refConvTitle(e: KnowledgeEventRecord): string {
  // 解析一次复用:原两次 parseContext 调用会重复 JSON.parse,引用列表项越多浪费越大
  const ctx = parseContext(e)
  return ctx.conv_title || ctx.conv_id || ''
}
function refQuery(e: KnowledgeEventRecord): string {
  return parseContext(e).query || ''
}

// 溯源:提取事件(created/extracted)
const extractedEvent = computed(() => props.detail?.events.find(e => e.event_type === 'extracted'))
const createdEvent = computed(() => props.detail?.events.find(e => e.event_type === 'created'))

const originMethod = computed(() => {
  if (extractedEvent.value) return t('knowledge.originExtracted')
  if (createdEvent.value) return t('knowledge.originManual')
  return t('knowledge.originUnknown')
})
const originConvTitle = computed(() => {
  if (!extractedEvent.value) return ''
  const ctx = parseContext(extractedEvent.value)
  return ctx.conv_title || ''
})
const originTime = computed(() => {
  const e = extractedEvent.value || createdEvent.value
  return e ? relativeTime(e.timestamp) : ''
})
const reasoningText = computed(() => {
  // 优先取主表 reasoning 字段,降级取 extracted 事件 context
  if (props.detail?.knowledge.reasoning) return props.detail.knowledge.reasoning
  if (extractedEvent.value) return parseContext(extractedEvent.value).reasoning || ''
  return ''
})

// 引用事件(倒序)
const referenceEvents = computed(() =>
  (props.detail?.events ?? []).filter(e => e.event_type === 'referenced').reverse()
)

// 生命周期时间线节点(正序 + 未来占位)
const timelineNodes = computed(() => {
  const events = props.detail?.events ?? []
  const nodes = events.map(e => {
    const ctx = parseContext(e)
    let icon = '•', label = e.event_type, summary = ''
    if (e.event_type === 'extracted') {
      icon = '🤖'; label = t('knowledge.timeline.extracted')
      summary = ctx.conv_title ? t('knowledge.timeline.summarySource', { title: ctx.conv_title }) : ''
    } else if (e.event_type === 'created') {
      icon = '✍️'; label = t('knowledge.timeline.created')
    } else if (e.event_type === 'status_changed') {
      const to = ctx.to
      if (to === 'published') { icon = '✅'; label = t('knowledge.timeline.published') }
      else if (to === 'archived') { icon = '🗄️'; label = t('knowledge.timeline.archived') }
      else if (to === 'pending_review') { icon = '👀'; label = t('knowledge.timeline.enterReview') }
      else { icon = '🔄'; label = t('knowledge.timeline.statusChanged', { to }) }
    } else if (e.event_type === 'referenced') {
      icon = '🔄'; label = t('knowledge.timeline.referenced')
      summary = ctx.conv_title ? t('knowledge.timeline.summaryConv', { title: ctx.conv_title }) : ''
    }
    return { id: e.id, icon, label, summary, timestamp: e.timestamp }
  })
  return nodes
})

// ===== 标签/时间辅助(kind*/status/confidence label 由 @/stores/knowledge 共用,相对时间本组件自留 30 天截止)=====
// 相对时间:复用 common.* 既有 key(justNow/minutesAgo/hoursAgo/dayAgo),30 天以上回退绝对值
function relativeTime(millisStr: string): string {
  const ms = Number(millisStr)
  if (!ms) return ''
  const diff = Date.now() - ms
  const min = Math.floor(diff / 60000)
  if (min < 1) return t('common.justNow')
  if (min < 60) return t('common.minutesAgo', { n: min })
  const hr = Math.floor(min / 60)
  if (hr < 24) return t('common.hoursAgo', { n: hr })
  const day = Math.floor(hr / 24)
  if (day < 30) return t('common.dayAgo', { n: day })
  return t('common.ago', { time: new Date(ms).toLocaleDateString() })
}

// 切换知识时重置引用列表「加载更多」上限 + 折叠态(对齐原 Knowledge.vue selectKnowledge 内 refLimit=10 行为)
watch(() => props.detail.knowledge.id, () => {
  refLimit.value = 10
  sectionOpen.value = { trace: true, refs: true, lifecycle: false }
  contentExpanded.value = false
  reasoningExpanded.value = false
  measureOverflow()
})

// 内容渲染完成后(异步 v-html)重测高度:renderedContent 变化时
watch(renderedContent, () => {
  measureOverflow()
})
</script>

<style scoped>
/* 详情面板四段(SW-260618-20 从 Knowledge.vue 迁移,样式与原一致) */
.detail-section { padding-bottom: 18px; margin-bottom: 18px; border-bottom: 0.5px solid var(--df-border); }
.detail-section:last-child { border-bottom: none; margin-bottom: 0; }

.detail-head { display: flex; justify-content: space-between; align-items: flex-start; gap: 12px; margin-bottom: 12px; min-width: 0; }
.detail-title-row { display: flex; align-items: center; gap: 8px; min-width: 0; flex: 1; overflow: hidden; }
.detail-kind-icon { font-size: 20px; flex-shrink: 0; }
.detail-title { font-size: 18px; font-weight: 500; color: var(--df-text); word-break: break-word; overflow-wrap: break-word; min-width: 0; }
.detail-actions { display: flex; gap: 6px; flex-shrink: 0; flex-wrap: wrap; }

.detail-badges { display: flex; gap: 8px; flex-wrap: wrap; margin-bottom: 14px; font-size: 11px; }
.badge-plain { color: var(--df-text-dim); }
.detail-field { margin-bottom: 12px; }
.detail-field label { display: block; font-size: 12px; color: var(--df-text-secondary); margin-bottom: 4px; }
.detail-content { font-size: 13px; color: var(--df-text); line-height: 1.6; white-space: pre-wrap; }

/* ===== 知识内容 Markdown 渲染(B-260615-25,基础样式收敛至全局 ai-md.css)===== */
.detail-content.ai-md { white-space: normal; }
.detail-tags { display: flex; gap: 6px; flex-wrap: wrap; }
.tag { font-size: 11px; padding: 2px 8px; border-radius: var(--df-radius-xs); background: rgba(108,99,255,0.1); color: var(--df-accent); }
.muted { color: var(--df-text-dim); font-size: 12px; }

/* 状态徽章 / 置信度 */
.kn-card-status { font-size: 11px; font-weight: 500; padding: 2px 8px; border-radius: var(--df-radius-xs); white-space: nowrap; }
.st-candidate { background: rgba(255,217,61,0.15); color: var(--df-warning); }
.st-pending_review { background: rgba(108,159,255,0.15); color: var(--df-info); }
.st-published { background: rgba(100,255,218,0.15); color: var(--df-success); }
.st-archived { background: rgba(90,99,128,0.2); color: var(--df-text-dim); }
.conf-high { background: rgba(100,255,218,0.15); color: var(--df-success); padding: 1px 6px; border-radius: var(--df-radius-xs); }
.conf-medium { background: rgba(255,217,61,0.15); color: var(--df-warning); padding: 1px 6px; border-radius: var(--df-radius-xs); }
.conf-low { background: rgba(255,107,107,0.15); color: var(--df-danger); padding: 1px 6px; border-radius: var(--df-radius-xs); }

/* 溯源 */
.section-title { font-size: 13px; font-weight: 500; color: var(--df-text); margin-bottom: 10px; }
.section-title-toggle {
  display: flex; align-items: center; justify-content: space-between;
  cursor: pointer; user-select: none; padding: 2px 0;
}
.section-title-toggle:hover { color: var(--df-accent); }
.section-chevron { font-size: 11px; color: var(--df-text-dim); }
.section-body { /* 折叠体容器,无额外样式 */ }
.trace-row { display: flex; gap: 12px; font-size: 12px; margin-bottom: 6px; }
.trace-label { color: var(--df-text-dim); min-width: 72px; }
.reasoning-box {
  font-size: 13px; color: var(--df-text-secondary); line-height: 1.6;
  background: var(--df-bg-card); border: 0.5px solid var(--df-border);
  border-radius: var(--df-radius); padding: 10px 12px; white-space: pre-wrap;
}
/* P1 reasoning 折叠:超过阈值收起为限定高度,渐隐边缘提示可展开 */
.reasoning-collapsed {
  max-height: 120px; overflow: hidden; position: relative;
}
.reasoning-collapsed::after {
  content: ''; position: absolute; left: 0; right: 0; bottom: 0; height: 24px;
  background: linear-gradient(to bottom, transparent, var(--df-bg-card));
  pointer-events: none;
}
/* P1 内容折叠:超过 300px 收起 */
.detail-content.content-collapsed {
  max-height: 300px; overflow: hidden; position: relative;
}
.detail-content.content-collapsed::after {
  content: ''; position: absolute; left: 0; right: 0; bottom: 0; height: 28px;
  background: linear-gradient(to bottom, transparent, var(--df-bg-panel, var(--df-bg-card)));
  pointer-events: none;
}
.detail-content { position: relative; }
.fold-toggle { margin-top: 6px; font-size: 11px; }

/* 引用 */
.ref-list { display: flex; flex-direction: column; gap: 8px; }
.ref-item {
  display: flex; gap: 10px; align-items: center; font-size: 12px;
  padding: 6px 10px; background: var(--df-bg-card); border-radius: var(--df-radius-sm);
}
.ref-time { color: var(--df-text-dim); white-space: nowrap; }
.ref-conv { color: var(--df-text); }
.ref-query { color: var(--df-text-secondary); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.load-more { align-self: flex-start; margin-top: 4px; }

/* 生命周期时间线 */
.timeline { display: flex; flex-direction: column; }
.tl-node { display: flex; gap: 12px; position: relative; padding-bottom: 4px; }
.tl-dot {
  width: 28px; height: 28px; border-radius: 50%; flex-shrink: 0;
  display: flex; align-items: center; justify-content: center; font-size: 13px;
  background: var(--df-bg-card); border: 0.5px solid var(--df-border); z-index: 1;
}
.tl-line { position: absolute; left: 14px; top: 28px; bottom: -4px; width: 0.5px; background: var(--df-border); }
.tl-body { padding-top: 4px; }
.tl-label { font-size: 13px; color: var(--df-text); }
.tl-time { font-size: 11px; color: var(--df-text-dim); }
.tl-summary { font-size: 11px; color: var(--df-text-secondary); margin-top: 2px; }

/* ===== 编辑输入 ===== */
.edit-input {
  width: 100%; padding: 8px 10px; background: var(--df-bg-card);
  border: 0.5px solid var(--df-border); border-radius: var(--df-radius-sm);
  color: var(--df-text); font-size: 13px; outline: none; box-sizing: border-box;
}
.edit-input:focus { border-color: var(--df-accent); }
.edit-input-title { font-size: 16px; font-weight: 500; }
.edit-textarea { min-height: 100px; resize: vertical; font-family: inherit; }

/* 按钮基础样式 (.btn / .btn-sm / .btn-primary / .btn-ghost) 已收敛至 global.css */

/* ===== 响应式:窄屏详情标题防竖线化(B-260619)===== */
@media (max-width: 760px) {
  .detail-head { flex-direction: column; align-items: flex-start; }
  .detail-actions { width: 100%; }
  .detail-title { font-size: 15px; }
}
</style>
