<template>
  <div v-if="store.record" class="research-detail-page">
    <section class="detail-header">
      <div class="detail-header__top">
        <div class="detail-header__main">
          <h2 class="detail-header__title">{{ store.record.title }}</h2>
          <div class="detail-header__bar">
            <div class="detail-header__meta">
              <div class="detail-meta-item">
                <span class="detail-meta-item__label">状态</span>
                <strong class="detail-meta-item__value">{{ statusLabel }}</strong>
              </div>
              <a-dropdown v-if="versions.length > 1" :trigger="['click']">
                <a-tag
                  color="blue"
                  style="cursor: pointer; font-size: 13px; padding: 2px 10px"
                >
                  v{{ store.record.versionNo }}
                  <DownOutlined style="font-size: 10px; margin-left: 4px" />
                </a-tag>
                <template #overlay>
                  <a-menu @click="handleVersionClick">
                    <a-menu-item
                      v-for="v in versions"
                      :key="v.id"
                      :disabled="v.id === store.record?.id"
                    >
                      <div style="display: flex; align-items: center; gap: 6px">
                        <span>v{{ v.versionNo }}</span>
                        <a-tag :color="versionStatusColor(v.status)" :bordered="false" size="small">
                          {{ v.status }}
                        </a-tag>
                        <span style="color: rgba(0,0,0,0.45); font-size: 12px; flex: 1">
                          {{ v.createdAt }}
                        </span>
                        <a-button
                          v-if="v.id !== store.record?.id && v.status === 'completed'"
                          size="small"
                          type="link"
                          @click.stop="router.push(`/research/${store.record?.id}/compare/${v.id}`)"
                        >
                          对比
                        </a-button>
                      </div>
                    </a-menu-item>
                  </a-menu>
                </template>
              </a-dropdown>
              <a-tag v-else-if="store.record.versionNo > 1" color="blue">v{{ store.record.versionNo }}</a-tag>
              <div class="detail-meta-item detail-meta-item--time">
                <span class="detail-meta-item__label">最近更新时间</span>
                <strong class="detail-meta-item__value">{{ formatAbsoluteTime(store.record.updatedAt) }}</strong>
                <span class="detail-meta-item__hint">{{ formatRelativeTime(store.record.updatedAt) }}</span>
              </div>
            </div>

            <div class="detail-header__actions">
              <a-space>
                <a-button @click="handleRegenerate">重新研究</a-button>
                <template v-if="store.record.status === 'completed'">
                  <a-dropdown :trigger="['click']">
                    <a-button :loading="docRegenerating">
                      <FileTextOutlined /> 重新生成文档 <DownOutlined />
                    </a-button>
                    <template #overlay>
                      <a-menu @click="handleRegenDocMenuClick">
                        <a-menu-item v-for="opt in templateOptions" :key="opt.value">
                          <div>{{ opt.label }}</div>
                          <div style="font-size: 11px; color: rgba(0,0,0,0.45)">{{ opt.description }}</div>
                        </a-menu-item>
                      </a-menu>
                    </template>
                  </a-dropdown>
                  <a-button @click="exportReport">导出 Markdown</a-button>
                  <a-button @click="exportWordReport">导出 Word</a-button>
                  <a-button v-if="store.report.finalDocumentMd" type="primary" @click="showDocumentReader = true">
                    <ReadOutlined /> 阅读报告
                  </a-button>
                </template>
              </a-space>
            </div>
          </div>
        </div>
      </div>
    </section>

    <a-alert
      v-if="store.record.lastError"
      class="detail-alert"
      type="error"
      :message="store.record.lastError"
      show-icon
      closable
    />

    <a-alert
      v-if="store.isRunning"
      class="detail-alert"
      type="info"
      message="研究正在执行中，时间线和报告区会持续更新。"
      description="你可以留在当前页面跟踪进度，也可以稍后回来继续查看。"
      show-icon
    />

    <div class="detail-layout">
      <main class="detail-main">
        <!-- Clarification history -->
        <div v-if="parsedClarifyMessages.length > 0" class="detail-section">
          <a-collapse v-model:activeKey="clarifyCollapseKey" :bordered="false" class="detail-card clarify-collapse">
            <a-collapse-panel key="clarify" header="需求澄清">
              <div class="clarify-messages">
                <div
                  v-for="(msg, idx) in parsedClarifyMessages"
                  :key="idx"
                  class="clarify-msg"
                  :class="msg.role === 'user' ? 'clarify-msg--user' : 'clarify-msg--assistant'"
                >
                  <div class="clarify-msg__bubble" :class="{ 'clarify-msg__bubble--file': msg.fileAttachment }">
                    <template v-if="msg.fileAttachment">
                      <div class="clarify-msg__file">
                        <PaperClipOutlined class="clarify-msg__file-icon" />
                        <span class="clarify-msg__file-name">{{ msg.fileAttachment.fileName }}</span>
                        <span class="clarify-msg__file-meta">{{ formatCharCount(msg.fileAttachment.charCount) }}</span>
                      </div>
                    </template>
                    <template v-else-if="msg.role === 'assistant' && msg.questions">
                      <div class="clarify-msg__questions">
                        <div v-for="(q, qi) in msg.questions" :key="qi" style="margin-bottom: 6px">
                          {{ qi + 1 }}. {{ q }}
                        </div>
                      </div>
                    </template>
                    <template v-else>
                      <div>{{ msg.content }}</div>
                    </template>
                    <div v-if="msg.note" style="color: rgba(0,0,0,0.45); font-size: 12px; margin-top: 6px">{{ msg.note }}</div>
                  </div>
                </div>
              </div>
            </a-collapse-panel>
          </a-collapse>
        </div>

        <div v-if="store.record.plan" class="detail-section">
          <a-collapse v-model:activeKey="planCollapseKey" :bordered="false" class="detail-card clarify-collapse">
            <a-collapse-panel key="plan">
              <template #header>
                <span>研究计划确认</span>
              </template>
              <template v-if="store.record.status === 'planned'" #extra>
                <a-space @click.stop>
                  <a-button size="small" :disabled="store.isRunning" @click="startRun">
                    <PlayCircleOutlined /> 确认并开始研究
                  </a-button>
                </a-space>
              </template>
              <PlanViewer
                :plan="store.record.plan"
                :record-id="store.recordId ?? undefined"
                hide-title
                @plan-saved="(p) => { if (store.record) store.record.plan = p }"
              />
            </a-collapse-panel>
          </a-collapse>
        </div>

        <div v-if="reportHasContent" class="detail-section">
          <ReportViewer
            :report="store.report"
            :report-has-content="reportHasContent"
            :is-running="store.isRunning"
            :can-rerun-section="store.record.status === 'completed' && !store.isRunning"
            :has-guide-evidence="hasGuideEvidence"
            :references="store.references"
            @rerun-section="handleRerunSection"
            @continue-from-section="handleContinueFromSection"
            @preview-reference="openReferencePreview"
            @preview-reference-by-index="handleReferenceClickByIndex"
          />
        </div>

        <div v-if="hasRiskContent" class="detail-section">
          <a-card class="detail-card" :bordered="false" title="冲突、缺口与待确认项">
            <div v-if="store.report.conflicts.length" class="risk-block">
              <div class="risk-block__title">冲突与证据缺口</div>
              <a-card
                v-for="conflict in store.report.conflicts"
                :key="`${conflict.title}-${conflict.content}`"
                size="small"
                class="risk-item"
              >
                <template #title>
                  <div class="risk-item__head">
                    <span>{{ conflict.title }}</span>
                    <a-tag :color="severityColor(conflict.severity)">{{ severityLabel(conflict.severity) }}</a-tag>
                  </div>
                </template>
                <MarkdownRenderer :content="conflict.content" @reference-click="handleReferenceClickByIndex" />
              </a-card>
            </div>

            <div v-if="store.report.openQuestions.length" class="risk-block">
              <div class="risk-block__title">待确认问题</div>
              <a-card
                v-for="question in store.report.openQuestions"
                :key="`${question.question}-${question.reason}`"
                size="small"
                class="risk-item"
              >
                <div class="question-item__title">{{ question.question }}</div>
                <div class="question-item__reason">{{ question.reason }}</div>
              </a-card>
            </div>
          </a-card>
        </div>

        <div v-if="store.progress.length > 0" class="detail-section">
          <ResearchTimeline
            :progress="store.progress"
            :report="store.report"
            :notes="store.record.notes || ''"
            :references="store.references"
            @preview-reference="openReferencePreview"
            @preview-reference-by-index="handleReferenceClickByIndex"
          />
        </div>

        <!-- F2: Post-research chat -->
        <div v-if="store.record.status === 'completed'" class="detail-section">
          <a-card class="detail-card" :bordered="false" title="继续对话">
            <div class="chat-messages">
              <div
                v-for="(msg, idx) in chatMessages"
                :key="idx"
                class="chat-msg"
                :class="msg.role === 'user' ? 'chat-msg--user' : 'chat-msg--assistant'"
              >
                <div class="chat-msg__bubble">
                  <MarkdownRenderer v-if="msg.role === 'assistant'" :content="msg.content" />
                  <span v-else>{{ msg.content }}</span>
                </div>
              </div>
              <div v-if="chatStreaming" class="chat-msg chat-msg--assistant">
                <div class="chat-msg__bubble">
                  <MarkdownRenderer :content="chatStreamContent" />
                  <span class="chat-typing">...</span>
                </div>
              </div>
            </div>
            <div v-if="suggestRegenerate" style="margin: 12px 0">
              <a-alert type="info" show-icon :message="suggestRegenerate">
                <template #action>
                  <a-button size="small" type="primary" @click="handleRegenerate">重新研究</a-button>
                </template>
              </a-alert>
            </div>
            <!-- Chat uploaded files -->
            <div v-if="chatUploadedFiles.length > 0" class="chat-uploads">
              <a-tag
                v-for="uf in chatUploadedFiles"
                :key="uf.fileId"
                :color="uf.status === 'error' ? 'error' : uf.status === 'uploading' ? 'processing' : 'success'"
              >
                <template #icon>
                  <LoadingOutlined v-if="uf.status === 'uploading'" />
                  <PaperClipOutlined v-else />
                </template>
                {{ uf.fileName }}
                <span v-if="uf.status === 'done'" style="color: rgba(0,0,0,0.35); margin-left: 4px">{{ formatCharCount(uf.charCount) }}</span>
              </a-tag>
            </div>
            <div class="chat-input-wrap" style="margin-top: 12px">
              <a-upload
                :show-upload-list="false"
                :before-upload="handleChatFileUpload"
                :multiple="true"
                accept=".pdf,.doc,.docx,.xls,.xlsx,.ppt,.pptx,.png,.jpg,.jpeg,.tiff,.bmp,.txt,.md"
              >
                <a-button size="small" :disabled="chatStreaming || docRegenerating" class="chat-upload-btn" title="上传文件">
                  <template #icon><PaperClipOutlined /></template>
                </a-button>
              </a-upload>
              <a-textarea
                v-model:value="chatInput"
                placeholder="就研究结果提问...（Shift+Enter 换行）"
                :disabled="chatStreaming"
                :auto-size="{ minRows: 1, maxRows: 6 }"
                @keydown="handleChatKeydown"
                style="flex: 1"
              />
              <a-button type="primary" :loading="chatStreaming" @click="sendChatMessage">发送</a-button>
            </div>
          </a-card>
        </div>
      </main>

      <aside class="detail-sidebar">
        <section class="sidebar-panel sidebar-panel--sticky">
          <EvidencePanel
            :references="store.references"
            :imported-items="store.record.importedItems || []"
            :has-basket-items="false"
            :busy="store.isRunning"
            :active-tab="evidenceTab"
            @update:active-tab="(v: string) => evidenceTab = v"
            @open-reference="handleOpenReference"
            @open-document="handleOpenDocument"
            @open-matter="handleOpenMatter"
            @download-file="handleDownloadFile"
            @remove-imported="() => {}"
            @clear-imported="() => {}"
            @import-basket="() => {}"
          />
        </section>
      </aside>
    </div>

    <DocumentQuickPreview
      v-model:open="previewOpen"
      title="引用快速预览"
      :doc-id="previewReference?.doc_id"
      :matched-chunks="previewMatchedChunks"
      :highlights="previewHighlights"
      :fallback-text="previewFallbackText"
      :show-import="false"
      @open-detail="openPreviewDetail"
    />

    <!-- Full-screen document reader -->
    <ReportDocumentReader
      :open="showDocumentReader"
      :content="store.report.finalDocumentMd"
      :title="store.record.title"
      @close="showDocumentReader = false"
    />
  </div>

  <div v-else class="detail-loading">
    <a-spin size="large" />
  </div>
