/* eslint-disable @next/next/no-img-element */
"use client"

import * as React from "react"
import {
  AlertTriangle, ArrowRight, BadgeCheck, BarChart3, CheckCircle2,
  ChevronLeft, ChevronRight, CircleAlert, Database, Download, ExternalLink,
  FileCheck2, FileJson, FileText, LoaderCircle, MessageSquareCheck,
  Printer, RefreshCw, RotateCcw, SearchCheck, ShieldCheck, SlidersHorizontal,
} from "lucide-react"
import { toast } from "sonner"

import { Badge } from "@/components/ui/badge"
import { Button } from "@/components/ui/button"
import {
  Dialog, DialogContent, DialogDescription, DialogFooter, DialogHeader, DialogTitle,
} from "@/components/ui/dialog"
import { Progress } from "@/components/ui/progress"
import {
  Select, SelectContent, SelectItem, SelectTrigger, SelectValue,
} from "@/components/ui/select"
import {
  Sheet, SheetContent, SheetDescription, SheetHeader, SheetTitle,
} from "@/components/ui/sheet"
import {
  Table, TableBody, TableCell, TableHead, TableHeader, TableRow,
} from "@/components/ui/table"
import { Textarea } from "@/components/ui/textarea"

type MetricSet = {
  answerCount: number
  mentionRate: number | null
  recommendRate: number | null
  top3Rate: number | null
  positiveRate: number | null
  neutralPositiveRate: number | null
  citationRate: number | null
  accuracyRate: number | null
  averageRank: number | null
  visibility: number | null
  health: number | null
}

type AnswerRecord = {
  recordId: string
  promptId: string
  platform: string
  modelVersion: string
  testedAt: string
  recordStatus: string
  keyword: string
  questionType: string
  scene: string
  region: string
  question: string
  answer: string
  conversationUrl: string | null
  evidenceUrl: string | null
  mention: number
  recommendationPrompt: number
  recommend: number
  top3: number
  rank: number | null
  sentiment: string | null
  accuracy: number | null
  factPointsTotal: number
  factPointsCorrect: number
  accuracyNote: string | null
  judgedBy: string | null
  citationDetectable: number
  brandCited: number
  citationUrls: string[]
}

type Coverage = {
  totalCallCount?: number
  validResponseRate?: number
  failedCount?: number
  timeoutCount?: number
  invalidCount?: number
  promptCount?: number
  platformCount?: number
  competitorCount?: number
  competitorScopeCoverage?: number
  competitorRecordCoverage?: number
  competitorEntityMatch?: number
  competitorCountMatch?: number
  unmatchedCompetitorCount?: number
  evidenceCoverage?: number
  rawEvidenceCoverage?: number
  citationClaimCount?: number
  citationEvidenceCount?: number
  citationEvidenceCoverage?: number
  accuracyCoverage?: number
  modelVersionCoverage?: number
  platformEntityMatch?: number
  keywordEntityMatch?: number
  completionReady?: number
  deliveryItemCount?: number
  deliveryWeightTotal?: number
  deliveryCompletion?: number
  protocolCoverage?: number
}

type ReportData = {
  project: {
    slug: string
    projectCode: string
    projectType: "client" | "reference"
    projectName: string
    brandName: string
    clientName: string
    coreKeyword: string
    derivativeKeywords: string[]
    platforms: string[]
    optimizationRegion: string
    serviceScope: string
    acceptanceRules: Record<string, number>
    measurementProtocol: {
      metricStandardVersion?: string
      calculationEngineVersion?: string
      brandAliases?: string[]
      promptPoolVersion?: string
      detectionCount?: number
      competitorSet?: string[]
      modelScope?: string
      judgmentRulesVersion?: string
    }
    configVersion: number
    configFingerprint: string
    frozenAt: string | null
    startDate: string | null
    endDate: string | null
    baselineMonth: string | null
    currentMonth: string | null
    logoKey: string | null
  }
  access: { allowed: boolean; internal: boolean; memberRole: string }
  snapshot: null | {
    id: string
    reportMonth: string
    version: number
    qualityScore: number
    answerCount: number
    deliveryCount: number
    evidenceCount: number
    acceptanceStatus: string
    acceptedAt: string | null
    publishedAt: string | null
    summary: { coverage?: Coverage; validation?: Record<string, number> }
    scope: Record<string, unknown>
    gate: { passed?: boolean; checks?: Array<{ key: string; label: string; passed: boolean }> }
  }
  snapshots: Array<{ id: string; reportMonth: string; version: number; qualityScore: number; answerCount: number; deliveryCount: number; acceptanceStatus?: string }>
  metrics: MetricSet | null
  platforms: Array<{ name: string } & MetricSet>
  answers: AnswerRecord[]
  answerTotal: number
  page: number
  pageSize: number
  deliveries: Array<{
    itemId: string
    title: string
    media: string
    mediaLevel: string
    originalUrl: string
    publishDate: string | null
    indexStatus: string
    citationStatus: string
    aiPlatforms: string[]
  }>
  completion: Array<{
    itemId: string
    category: string
    itemName: string
    unit: string
    contractQuantity: number
    qualifiedQuantity: number
    weight: number
    evidenceUrl: string
    note: string
  }>
  deliveryCompletion: number | null
  competitors: Array<{
    competitorName: string
    sampleCount: number
    mentions: number
    recommendations: number
    averageRank: number | null
    sov: number | null
    isTarget: boolean
  }>
  demand: Array<{
    keyword: string
    questionType: string
    scene: string
    region: string
    sampleCount: number
    mentions: number
    recommendations: number
  }>
  trend: Array<{
    snapshotId: string
    reportMonth: string
    version: number
    answerCount: number
    mentionRate: number | null
    recommendRate: number | null
    top3Rate: number | null
    comparable: boolean
  }>
  filters: { platform?: string[]; keyword?: string[]; scene?: string[]; region?: string[] }
  activeFilters: { platform: string; keyword: string; scene: string; region: string }
  acceptanceHistory: Array<{ id: string; status: string; comment: string; submittedBy: string; submittedAt: string }>
}

type FilterState = { month: string; platform: string; keyword: string; scene: string; region: string }

const reportPageTitles = ["报告概览", "前后对比与效果验证", "AI回答表现", "竞品格局对比", "市场需求与热点追踪", "GEO执行与品牌建设", "交付内容与文章链接", "数据公式与口径说明", "问题与风险", "下阶段行动计划"]

function value(source: number | null | undefined, suffix = "%") {
  return source === null || source === undefined ? "—" : `${source}${suffix}`
}