</template>

<script setup lang="ts">
import { ref, computed, onMounted } from 'vue'
import { useRoute, useRouter } from 'vue-router'
import { message } from 'ant-design-vue'
import { DownOutlined, PaperClipOutlined, PlayCircleOutlined, ReadOutlined, LoadingOutlined, FileTextOutlined } from '@ant-design/icons-vue'
import ReportDocumentReader from '@/views/research/ReportDocumentReader.vue'
import PlanViewer from '@/views/research/PlanViewer.vue'
import ReportViewer from '@/views/research/ReportViewer.vue'
import ResearchTimeline from '@/views/research/ResearchTimeline.vue'
import EvidencePanel from '@/views/research/EvidencePanel.vue'
import MarkdownRenderer from '@/components/MarkdownRenderer.vue'
import { RESEARCH_TEMPLATE_OPTIONS } from '@/types/research'
import DocumentQuickPreview from '@/components/DocumentQuickPreview.vue'
import { useSSE } from '@/composables/useSSE'
import { useResearchRecordWorkbenchStore } from '@/stores/researchRecordWorkbench'
import {
  startRecordRun,
  startRecordSectionRerun,
  buildRunEventsUrl,
  fetchVersions,
} from '@/api/researchRecords'
import { buildExportMarkdown, buildWordReportHtml, triggerBlobDownload, sanitizeFileName } from '@/utils/researchExport'
import { createMarkdownIt } from '@/utils/markdown'
import { getReferenceTargetPath } from '@/utils/referenceRouting'
import type { ResearchSectionResult } from '@/types/research'
import type { ResearchReference } from '@/types/document'

const route = useRoute()
const router = useRouter()
const store = useResearchRecordWorkbenchStore()
const { connect } = useSSE()

const evidenceTab = ref('evidence')
const previewOpen = ref(false)
const previewReference = ref<ResearchReference | null>(null)

const previewMatchedChunks = computed(() => previewReference.value?.matched_chunks ?? [])

// Version chain (F4)
import type { ResearchRecordSummary } from '@/types/research'
const versions = ref<ResearchRecordSummary[]>([])

async function loadVersions() {
  if (!store.record) return
  try {
    versions.value = await fetchVersions(store.record.id)
  } catch { versions.value = [] }
}

function handleVersionClick({ key }: { key: string }) {
  if (key !== store.record?.id) {
    router.push(`/research/${key}`)
  }
}

function versionStatusColor(status: string) {
  const map: Record<string, string> = {
    draft: 'default', planned: 'blue', running: 'orange',
    completed: 'green', failed: 'red',
  }
  return map[status] || 'default'
}

function handleRegenerate() {
  if (store.record) {
    router.push(`/research/new?from=${store.record.id}`)
  }
}

// Clarification history (read-only on detail page)
interface ClarifyMessage {
  role: 'user' | 'assistant'
  content: string
  questions?: string[]
  note?: string
  fileAttachment?: { fileId: string; fileName: string; fileType: string; charCount: number }
}
const clarifyCollapseKey = ref<string[]>([])
const showDocumentReader = ref(false)
const planCollapseKey = ref<string[]>([])