function reportDate(source: string | null | undefined) {
  if (!source) return "—"
  const date = new Date(source)
  return Number.isNaN(date.getTime()) ? source : date.toLocaleString("zh-CN", { hour12: false })
}

function readyCompetitorCoverage(coverage: Coverage) {
  if (coverage.competitorEntityMatch !== 1 || coverage.competitorCountMatch !== 1 || Number(coverage.unmatchedCompetitorCount ?? 0) > 0) return 0
  return Math.min(Number(coverage.competitorScopeCoverage ?? 0), Number(coverage.competitorRecordCoverage ?? 0))
}

function safeFilename(source: string) {
  return source.replace(/[\\/:*?"<>|\s]+/g, "-").slice(0, 80)
}

function csvCell(source: unknown) {
  return `"${String(source ?? "").replaceAll('"', '""')}"`
}

function downloadText(filename: string, content: string, type: string) {
  const url = URL.createObjectURL(new Blob([content], { type }))
  const anchor = document.createElement("a")
  anchor.href = url
  anchor.download = filename
  anchor.click()
  window.setTimeout(() => URL.revokeObjectURL(url), 300)
}

function Heading({ eyebrow, title, description, aside }: { eyebrow: string; title: string; description: string; aside?: React.ReactNode }) {
  return <div className="live-report-heading v8"><div><span>{eyebrow}</span><h2>{title}</h2><p>{description}</p></div>{aside ? <div>{aside}</div> : null}</div>
}

function EmptyState({ title, description }: { title: string; description: string }) {
  return <div className="live-report-empty"><Database/><strong>{title}</strong><span>{description}</span></div>
}

function MetricCard({ label, metric, question, target }: { label: string; metric: number | null; question: string; target?: number }) {
  const achieved = metric !== null && target ? metric >= target : null
  return <div className="live-metric-card"><div><span>{label}</span>{achieved === null ? <BarChart3/> : achieved ? <CheckCircle2/> : <CircleAlert/>}</div><strong>{value(metric)}</strong><p>{question}</p>{target ? <small className={achieved ? "met" : "pending"}>验收目标 {target}% · {achieved ? "已达成" : "持续优化"}</small> : <small>当前正式快照</small>}</div>
}

function AcceptanceStatus({ status }: { status: string }) {
  if (status === "accepted") return <Badge variant="outline" className="status-positive"><CheckCircle2/>甲方已验收</Badge>
  if (status === "disputed") return <Badge variant="outline" className="status-negative"><CircleAlert/>甲方有异议</Badge>
  return <Badge variant="outline" className="status-warning"><MessageSquareCheck/>待甲方验收</Badge>
}

function Overview({ data, onAcceptance }: { data: ReportData; onAcceptance: () => void }) {
  const metrics = data.metrics
  const rules = data.project.acceptanceRules
  const coverage = data.snapshot?.summary.coverage ?? {}
  const canAccept = ["owner", "reviewer", "approver"].includes(data.access.memberRole)
  return <div className="live-report-stack">
    <section className="live-project-hero">
      <div className="live-project-brand"><div>{data.project.logoKey ? <img src={`/api/ops/files?key=${encodeURIComponent(data.project.logoKey)}`} alt={`${data.project.brandName} Logo`}/> : data.project.brandName.slice(0, 1)}</div><span>{data.project.projectCode}</span><h1>{data.project.brandName}</h1><p>{data.project.clientName}</p></div>
      <div className="live-project-brief"><div className="live-hero-badges"><Badge variant="outline"><BadgeCheck/>正式发布报告</Badge>{data.snapshot ? <AcceptanceStatus status={data.snapshot.acceptanceStatus}/> : null}</div><h2>{data.project.projectName}</h2><p>核心词「{data.project.coreKeyword || "待配置"}」 · {data.project.optimizationRegion || "优化地域待配置"} · {data.project.platforms.length}个检测平台</p><div><span>报告月份<strong>{data.snapshot?.reportMonth ?? "—"}</strong></span><span>快照版本<strong>{data.snapshot ? `r${data.snapshot.version}` : "—"}</strong></span><span>发布时间<strong>{reportDate(data.snapshot?.publishedAt)}</strong></span><span>数据质量<strong>{value(data.snapshot?.qualityScore)}</strong></span></div></div>
    </section>
    {metrics ? <section className="live-metric-grid v8"><MetricCard label="AI综合可见度" metric={metrics.visibility} question={metrics.visibility === null ? "六项底层指标完整后按固定权重出分" : "品牌在AI答案中的综合曝光与推荐表现"}/><MetricCard label="品牌健康度" metric={metrics.health} question="事实点准确性与内容中正性的综合质量"/><MetricCard label="品牌提及率" metric={metrics.mentionRate} target={rules.mentionRate} question="用户提问时，品牌是否被AI提及"/><MetricCard label="主动推荐率" metric={metrics.recommendRate} target={rules.recommendRate} question="推荐型有效回答中，品牌是否被明确推荐"/><MetricCard label="Top3曝光率" metric={metrics.top3Rate} target={rules.top3Rate} question="推荐型有效回答中，品牌是否进入前三位"/><MetricCard label="品牌信息准确率" metric={metrics.accuracyRate} question="正确品牌事实点占全部可核验事实点的比例"/><MetricCard label="内容正面率" metric={metrics.positiveRate} question="提及品牌的回答中，正面评价比例"/><MetricCard label="品牌信源引用率" metric={metrics.citationRate} question="可检测引用的回答中，品牌相关信源被引用的比例"/></section> : <EmptyState title="尚未发布有效数据快照" description="乙方完成数据导入、质量复核并发布后，本页才会出现效果指标。"/>}
    <section className="live-report-card"><Heading eyebrow="DELIVERY EVIDENCE" title="本期交付与证据完整度" description="汇总数字只读取当前正式快照；原始回答证据与引用信源证据分开统计。"/><div className="live-stat-row"><div><span>有效AI回答</span><strong>{metrics?.answerCount ?? 0}</strong></div><div><span>原始回答证据</span><strong>{value(coverage.rawEvidenceCoverage ?? coverage.evidenceCoverage)}</strong></div><div><span>引用信源证据</span><strong>{value(coverage.citationEvidenceCoverage)}</strong></div><div><span>事实点核验覆盖</span><strong>{value(coverage.accuracyCoverage)}</strong></div><div><span>竞品同口径覆盖</span><strong>{value(readyCompetitorCoverage(coverage))}</strong></div></div></section>
    {data.snapshot && data.project.projectType === "client" ? <section className="live-acceptance-card"><div><MessageSquareCheck/><span>CLIENT ACCEPTANCE</span><h3>本期交付验收</h3><p>验收结论绑定当前发布快照；若存在异议，请写明具体指标、Prompt或证据记录。</p></div><div><AcceptanceStatus status={data.snapshot.acceptanceStatus}/><small>{data.snapshot.acceptanceStatus === "accepted" ? `确认时间 ${reportDate(data.snapshot.acceptedAt)}` : "当前快照等待品牌方确认"}</small>{canAccept ? <Button onClick={onAcceptance}><SearchCheck/>进入验收</Button> : <span className="live-viewer-note"><ShieldCheck/>当前账号为查看人</span>}</div></section> : null}
  </div>
}

function Comparison({ data }: { data: ReportData }) {
  return <section className="live-report-card"><Heading eyebrow="BEFORE / AFTER" title="前后对比与效果验证" description="只有口径指纹一致的快照才可纳入同比；口径变化会明确标注，不混算提升幅度。"/>{data.trend.length > 1 ? <div className="table-shell"><Table><TableHeader><TableRow><TableHead>月份</TableHead><TableHead>口径一致性</TableHead><TableHead>有效回答</TableHead><TableHead>提及率</TableHead><TableHead>推荐率</TableHead><TableHead>Top3率</TableHead></TableRow></TableHeader><TableBody>{data.trend.map((item) => <TableRow key={`${item.reportMonth}-${item.version}`}><TableCell><strong>{item.reportMonth}</strong><small>r{item.version}</small></TableCell><TableCell>{item.comparable ? <Badge variant="outline" className="status-positive"><CheckCircle2/>同口径</Badge> : <Badge variant="outline" className="status-warning"><CircleAlert/>不纳入同比</Badge>}</TableCell><TableCell>{item.answerCount}</TableCell><TableCell>{value(item.mentionRate)}</TableCell><TableCell>{value(item.recommendRate)}</TableCell><TableCell>{value(item.top3Rate)}</TableCell></TableRow>)}</TableBody></Table></div> : <EmptyState title="需要至少两个正式月度快照" description="首个快照建立基线；发布下一月份同口径数据后，系统自动形成前后对比。"/>}</section>
}

function Answers({ data, onSelect, onPage }: { data: ReportData; onSelect: (answer: AnswerRecord) => void; onPage: (page: number) => void }) {
  const totalPages = Math.max(1, Math.ceil(data.answerTotal / data.pageSize))
  return <section className="live-report-card"><Heading eyebrow="AI ANSWER EVIDENCE" title="AI回答表现" description="点击记录可下钻至Prompt、完整回答、模型版本、事实点判定、引用与原始证据。" aside={<Badge variant="outline">共 {data.answerTotal} 条</Badge>}/>{data.answers.length ? <><div className="table-shell live-answer-table"><Table><TableHeader><TableRow><TableHead>平台 / 场景</TableHead><TableHead>问题与回答摘要</TableHead><TableHead>提及</TableHead><TableHead>推荐</TableHead><TableHead>排名</TableHead><TableHead>事实点</TableHead><TableHead>核验</TableHead></TableRow></TableHeader><TableBody>{data.answers.map((item) => <TableRow key={item.recordId}><TableCell><strong>{item.platform}</strong><small>{item.keyword || "未标注关键词"}<br/>{item.scene || item.questionType || "未标注场景"}</small></TableCell><TableCell><strong>{item.question}</strong><p>{item.answer}</p></TableCell><TableCell>{item.mention ? "是" : "否"}</TableCell><TableCell>{item.recommendationPrompt ? (item.recommend ? "是" : "否") : "非推荐型"}</TableCell><TableCell>{item.rank ?? "—"}</TableCell><TableCell>{item.factPointsTotal ? `${item.factPointsCorrect}/${item.factPointsTotal}` : "无事实点"}</TableCell><TableCell><Button variant="outline" size="sm" onClick={() => onSelect(item)}><SearchCheck/>查看证据</Button></TableCell></TableRow>)}</TableBody></Table></div><div className="live-pagination"><span>第 {data.page} / {totalPages} 页 · 当前 {data.answers.length} 条</span><div><Button variant="outline" size="sm" onClick={() => onPage(data.page - 1)} disabled={data.page <= 1}><ChevronLeft/>上一页</Button><Button variant="outline" size="sm" onClick={() => onPage(data.page + 1)} disabled={data.page >= totalPages}>下一页<ChevronRight/></Button></div></div></> : <EmptyState title="当前筛选条件没有AI回答" description="可以重置筛选，或检查当前快照的数据导入范围。"/>}</section>
}

function Competition({ data }: { data: ReportData }) {
  const target = data.competitors.find((item) => item.isTarget)
  const hasCompetitors = data.competitors.some((item) => !item.isTarget)
  return <div className="live-report-stack"><section className="live-report-card"><Heading eyebrow="SHARE OF VOICE" title="竞品格局与品牌SOV" description="目标品牌与竞品使用同一Prompt、平台和筛选范围；SOV按推荐次数占全部品牌推荐次数计算。" aside={target ? <div className="live-sov-highlight"><span>品牌SOV</span><strong>{value(target.sov)}</strong></div> : null}/>{hasCompetitors ? <div className="live-competitor-list">{data.competitors.map((item, index) => <div key={item.competitorName} className={item.isTarget ? "target" : ""}><span>{String(index + 1).padStart(2, "0")}</span><div><strong>{item.competitorName}{item.isTarget ? <Badge variant="outline">目标品牌</Badge> : null}</strong><Progress value={item.sov ?? 0}/><small>提及 {item.mentions} · 推荐 {item.recommendations} · 平均位次 {item.averageRank ?? "—"}</small></div><b>{value(item.sov)}</b></div>)}</div> : <EmptyState title="当前快照尚无完整竞品检测数据" description="系统不会根据品牌回答推测竞品份额；需导入同Prompt、同平台的竞品记录后计算。"/>}</section><section className="live-report-card"><Heading eyebrow="PLATFORM LANDSCAPE" title="跨平台表现对比" description="查看同一筛选范围内各AI平台的提及、推荐、Top3与准确性差异。"/>{data.platforms.length ? <div className="live-platform-grid">{data.platforms.map((item) => <div key={item.name}><strong>{item.name}</strong><span>提及率 {value(item.mentionRate)}</span><Progress value={item.mentionRate ?? 0}/><small>推荐 {value(item.recommendRate)} · Top3 {value(item.top3Rate)} · 准确 {value(item.accuracyRate)}</small></div>)}</div> : <EmptyState title="暂无平台对比数据" description="重置平台筛选或确认回答记录中的平台字段。"/>}</section></div>
}

function Demand({ data }: { data: ReportData }) {
  return <section className="live-report-card"><Heading eyebrow="QUESTION & SCENE COVERAGE" title="市场需求与热点追踪" description="本页展示真实检测问题的关键词、问题类型、场景和地域覆盖；未接入搜索量时不将样本数表述为市场搜索量。"/>{data.demand.length ? <div className="live-demand-grid">{data.demand.slice(0, 30).map((item, index) => <div key={`${item.keyword}-${item.questionType}-${item.scene}-${item.region}-${index}`}><span>{String(index + 1).padStart(2, "0")}</span><div><strong>{item.keyword || "未标注关键词"}</strong><p>{[item.questionType, item.scene, item.region].filter(Boolean).join(" · ") || "通用问题"}</p><small>样本 {item.sampleCount} · 提及 {item.mentions} · 推荐 {item.recommendations}</small></div></div>)}</div> : <EmptyState title="暂无有效问题样本" description="导入包含关键词、问题类型、场景和地域的AI回答后自动生成。"/>}</section>
}

function Execution({ data }: { data: ReportData }) {
  const target = Number(data.project.acceptanceRules.deliveryTarget || 0)
  const completion = target ? Math.min(100, Number(((data.deliveries.length / target) * 100).toFixed(1))) : null
  return <div className="live-report-stack">
    <section className="live-report-card"><Heading eyebrow="DELIVERY ACCEPTANCE" title="第一层：合同交付完成度" description="逐项核对合同数量、合格数量、权重和可访问证据；单项完成率最高按100%计。" aside={<div className="live-sov-highlight"><span>加权完成度</span><strong>{value(data.deliveryCompletion)}</strong></div>}/>{data.completion.length ? <div className="table-shell"><Table><TableHeader><TableRow><TableHead>交付项</TableHead><TableHead>合同约定</TableHead><TableHead>合格交付</TableHead><TableHead>单项完成率</TableHead><TableHead>权重</TableHead><TableHead>加权贡献</TableHead><TableHead>证据</TableHead></TableRow></TableHeader><TableBody>{data.completion.map((item) => { const itemRate = Math.min(100, Number(((item.qualifiedQuantity / item.contractQuantity) * 100).toFixed(1))); const contribution = Number(((itemRate / 100) * item.weight).toFixed(1)); return <TableRow key={item.itemId}><TableCell><strong>{item.itemName}</strong><small>{item.category}</small></TableCell><TableCell>{item.contractQuantity} {item.unit}</TableCell><TableCell>{item.qualifiedQuantity} {item.unit}</TableCell><TableCell>{itemRate}%</TableCell><TableCell>{item.weight}%</TableCell><TableCell>{contribution}分</TableCell><TableCell><Button variant="outline" size="sm" asChild><a href={item.evidenceUrl} target="_blank" rel="noreferrer"><ExternalLink/>核验</a></Button></TableCell></TableRow> })}</TableBody></Table></div> : <EmptyState title="尚未导入合同交付验收表" description="乙方需按合同逐项导入数量、权重与证据链接，才能发布正式验收报告。"/>}</section>
    <section className="live-report-card"><Heading eyebrow="GEO EXECUTION" title="内容建设与公开交付" description="交付动作、目标内容和公开链接以当前正式快照为准。"/><div className="live-execution-hero"><FileCheck2/><div><span>本期有效内容</span><strong>{data.deliveries.length}篇</strong><p>{target ? `验收目标 ${target}篇，当前完成 ${completion}%` : "内容数量目标尚未配置"}</p></div>{completion !== null ? <Progress value={completion}/> : null}</div></section>
    <section className="live-report-card"><Heading eyebrow="CONTENT DISTRIBUTION" title="媒体层级分布" description="按真实交付记录的媒体层级字段汇总。"/><div className="live-stat-row">{Object.entries(data.deliveries.reduce<Record<string, number>>((acc, item) => { const key = item.mediaLevel || "未标注层级"; acc[key] = (acc[key] ?? 0) + 1; return acc }, {})).map(([label, count]) => <div key={label}><span>{label}</span><strong>{count}</strong></div>)}</div>{!data.deliveries.length ? <EmptyState title="暂无交付内容" description="导入并发布交付链接后自动生成执行进度。"/> : null}</section>
  </div>
}

function Deliveries({ data }: { data: ReportData }) {
  return <section className="live-report-card"><Heading eyebrow="DELIVERY REGISTER" title="交付内容与文章链接" description="点击原文核验媒体、标题、发布时间、收录状态与AI引用状态。" aside={<Badge variant="outline">共 {data.deliveries.length} 条</Badge>}/>{data.deliveries.length ? <div className="table-shell"><Table><TableHeader><TableRow><TableHead>文章标题</TableHead><TableHead>媒体</TableHead><TableHead>层级</TableHead><TableHead>发布时间</TableHead><TableHead>收录</TableHead><TableHead>AI引用</TableHead><TableHead>原文</TableHead></TableRow></TableHeader><TableBody>{data.deliveries.map((item) => <TableRow key={item.itemId}><TableCell><strong>{item.title}</strong></TableCell><TableCell>{item.media}</TableCell><TableCell>{item.mediaLevel || "—"}</TableCell><TableCell>{item.publishDate || "—"}</TableCell><TableCell>{item.indexStatus}</TableCell><TableCell>{item.citationStatus}</TableCell><TableCell><Button variant="outline" size="sm" asChild><a href={item.originalUrl} target="_blank" rel="noreferrer"><ExternalLink/>查看</a></Button></TableCell></TableRow>)}</TableBody></Table></div> : <EmptyState title="当前快照没有交付链接" description="交付内容导入并发布后将在这里形成甲方验收台账。"/>}</section>
}

function Formulas({ data }: { data: ReportData }) {
  const coverage = data.snapshot?.summary.coverage ?? {}
  const protocol = data.project.measurementProtocol
  return <div className="live-report-stack"><section className="live-report-card"><Heading eyebrow="METRIC STANDARD" title="数据公式与口径说明" description={`当前报告绑定 ${data.snapshot ? `${data.snapshot.reportMonth}-r${data.snapshot.version}` : "未发布"} 快照，01—10模块共用同一计算结果。`}/><div className="live-formula-grid">{[
    ["品牌提及率", "提及品牌的有效回答数 ÷ 全部有效回答数 × 100%"],
    ["主动推荐率", "明确推荐品牌的回答数 ÷ 推荐型有效回答数 × 100%"],
    ["Top3曝光率", "品牌进入前三位的回答数 ÷ 推荐型有效回答数 × 100%"],
    ["平均推荐位次", "全部有效推荐位次之和 ÷ 获得明确推荐位次的次数"],
    ["品牌信源引用率", "品牌相关信源被引用的回答数 ÷ 可检测引用的有效回答数 × 100%"],
    ["原始回答证据覆盖率", "具有AI对话链接或原始回答证据文件的有效回答数 ÷ 全部有效回答数 × 100%"],
    ["引用信源证据覆盖率", "具有实际引用URL的品牌信源引用记录数 ÷ 品牌信源引用记录数 × 100%"],
    ["有效回答率", "有效回答数 ÷ 检测调用总数 × 100%；失败、超时与无效输出单独留痕"],
    ["单项交付完成率", "实际合格交付数量 ÷ 合同约定数量 × 100%，最高按100%计"],
    ["总交付完成度", "Σ（各单项交付完成率 × 对应权重），全部权重合计100%"],
    ["品牌正面率", "提及品牌且评价为正面的回答数 ÷ 提及品牌的回答数 × 100%"],
    ["品牌信息准确率", "正确品牌事实点数量 ÷ 全部可核验品牌事实点数量 × 100%"],
    ["品牌健康度", "品牌信息准确率 × 60% + 内容中正率 × 40%"],
    ["品牌SOV", "目标品牌推荐次数 ÷ 目标品牌与全部竞品推荐次数之和 × 100%；展示值采用最大余数法，合计固定100.0%"],
    ["AI综合可见度", "提及25% + 推荐25% + Top3 15% + 位次得分10% + 引用10% + SOV 15%"],
  ].map(([label, formula]) => <div key={label}><span>{label}</span><strong>{formula}</strong></div>)}</div></section><section className="live-report-card"><Heading eyebrow="FROZEN SCOPE" title="本期冻结口径与样本边界" description="品牌别名、Prompt池、平台、竞品集合、检测计划与判定规则共同形成快照指纹。"/><div className="live-scope-grid"><div><span>配置版本</span><strong>v{data.project.configVersion}</strong></div><div><span>指标 / 引擎版本</span><strong>{protocol.metricStandardVersion || "—"} · {protocol.calculationEngineVersion || "—"}</strong></div><div><span>品牌别名</span><strong>{protocol.brandAliases?.join("、") || data.project.brandName}</strong></div><div><span>Prompt池</span><strong>{protocol.promptPoolVersion || "—"}</strong></div><div><span>计划检测 N</span><strong>{protocol.detectionCount ?? "—"}</strong></div><div><span>实际调用</span><strong>{coverage.totalCallCount ?? 0}</strong></div><div><span>当前有效 n</span><strong>{data.metrics?.answerCount ?? 0}</strong></div><div><span>有效回答率</span><strong>{value(coverage.validResponseRate)}</strong></div><div><span>异常调用</span><strong>失败 {coverage.failedCount ?? 0} · 超时 {coverage.timeoutCount ?? 0} · 无效 {coverage.invalidCount ?? 0}</strong></div><div><span>原始回答证据</span><strong>{value(coverage.rawEvidenceCoverage ?? coverage.evidenceCoverage)}</strong></div><div><span>引用信源证据</span><strong>{value(coverage.citationEvidenceCoverage)}</strong></div><div><span>事实点核验覆盖</span><strong>{value(coverage.accuracyCoverage)}</strong></div><div><span>判定规则</span><strong>{protocol.judgmentRulesVersion || "—"}</strong></div><div className="fingerprint"><span>口径指纹</span><strong>{data.project.configFingerprint ? `${data.project.configFingerprint.slice(0, 12)}…` : "—"}</strong></div></div></section></div>
}

function Risks({ data }: { data: ReportData }) {
  const rules = data.project.acceptanceRules
  const metrics = data.metrics
  const coverage = data.snapshot?.summary.coverage ?? {}
  const risks = [
    !metrics ? ["数据不足", "当前没有可用于验收的正式效果数据", "待处理"] : null,
    metrics && rules.mentionRate && (metrics.mentionRate ?? 0) < rules.mentionRate ? ["提及率未达目标", `当前${value(metrics.mentionRate)}，验收目标${rules.mentionRate}%`, "持续优化"] : null,
    metrics && rules.recommendRate && (metrics.recommendRate ?? 0) < rules.recommendRate ? ["推荐率未达目标", `当前${value(metrics.recommendRate)}，验收目标${rules.recommendRate}%`, "持续优化"] : null,
    metrics && rules.top3Rate && (metrics.top3Rate ?? 0) < rules.top3Rate ? ["Top3率未达目标", `当前${value(metrics.top3Rate)}，验收目标${rules.top3Rate}%`, "持续优化"] : null,
    Number(coverage.validResponseRate ?? 0) < Number(rules.minValidResponseRate ?? 90) ? ["有效回答率未达门槛", `当前${value(coverage.validResponseRate)}，发布门槛${rules.minValidResponseRate ?? 90}%`, "需补测"] : null,
    Number(coverage.deliveryCompletion ?? 0) < Number(rules.minDeliveryCompletion ?? 100) ? ["合同交付完成度未达门槛", `当前${value(coverage.deliveryCompletion)}，验收门槛${rules.minDeliveryCompletion ?? 100}%`, "待补交付"] : null,
    Number(coverage.rawEvidenceCoverage ?? coverage.evidenceCoverage ?? 0) < Number(rules.minEvidenceCoverage ?? 100) ? ["原始回答证据覆盖不足", `当前${value(coverage.rawEvidenceCoverage ?? coverage.evidenceCoverage)}，发布门槛${rules.minEvidenceCoverage ?? 100}%`, "待补原始证据"] : null,
    Number(coverage.citationEvidenceCoverage ?? 0) < Number(rules.minCitationEvidenceCoverage ?? 100) ? ["引用信源证据覆盖不足", `当前${value(coverage.citationEvidenceCoverage)}，发布门槛${rules.minCitationEvidenceCoverage ?? 100}%`, "待补引用证据"] : null,
    Number(coverage.accuracyCoverage ?? 0) < Number(rules.minAccuracyCoverage ?? 100) ? ["事实点核验未完成", `当前覆盖${value(coverage.accuracyCoverage)}，发布门槛${rules.minAccuracyCoverage ?? 100}%`, "待复核"] : null,
    readyCompetitorCoverage(coverage) < 100 ? ["竞品检测口径不完整", `有效同口径覆盖${value(readyCompetitorCoverage(coverage))}，未匹配记录${coverage.unmatchedCompetitorCount ?? 0}条`, "待补数据"] : null,
    data.snapshot?.acceptanceStatus === "disputed" ? ["甲方提交验收异议", "请依据验收记录定位指标、Prompt或证据并闭环回复", "优先处理"] : null,
    data.trend.some((item) => !item.comparable) ? ["存在不同口径快照", "不同指纹的数据已隔离展示，不纳入前后同比结论", "已隔离"] : null,
  ].filter(Boolean) as string[][]
  return <section className="live-report-card"><Heading eyebrow="ISSUES & RISKS" title="问题与风险" description="只呈现当前正式数据能够确认的问题，不生成没有证据的风险结论。"/>{risks.length ? <div className="live-risk-list">{risks.map(([title, detail, status]) => <div key={title}><AlertTriangle/><div><strong>{title}</strong><p>{detail}</p></div><Badge variant="outline">{status}</Badge></div>)}</div> : <div className="live-clear-state"><ShieldCheck/><strong>当前快照未发现需要升级处理的验收风险</strong><span>仍建议按月保持同口径复测与链接巡检。</span></div>}</section>
}

function NextActions({ data, onAcceptance }: { data: ReportData; onAcceptance: () => void }) {
  const coverage = data.snapshot?.summary.coverage ?? {}
  const tasks = [
    !data.snapshot ? ["P0", "完成首批数据导入、质量复核与正式发布"] : null,
    data.snapshot?.acceptanceStatus === "awaiting_acceptance" ? ["P0", "品牌方复核本期报告并提交验收结论"] : null,
    data.snapshot?.acceptanceStatus === "disputed" ? ["P0", "乙方根据验收异议补证、修正并发布新版本"] : null,
    data.trend.length < 2 ? ["P0", "形成下一期同口径快照，建立前后对比"] : null,
    readyCompetitorCoverage(coverage) < 100 ? ["P0", "补齐冻结竞品实体、记录数、Prompt与平台数据"] : null,
    data.deliveries.some((item) => item.indexStatus.includes("待")) ? ["P1", "持续巡检待收录的交付内容"] : null,
    ["P1", "按核心词、问题类型、场景和地域复核覆盖"],
    ["P2", "完成下一月数据口径复核与正式发布"],
  ].filter(Boolean) as string[][]
  return <div className="live-report-stack"><section className="live-report-card"><Heading eyebrow="NEXT ACTION PLAN" title="下阶段行动计划" description="根据项目数据完整度、目标达成和验收状态形成待办，最终由项目负责人确认。"/><div className="live-action-list">{tasks.map(([priority, task], index) => <div key={`${priority}-${task}`}><span>{String(index + 1).padStart(2, "0")}</span><Badge variant="outline">{priority}</Badge><strong>{task}</strong><ArrowRight/></div>)}</div></section>{data.snapshot && data.project.projectType === "client" && ["owner", "reviewer", "approver"].includes(data.access.memberRole) ? <section className="live-next-acceptance"><div><MessageSquareCheck/><span>当前验收状态</span><AcceptanceStatus status={data.snapshot.acceptanceStatus}/></div><Button onClick={onAcceptance}>复核并提交结论<ArrowRight/></Button></section> : null}</div>
}

function FilterBar({ data, filters, loading, onFilter, onReset, onExport }: { data: ReportData; filters: FilterState; loading: boolean; onFilter: (key: keyof FilterState, value: string) => void; onReset: () => void; onExport: (type: "json" | "answers" | "deliveries" | "completion" | "print") => void }) {
  const activeCount = [filters.platform, filters.keyword, filters.scene, filters.region].filter(Boolean).length
  const selectors: Array<{ key: keyof FilterState; label: string; values: string[] }> = [
    { key: "platform", label: "全部平台", values: data.filters.platform ?? [] },
    { key: "keyword", label: "全部关键词", values: data.filters.keyword ?? [] },
    { key: "scene", label: "全部场景", values: data.filters.scene ?? [] },
    { key: "region", label: "全部地域", values: data.filters.region ?? [] },
  ]
  return <section className="live-filter-bar"><div className="live-filter-title"><SlidersHorizontal/><div><strong>报告数据范围</strong><span>{activeCount ? `已启用 ${activeCount} 项筛选` : "当前展示完整发布快照"}</span></div>{loading ? <LoaderCircle className="spin"/> : <Badge variant="outline"><ShieldCheck/>服务端同口径计算</Badge>}</div><div className="live-filter-controls"><Select value={filters.month || data.snapshot?.reportMonth || "none"} onValueChange={(entry) => onFilter("month", entry === "none" ? "" : entry)}><SelectTrigger aria-label="报告月份"><SelectValue placeholder="报告月份"/></SelectTrigger><SelectContent>{data.snapshots.length ? data.snapshots.map((snapshot) => <SelectItem key={snapshot.id} value={snapshot.reportMonth}>{snapshot.reportMonth} · r{snapshot.version}</SelectItem>) : <SelectItem value="none" disabled>尚无正式快照</SelectItem>}</SelectContent></Select>{selectors.map((selector) => <Select key={selector.key} value={filters[selector.key] || "__all__"} onValueChange={(entry) => onFilter(selector.key, entry === "__all__" ? "" : entry)}><SelectTrigger aria-label={selector.label}><SelectValue placeholder={selector.label}/></SelectTrigger><SelectContent><SelectItem value="__all__">{selector.label}</SelectItem>{selector.values.map((entry) => <SelectItem key={entry} value={entry}>{entry}</SelectItem>)}</SelectContent></Select>)}<Button variant="outline" onClick={onReset} disabled={!activeCount}><RotateCcw/>重置</Button></div><div className="live-export-actions"><Button variant="ghost" size="sm" onClick={() => onExport("json")}><FileJson/>视图JSON</Button><Button variant="ghost" size="sm" onClick={() => onExport("answers")}><Download/>当前页回答CSV</Button><Button variant="ghost" size="sm" onClick={() => onExport("completion")}><Download/>验收明细CSV</Button><Button variant="ghost" size="sm" onClick={() => onExport("deliveries")}><Download/>交付清单CSV</Button><Button variant="ghost" size="sm" onClick={() => onExport("print")}><Printer/>完整报告PDF</Button></div></section>
}

function EvidenceSheet({ answer, onClose }: { answer: AnswerRecord | null; onClose: () => void }) {
  return <Sheet open={Boolean(answer)} onOpenChange={(open) => !open && onClose()}>
    <SheetContent className="live-evidence-sheet sm:max-w-2xl">
      <SheetHeader><SheetTitle>AI回答证据核验</SheetTitle><SheetDescription>记录ID、Prompt、模型、检测时间、完整回答、事实点与引用判定均来自当前正式快照。</SheetDescription></SheetHeader>
      {answer ? <div className="live-evidence-body">
        <div className="live-evidence-id"><span>{answer.recordId}</span><Badge variant="outline">{answer.platform}</Badge></div>
        <div className="live-evidence-meta">
          <div><span>Prompt ID</span><strong>{answer.promptId}</strong></div><div><span>模型版本</span><strong>{answer.modelVersion || "未记录"}</strong></div>
          <div><span>检测时间</span><strong>{answer.testedAt}</strong></div><div><span>关键词</span><strong>{answer.keyword || "—"}</strong></div>
          <div><span>问题类型 / 场景</span><strong>{[answer.questionType, answer.scene].filter(Boolean).join(" / ") || "—"}</strong></div><div><span>地域</span><strong>{answer.region || "—"}</strong></div>
        </div>
        <div className="live-evidence-copy"><span>检测问题</span><strong>{answer.question}</strong></div>
        <div className="live-evidence-copy answer"><span>完整回答</span><p>{answer.answer}</p></div>
        <div className="live-evidence-judgment">
          <div><span>推荐型Prompt</span><strong>{answer.recommendationPrompt ? "是" : "否"}</strong></div><div><span>品牌提及</span><strong>{answer.mention ? "是" : "否"}</strong></div>
          <div><span>主动推荐</span><strong>{answer.recommend ? "是" : "否"}</strong></div><div><span>Top3 / 位次</span><strong>{answer.top3 ? "是" : "否"} / {answer.rank ?? "—"}</strong></div>
          <div><span>情感</span><strong>{answer.sentiment || "未判定"}</strong></div><div><span>正确事实点</span><strong>{answer.factPointsCorrect} / {answer.factPointsTotal}</strong></div>
          <div><span>引用可检测</span><strong>{answer.citationDetectable ? "是" : "否"}</strong></div><div><span>品牌信源被引用</span><strong>{answer.brandCited ? "是" : "否"}</strong></div>
        </div>
        {answer.accuracyNote ? <div className="live-evidence-note"><SearchCheck/><div><span>事实点核验说明</span><p>{answer.accuracyNote}</p><small>{answer.judgedBy ? `判定人：${answer.judgedBy}` : ""}</small></div></div> : null}
        <div className="live-evidence-links"><span>可核验证据</span><div>{answer.evidenceUrl ? <Button asChild><a href={answer.evidenceUrl} target="_blank" rel="noreferrer"><FileText/>原始证据文件</a></Button> : null}{answer.conversationUrl ? <Button variant="outline" asChild><a href={answer.conversationUrl} target="_blank" rel="noreferrer"><ExternalLink/>AI对话链接</a></Button> : null}</div>{answer.citationUrls.length ? <ul>{answer.citationUrls.map((url, index) => <li key={`${url}-${index}`}><a href={url} target="_blank" rel="noreferrer">品牌相关引用来源 {index + 1}<ExternalLink/></a></li>)}</ul> : null}{!answer.evidenceUrl && !answer.conversationUrl && !answer.citationUrls.length ? <small>当前记录没有可下载的证据文件或外部链接。</small> : null}</div>
      </div> : null}
    </SheetContent>
  </Sheet>
}

export function LiveProjectReport({ projectSlug, activePage }: { projectSlug: string; activePage: number }) {
  const [data, setData] = React.useState<ReportData | null>(null)
  const [error, setError] = React.useState("")
  const [loading, setLoading] = React.useState(true)
  const [filters, setFilters] = React.useState<FilterState>({ month: "", platform: "", keyword: "", scene: "", region: "" })
  const [page, setPage] = React.useState(1)
  const [selectedAnswer, setSelectedAnswer] = React.useState<AnswerRecord | null>(null)
  const [acceptanceOpen, setAcceptanceOpen] = React.useState(false)
  const [acceptanceStatus, setAcceptanceStatus] = React.useState<"accepted" | "disputed">("accepted")
  const [acceptanceComment, setAcceptanceComment] = React.useState("")
  const [acceptancePending, setAcceptancePending] = React.useState(false)
  const [refreshKey, setRefreshKey] = React.useState(0)

  React.useEffect(() => {
    const controller = new AbortController()
    const query = new URLSearchParams({ slug: projectSlug, page: String(page) })
    Object.entries(filters).forEach(([key, entry]) => { if (entry) query.set(key, entry) })
    const loadingTimer = window.setTimeout(() => { setLoading(true); setError("") }, 0)
    fetch(`/api/report?${query.toString()}`, { signal: controller.signal, headers: { accept: "application/json" } })
      .then(async (response) => {
        const result = await response.json() as ReportData & { error?: string }
        if (!response.ok) throw new Error(result.error ?? "报告读取失败")
        setData(result)
        setFilters((current) => current.month || !result.snapshot?.reportMonth ? current : { ...current, month: result.snapshot.reportMonth })
      })
      .catch((reason) => { if (reason?.name !== "AbortError") setError(reason instanceof Error ? reason.message : "报告读取失败") })
      .finally(() => { if (!controller.signal.aborted) setLoading(false) })
    return () => { window.clearTimeout(loadingTimer); controller.abort() }
  }, [projectSlug, filters, page, refreshKey])

  const onFilter = (key: keyof FilterState, entry: string) => {
    setFilters((current) => ({ ...current, [key]: entry }))
    setPage(1)
  }

  const resetFilters = () => {
    setFilters((current) => ({ month: current.month, platform: "", keyword: "", scene: "", region: "" }))
    setPage(1)
  }

  const exportView = (type: "json" | "answers" | "deliveries" | "completion" | "print") => {
    if (!data) return
    const base = `${safeFilename(data.project.brandName)}_${data.snapshot?.reportMonth ?? "报告"}`
    if (type === "print") { window.print(); toast.info("已打开打印 / 另存为PDF面板"); return }
    if (type === "json") {
      downloadText(`${base}_筛选视图.json`, JSON.stringify({ ...data, activeFilters: filters, exportedAt: new Date().toISOString() }, null, 2), "application/json;charset=utf-8")
      toast.success("当前筛选视图已导出")
      return
    }
    if (type === "answers") {
      const columns: Array<keyof AnswerRecord> = ["recordId", "promptId", "platform", "modelVersion", "testedAt", "recordStatus", "keyword", "questionType", "scene", "region", "question", "answer", "mention", "recommendationPrompt", "recommend", "top3", "rank", "sentiment", "factPointsTotal", "factPointsCorrect", "accuracyNote", "judgedBy", "citationDetectable", "brandCited", "citationUrls", "conversationUrl", "evidenceUrl"]
      const rows = data.answers.map((answer) => columns.map((column) => {
        const entry = answer[column]
        return csvCell(Array.isArray(entry) ? entry.join("|") : entry)
      }).join(","))
      const csv = `\ufeff${columns.join(",")}\n${rows.join("\n")}`
      downloadText(`${base}_当前页回答证据.csv`, csv, "text/csv;charset=utf-8")
      toast.success("当前页回答证据已导出")
      return
    }
    if (type === "completion") {
      const columns = ["itemId", "category", "itemName", "unit", "contractQuantity", "qualifiedQuantity", "weight", "evidenceUrl", "note"] as const
      const csv = `\ufeff${columns.join(",")}\n${data.completion.map((item) => columns.map((column) => csvCell(item[column])).join(",")).join("\n")}`
      downloadText(`${base}_合同交付验收明细.csv`, csv, "text/csv;charset=utf-8")
      toast.success("合同交付验收明细已导出")
      return
    }
    const deliveryColumns = ["itemId", "title", "media", "mediaLevel", "originalUrl", "publishDate", "indexStatus", "citationStatus", "aiPlatforms"] as const
    const deliveryCsv = `\ufeff${deliveryColumns.join(",")}\n${data.deliveries.map((item) => deliveryColumns.map((column) => csvCell(Array.isArray(item[column]) ? item[column].join("|") : item[column])).join(",")).join("\n")}`
    downloadText(`${base}_交付内容与权威媒体链接.csv`, deliveryCsv, "text/csv;charset=utf-8")
    toast.success("交付清单与原文链接已导出")
  }

  const submitAcceptance = async () => {
    if (!data?.snapshot) return
    setAcceptancePending(true)
    try {
      const response = await fetch("/api/report", { method: "POST", headers: { "content-type": "application/json" }, body: JSON.stringify({ action: "submit-acceptance", snapshotId: data.snapshot.id, status: acceptanceStatus, comment: acceptanceComment }) })
      const result = await response.json() as { error?: string; message?: string }
      if (!response.ok) throw new Error(result.error ?? "验收提交失败")
      toast.success(result.message ?? "验收结论已提交")
      setAcceptanceOpen(false); setAcceptanceComment(""); setRefreshKey((current) => current + 1)
    } catch (reason) { toast.error(reason instanceof Error ? reason.message : "验收提交失败") }
    finally { setAcceptancePending(false) }
  }

  if (error && !data) return <div className="live-report-loading error"><CircleAlert/><strong>报告暂时无法读取</strong><span>{error}</span><Button variant="outline" onClick={() => setRefreshKey((current) => current + 1)}><RefreshCw/>重新读取</Button></div>
  if (!data) return <div className="live-report-loading"><LoaderCircle className="spin"/><strong>正在读取正式发布快照</strong><span>核对项目权限、公式口径与证据链…</span></div>

  const openAcceptance = () => { setAcceptanceStatus(data.snapshot?.acceptanceStatus === "disputed" ? "disputed" : "accepted"); setAcceptanceComment(""); setAcceptanceOpen(true) }
  const pages = [
    <Overview key="overview" data={data} onAcceptance={openAcceptance}/>,
    <Comparison key="comparison" data={data}/>,
    <Answers key="answers" data={data} onSelect={setSelectedAnswer} onPage={setPage}/>,
    <Competition key="competition" data={data}/>,
    <Demand key="demand" data={data}/>,
    <Execution key="execution" data={data}/>,
    <Deliveries key="deliveries" data={data}/>,
    <Formulas key="formulas" data={data}/>,
    <Risks key="risks" data={data}/>,
    <NextActions key="actions" data={data} onAcceptance={openAcceptance}/>,
  ]

  return <div className="live-report-root v8"><FilterBar data={data} filters={filters} loading={loading} onFilter={onFilter} onReset={resetFilters} onExport={exportView}/>{error ? <div className="live-inline-error"><CircleAlert/>{error}<Button variant="ghost" size="sm" onClick={() => setRefreshKey((current) => current + 1)}>重试</Button></div> : null}<div className="live-screen-module">{pages[activePage - 1] ?? pages[0]}</div><div className="live-print-modules">{pages.map((module, index) => <section key={reportPageTitles[index]}><header><span>{String(index + 1).padStart(2, "0")} / 10</span><strong>{reportPageTitles[index]}</strong><small>{data.project.brandName} · {data.snapshot?.reportMonth ?? "—"} · r{data.snapshot?.version ?? "—"}</small></header>{module}</section>)}</div><EvidenceSheet answer={selectedAnswer} onClose={() => setSelectedAnswer(null)}/><Dialog open={acceptanceOpen} onOpenChange={setAcceptanceOpen}><DialogContent><DialogHeader><DialogTitle>提交本期验收结论</DialogTitle><DialogDescription>结论将绑定 {data.snapshot ? `${data.snapshot.reportMonth}-r${data.snapshot.version}` : "当前"} 正式快照并进入项目审计记录。</DialogDescription></DialogHeader><div className="live-acceptance-options"><button className={acceptanceStatus === "accepted" ? "active" : ""} onClick={() => setAcceptanceStatus("accepted")}><CheckCircle2/><strong>确认验收</strong><span>已核对指标、交付链接与回答证据</span></button><button className={acceptanceStatus === "disputed" ? "active disputed" : ""} onClick={() => setAcceptanceStatus("disputed")}><CircleAlert/><strong>提交异议</strong><span>指出需要乙方复核或补证的具体问题</span></button></div><div><label htmlFor="acceptance-comment">验收备注{acceptanceStatus === "disputed" ? "（必填）" : "（选填）"}</label><Textarea id="acceptance-comment" value={acceptanceComment} onChange={(event) => setAcceptanceComment(event.target.value)} placeholder={acceptanceStatus === "disputed" ? "请填写指标、Prompt ID、回答记录ID或交付链接及具体问题" : "可记录品牌方确认范围和内部意见"}/></div>{data.acceptanceHistory.length ? <div className="live-acceptance-history"><span>历史提交</span>{data.acceptanceHistory.slice(0, 3).map((item) => <div key={item.id}><Badge variant="outline">{item.status === "accepted" ? "确认验收" : "验收异议"}</Badge><p>{item.comment || "未填写备注"}</p><small>{item.submittedBy} · {reportDate(item.submittedAt)}</small></div>)}</div> : null}<DialogFooter><Button variant="outline" onClick={() => setAcceptanceOpen(false)}>取消</Button><Button onClick={() => void submitAcceptance()} disabled={acceptancePending || (acceptanceStatus === "disputed" && !acceptanceComment.trim())}>{acceptancePending ? <LoaderCircle className="spin"/> : acceptanceStatus === "accepted" ? <CheckCircle2/> : <CircleAlert/>}{acceptanceStatus === "accepted" ? "确认本期验收" : "提交验收异议"}</Button></DialogFooter></DialogContent></Dialog></div>
}