function formatCharCount(n: number): string {
  if (n >= 10000) return `${(n / 10000).toFixed(1)}万字`
  if (n >= 1000) return `${(n / 1000).toFixed(1)}k字`
  return `${n}字`
}

const parsedClarifyMessages = computed<ClarifyMessage[]>(() => {
  const raw = store.record?.clarificationMessages
  if (!raw || !Array.isArray(raw)) return []
  return raw.map((m: any) => {
    // File attachment message (written by upload-material endpoint)
    if (m.role === 'user' && m.attachment_type === 'file') {
      return {
        role: 'user' as const,
        content: '',
        fileAttachment: {
          fileId: String(m.file_id || ''),
          fileName: String(m.file_name || '未知文件'),
          fileType: String(m.file_type || ''),
          charCount: Number(m.char_count || 0),
        },
      }
    }
    if (m.role === 'user') {
      return { role: 'user' as const, content: String(m.content || '') }
    }
    // Assistant messages: content is JSON string with {questions, note, ...}
    try {
      const parsed = typeof m.content === 'string' ? JSON.parse(m.content) : m.content
      const questions = parsed.questions as string[] | undefined
      return {
        role: 'assistant' as const,
        content: parsed.ready ? '任务信息充分，可以生成研究计划。' : '',
        questions: questions?.length ? questions : undefined,
        note: parsed.note as string | undefined,
      }
    } catch {
      return { role: 'assistant' as const, content: String(m.content || '') }
    }
  })
})

// F2: Post-research chat state
interface ChatMsg { role: 'user' | 'assistant'; content: string }
const chatMessages = ref<ChatMsg[]>([])
const chatInput = ref('')
const chatStreaming = ref(false)
const chatStreamContent = ref('')
const suggestRegenerate = ref('')
const docRegenerating = ref(false)

// Chat file upload state
interface ChatUploadedFile {
  fileId: string
  fileName: string
  charCount: number
  status: 'uploading' | 'done' | 'error'
}
const chatUploadedFiles = ref<ChatUploadedFile[]>([])

function handleChatKeydown(e: KeyboardEvent) {
  if (e.key === 'Enter' && !e.shiftKey) {
    e.preventDefault()
    sendChatMessage()
  }
}

function handleChatFileUpload(file: File) {
  const MAX_SIZE = 20 * 1024 * 1024
  if (file.size > MAX_SIZE) {
    message.error(`文件 ${file.name} 超过 20MB 限制`)
    return false
  }
  if (!store.recordId) return false
  doChatFileUpload(file)
  return false
}

async function doChatFileUpload(file: File) {
  const tempId = `tmp_chat_${Date.now()}`
  chatUploadedFiles.value.push({ fileId: tempId, fileName: file.name, charCount: 0, status: 'uploading' })
  const getIdx = () => chatUploadedFiles.value.findIndex((m) => m.fileId === tempId)

  try {
    const { uploadMaterial } = await import('@/api/researchRecords')
    const result = await uploadMaterial(store.recordId!, file)
    const idx = getIdx()
    if (idx !== -1) {
      chatUploadedFiles.value[idx] = {
        fileId: result.fileId,
        fileName: result.originalFilename,
        charCount: result.charCount,
        status: 'done',
      }
    }
    message.success(`已提取 ${file.name}（${formatCharCount(result.charCount)}）`)
  } catch (err: any) {
    const idx = getIdx()
    if (idx !== -1) {
      chatUploadedFiles.value[idx] = { ...chatUploadedFiles.value[idx], status: 'error' }
    }
    message.error(`文件 ${file.name} 处理失败`)
  }
}

const templateOptions = RESEARCH_TEMPLATE_OPTIONS

function handleRegenDocMenuClick(info: { key: string }) {
  regenerateDocument(info.key)
}

async function regenerateDocument(outputTemplate?: string) {
  if (!store.recordId || docRegenerating.value) return
  docRegenerating.value = true
  try {
    const url = `/api/ai/v1/research/records/${store.recordId}/regenerate-document`
    const response = await fetch(url, {
      method: 'POST',
      headers: {
        'Content-Type': 'application/json',
        'Authorization': `Bearer ${localStorage.getItem('token') || ''}`,
      },
      body: JSON.stringify({ output_template: outputTemplate || undefined }),
    })
    if (!response.ok) throw new Error('Regenerate request failed')
    const reader = response.body?.getReader()
    if (!reader) return
    const decoder = new TextDecoder()
    let buffer = ''

    while (true) {
      const { done, value } = await reader.read()
      if (done) break
      buffer += decoder.decode(value, { stream: true })
      const lines = buffer.split('\n')
      buffer = lines.pop() || ''
      for (const line of lines) {
        if (!line.startsWith('data: ')) continue
        try {
          const chunk = JSON.parse(line.slice(6))
          if (chunk.type === 'final_document') {
            store.report.finalDocumentMd = chunk.content || ''
          }
        } catch { /* ignore */ }
      }
    }
    message.success('交付物文档已重新生成')
  } catch {
    message.error('文档重新生成失败')
  } finally {
    docRegenerating.value = false
  }
}

async function sendChatMessage() {
  const text = chatInput.value.trim()
  if (!text || !store.record || chatStreaming.value) return
  chatMessages.value.push({ role: 'user', content: text })
  chatInput.value = ''
  chatStreaming.value = true
  chatStreamContent.value = ''
  suggestRegenerate.value = ''

  try {
    const { buildChatUrl } = await import('@/api/researchRecords')
    const url = buildChatUrl(store.record.id)
    const response = await fetch(url, {
      method: 'POST',
      headers: {
        'Content-Type': 'application/json',
        'Authorization': `Bearer ${localStorage.getItem('token') || ''}`,
      },
      body: JSON.stringify({ message: text }),
    })
    if (!response.ok) throw new Error('Chat request failed')
    const reader = response.body?.getReader()
    if (!reader) return
    const decoder = new TextDecoder()
    let buffer = ''
    let fullContent = ''

    while (true) {
      const { done, value } = await reader.read()
      if (done) break
      buffer += decoder.decode(value, { stream: true })
      const lines = buffer.split('\n')
      buffer = lines.pop() || ''
      for (const line of lines) {
        if (!line.startsWith('data: ')) continue
        try {
          const chunk = JSON.parse(line.slice(6))
          if (chunk.type === 'chat_content') {
            fullContent += chunk.content
            chatStreamContent.value = fullContent
          } else if (chunk.type === 'suggest_regenerate') {
            suggestRegenerate.value = chunk.content
          }
        } catch { /* ignore */ }
      }
    }
    chatMessages.value.push({ role: 'assistant', content: fullContent })
  } catch {
    chatMessages.value.push({ role: 'assistant', content: '对话请求失败，请重试。' })
  } finally {
    chatStreaming.value = false
    chatStreamContent.value = ''
  }
}

const previewHighlights = computed(() => {
  if (!previewReference.value) return []
  if (previewReference.value.summary) return [previewReference.value.summary]
  if (previewReference.value.matched_field_labels?.length) {
    return [`命中字段：${previewReference.value.matched_field_labels.join('、')}`]
  }
  return []
})

const previewFallbackText = computed(() => {
  if (!previewReference.value) return ''
  if (previewReference.value.summary?.trim()) return previewReference.value.summary.trim()
  if (previewReference.value.matched_field_labels?.length) {
    return `命中字段：${previewReference.value.matched_field_labels.join('、')}`
  }
  return ''
})

const reportHasContent = computed(() => {
  const r = store.report
  return !!(
    r.executiveSummary ||
    r.findings.length ||
    r.sections.length ||
    r.onePageSummary
  )
})

const hasRiskContent = computed(() => {
  return store.report.conflicts.length > 0 || store.report.openQuestions.length > 0
})

// P0-1: Guide evidence detection for ReportViewer
const hasGuideEvidence = computed(() => {
  return store.references.some((r) => r.source_group === 'guide')
})

function severityLabel(severity: string): string {
  if (severity === 'high') return '高风险'
  if (severity === 'low') return '低风险'
  return '中风险'
}

function severityColor(severity: string): string {
  if (severity === 'high') return 'red'
  if (severity === 'low') return 'blue'
  return 'gold'
}

const statusLabel = computed(() => {
  const map: Record<string, string> = {
    draft: '草稿', planned: '已规划', running: '研究中',
    completed: '已完成', failed: '失败',
  }
  return map[store.record?.status || ''] || store.record?.status || ''
})

// ------------------------------------------------------------------
// SSE subscription
// ------------------------------------------------------------------

async function subscribeRun(runId: string) {
  await connect({
    url: buildRunEventsUrl(store.recordId!, runId),
    body: {},
    onMessage: (data) => store.handleSSEEvent(data as Record<string, unknown>),
    onDone: async () => {
      // C14: this only fires on natural stream end, not AbortError
      store.isRunning = false
      await store.loadRecord(store.recordId!)
      if (store.record?.status === 'completed') {
        await store.loadReport(store.recordId!)
      }
    },
    onError: () => {
      store.isRunning = false
    },
  })
}

async function startRun() {
  store.isRunning = true
  try {
    const { runId } = await startRecordRun(store.recordId!)
    // Clear autoRun immediately to prevent re-trigger on refresh
    router.replace({ query: {} })
    await subscribeRun(runId)
  } catch {
    store.isRunning = false
  }
}

// C18: resume existing run (refresh scenario)
async function resumeRun(runId: string, runType: string) {
  store.isRunning = true
  store.resetStreamState(runType === 'full')
  await subscribeRun(runId)
}

async function handleRerunSection(section: ResearchSectionResult) {
  store.isRunning = true
  try {
    const { runId } = await startRecordSectionRerun(store.recordId!, {
      section_title: section.title,
      section_summary: section.summary || undefined,
      source_doc_ids: section.sourceDocIds?.length ? section.sourceDocIds : undefined,
    })
    // C18: section rerun — don't clear report
    store.resetStreamState(false)
    await subscribeRun(runId)
  } catch {
    store.isRunning = false
  }
}

// ------------------------------------------------------------------
// P0-3: Continue from section — navigate to new research prefilled
// ------------------------------------------------------------------

function handleContinueFromSection(section: ResearchSectionResult) {
  // Store section context for the new research page to pick up
  const prefill = {
    topic: section.title,
    question: `对"${section.title}"进行更深入的研究分析`,
    sourceDocIds: section.sourceDocIds || [],
  }
  sessionStorage.setItem('research-continue-from-section', JSON.stringify(prefill))
  router.push('/research/new')
}

// ------------------------------------------------------------------
// P0-2: Evidence panel event handlers
// ------------------------------------------------------------------

function handleOpenReference(reference: ResearchReference) {
  router.push(getReferenceTargetPath(reference))
}

function openReferencePreview(reference: ResearchReference) {
  previewReference.value = reference
  previewOpen.value = true
}

function handleReferenceClickByIndex(index: number) {
  // Try citation_map first (passage-level precision from new records)
  const citation = store.citationMap[index - 1] as Record<string, unknown> | undefined
  if (citation?.doc_id) {
    const chunk: Record<string, unknown> = {
      text: citation.text as string || '',
      page_number: citation.page_number as number | undefined,
      page_numbers: (citation.page_numbers as number[]) || [],
      heading_hierarchy: (citation.heading_hierarchy as string[]) || [],
      element_type: (citation.element_type as string) || '',
      chunk_index: citation.chunk_index as number | undefined,
    }
    const syntheticRef: ResearchReference = {
      doc_id: citation.doc_id as string,
      title: (citation.title as string) || '',
      doc_number: (citation.doc_number as string) || '',
      matched_chunks: [chunk as any],
    }
    openReferencePreview(syntheticRef)
    return
  }

  // Fallback for old records: [N] was passage-level but no citation_map.
  // Try to find the Nth matched_chunk across all references.
  if (store.citationMap.length === 0 && store.references.length > 0) {
    let remaining = index
    for (const ref of store.references) {
      const chunks = ref.matched_chunks || []
      if (remaining <= chunks.length) {
        // Found the target chunk
        const syntheticRef: ResearchReference = {
          doc_id: ref.doc_id,
          title: ref.title,
          doc_number: ref.doc_number,
          matched_chunks: [chunks[remaining - 1]],
        }
        openReferencePreview(syntheticRef)
        return
      }
      remaining -= chunks.length
    }
    // If index exceeds total chunks, show the first reference as fallback
    openReferencePreview(store.references[0])
    return
  }

  // Final fallback: direct index lookup
  const reference = store.references[index - 1]
  if (!reference) return
  openReferencePreview(reference)
}

function openPreviewDetail() {
  if (!previewReference.value) return
  router.push(getReferenceTargetPath(previewReference.value))
}

function handleOpenDocument(docId: string) {
  router.push(`/doc/${docId}`)
}

function handleOpenMatter(matterId: string) {
  router.push(`/matters/${matterId}`)
}

async function handleDownloadFile(fileId: string, fileName: string) {
  if (!store.recordId) return
  const { downloadUploadedFile } = await import('@/api/researchRecords')
  await downloadUploadedFile(store.recordId, fileId, fileName)
}

function formatAbsoluteTime(timeStr: string) {
  if (!timeStr) return '--'
  try {
    return new Date(timeStr).toLocaleString('zh-CN', {
      year: 'numeric',
      month: '2-digit',
      day: '2-digit',
      hour: '2-digit',
      minute: '2-digit',
    })
  } catch {
    return timeStr
  }
}

function formatRelativeTime(timeStr: string) {
  if (!timeStr) return '--'
  try {
    const diff = Date.now() - new Date(timeStr).getTime()
    const minutes = Math.floor(diff / 60000)
    if (minutes < 1) return '刚刚更新'
    if (minutes < 60) return `${minutes} 分钟前`
    const hours = Math.floor(minutes / 60)
    if (hours < 24) return `${hours} 小时前`
    const days = Math.floor(hours / 24)
    return `${days} 天前`
  } catch {
    return timeStr
  }
}

// ------------------------------------------------------------------
// Export
// ------------------------------------------------------------------

function exportReport() {
  if (!store.record) return
  const md = buildExportMarkdown({
    sessionTitle: store.record.title,
    task: store.record.task as any,
    plan: store.record.plan as any,
    report: store.report,
    references: store.references,
  })
  const blob = new Blob([md], { type: 'text/markdown;charset=utf-8' })
  triggerBlobDownload(blob, sanitizeFileName(store.record.title) + '.md')
}

async function exportWordReport() {
  if (!store.record) return
  try {
    const { asBlob } = await import('html-docx-js-typescript')
    const markdown = createMarkdownIt({ referenceLinks: true })
    const html = buildWordReportHtml({
      sessionTitle: store.record.title,
      task: store.record.task as any,
      plan: store.record.plan as any,
      report: store.report,
      references: store.references,
    }, markdown)
    const blob = await asBlob(html) as Blob
    triggerBlobDownload(blob, sanitizeFileName(store.record.title) + '.docx')
  } catch {
    // Fallback to old .doc format
    const markdown = createMarkdownIt({ referenceLinks: true })
    const html = buildWordReportHtml({
      sessionTitle: store.record.title,
      task: store.record.task as any,
      plan: store.record.plan as any,
      report: store.report,
      references: store.references,
    }, markdown)
    const blob = new Blob([html], { type: 'application/msword;charset=utf-8' })
    triggerBlobDownload(blob, sanitizeFileName(store.record.title) + '.docx')
  }
}

// ------------------------------------------------------------------
// Lifecycle
// ------------------------------------------------------------------

onMounted(async () => {
  const id = route.params.id as string
  store.reset()
  await store.loadRecord(id)

  if (!store.record) return

  // Load version chain (F4)
  loadVersions()

  // Clarification collapse: default expanded unless completed
  if (store.record.status !== 'completed') {
    clarifyCollapseKey.value = ['clarify']
  }

  // Plan collapse: expanded when planned, collapsed after research starts
  if (store.record.status === 'planned') {
    planCollapseKey.value = ['plan']
  }

  // F2: Restore chat history from record detail
  if (store.record.chatMessages && Array.isArray(store.record.chatMessages)) {
    chatMessages.value = store.record.chatMessages.map((m: any) => ({
      role: m.role as 'user' | 'assistant',
      content: String(m.content || ''),
    }))
  }

  const autoRun = route.query.autoRun === 'true'

  if (autoRun && store.record.status === 'planned') {
    // From CreateView: start research
    await startRun()
  } else if (store.record.status === 'running' && store.record.latestRunId) {
    // Refresh recovery: re-subscribe to existing run (C7)
    await resumeRun(store.record.latestRunId, store.record.latestRunType || 'full')
  } else if (store.record.status === 'completed') {
    // Load persisted report
    await store.loadReport(id)
  }

  // Clear autoRun if still present
  if (autoRun) {
    router.replace({ query: {} })
  }
})
</script>

<style scoped lang="less">
.research-detail-page {
  max-width: 1380px;
  margin: 0 auto;
  padding: 28px 24px 40px;
}

.detail-header {
  display: flex;
  flex-direction: column;
}

.detail-header__top {
  display: flex;
  justify-content: space-between;
  gap: 20px;
  align-items: flex-start;
}

.detail-header__main {
  min-width: 0;
}

.detail-header__bar {
  display: flex;
  justify-content: space-between;
  align-items: center;
  gap: 20px;
  margin-top: 14px;
}

.detail-header__title {
  margin: 0;
  font-size: 30px;
  line-height: 1.24;
  font-weight: 700;
  color: #101828;
}

.detail-header__meta {
  display: flex;
  flex-wrap: wrap;
  gap: 24px;
}

.detail-meta-item {
  display: flex;
  align-items: baseline;
  gap: 8px;
  min-width: 0;
}

.detail-meta-item--time {
  flex-wrap: wrap;
}

.detail-meta-item__label {
  font-size: 12px;
  color: #667085;
}

.detail-meta-item__value {
  font-size: 14px;
  font-weight: 700;
  color: #101828;
}

.detail-meta-item__hint {
  font-size: 12px;
  color: #667085;
}

.detail-header__actions {
  display: flex;
  justify-content: flex-end;
  flex-shrink: 0;
}

.detail-alert {
  margin-top: 16px;
  border-radius: 18px;
}

.detail-layout {
  display: grid;
  grid-template-columns: minmax(0, 1fr) 360px;
  gap: 20px;
  margin-top: 20px;
}

.detail-main {
  min-width: 0;
}

.detail-sidebar {
  min-width: 0;
}

.detail-section + .detail-section {
  margin-top: 20px;
}

.detail-card,
.sidebar-panel {
  border-radius: 22px;
  border: 1px solid #e8edf5;
  box-shadow: 0 16px 40px rgba(15, 23, 42, 0.06);
}

.risk-block + .risk-block {
  margin-top: 18px;
}

.risk-block__title {
  margin-bottom: 10px;
  font-size: 13px;
  font-weight: 700;
  color: #15233b;
}

.risk-item {
  border-radius: 16px;
}

.risk-item + .risk-item {
  margin-top: 12px;
}

.risk-item__head {
  display: flex;
  justify-content: space-between;
  gap: 10px;
  align-items: center;
}

.question-item__title {
  font-weight: 700;
  color: #101828;
}

.question-item__reason {
  margin-top: 6px;
  line-height: 1.7;
  color: #475467;
}

.sidebar-panel {
  overflow: hidden;
  background: #ffffff;
}

.sidebar-panel--sticky {
  position: sticky;
  top: 20px;
}

.detail-loading {
  display: flex;
  justify-content: center;
  padding: 100px;
}

@media (max-width: 1120px) {
  .detail-layout {
    grid-template-columns: 1fr;
  }
}

@media (max-width: 720px) {
  .research-detail-page {
    padding: 20px 16px 32px;
  }

  .detail-header__top {
    flex-direction: column;
  }

  .detail-header__bar {
    flex-direction: column;
    align-items: flex-start;
  }

  .detail-header__actions {
    justify-content: flex-start;
  }

  .detail-header__title {
    font-size: 28px;
  }
}

// F2: Chat styles
.chat-messages {
  display: flex;
  flex-direction: column;
  gap: 12px;
  max-height: 400px;
  overflow-y: auto;
  margin-bottom: 8px;
}

.chat-msg {
  display: flex;
  &--user { justify-content: flex-end; }
  &--assistant { justify-content: flex-start; }
}

.chat-msg__bubble {
  max-width: 85%;
  padding: 10px 14px;
  border-radius: 12px;
  font-size: 13px;
  line-height: 1.6;

  .chat-msg--user & {
    background: #e6f4ff;
    color: rgba(0, 0, 0, 0.88);
  }
  .chat-msg--assistant & {
    background: #f5f5f5;
    color: rgba(0, 0, 0, 0.88);
  }
}

.chat-typing {
  color: rgba(0, 0, 0, 0.35);
  animation: blink 1s infinite;
}

@keyframes blink {
  50% { opacity: 0.3; }
}

.chat-input-wrap {
  display: flex;
  gap: 8px;
  align-items: flex-end;
}

.chat-upload-btn {
  flex-shrink: 0;
  height: 32px;
}

.chat-uploads {
  display: flex;
  flex-wrap: wrap;
  gap: 6px;
  margin-top: 8px;
}

// Clarification history styles
.clarify-collapse {
  background: #fff;

  :deep(.ant-collapse-header) {
    font-weight: 600;
    font-size: 15px;
  }
}

.clarify-messages {
  display: flex;
  flex-direction: column;
  gap: 12px;
}

.clarify-msg {
  display: flex;
  &--user { justify-content: flex-end; }
  &--assistant { justify-content: flex-start; }
}

.clarify-msg__bubble {
  max-width: 80%;
  padding: 10px 14px;
  border-radius: 12px;
  font-size: 13px;
  line-height: 1.6;

  .clarify-msg--user & {
    background: #e6f4ff;
    color: rgba(0, 0, 0, 0.88);
  }
  .clarify-msg--assistant & {
    background: #f5f5f5;
    color: rgba(0, 0, 0, 0.88);
  }
}

.clarify-msg__questions {
  font-weight: 500;
}

.clarify-msg__bubble--file {
  background: #f0f7ff !important;
  border: 1px solid #bae0ff;
  padding: 8px 12px;
}

.clarify-msg__file {
  display: flex;
  align-items: center;
  gap: 7px;

  &-icon {
    font-size: 15px;
    color: #1677ff;
    flex-shrink: 0;
  }

  &-name {
    font-size: 13px;
    font-weight: 500;
    color: rgba(0, 0, 0, 0.85);
    word-break: break-all;
  }

  &-meta {
    font-size: 11px;
    color: rgba(0, 0, 0, 0.35);
    flex-shrink: 0;
  }
}
</style>
