'use client';

import { useState } from 'react';
import { Check, Copy } from 'lucide-react';
import type { AiInvocationDetail } from '@pac/types';
import { Card, CardContent, CardDescription, CardHeader, CardTitle } from '@/components/ui/card';
import { Badge } from '@/components/ui/badge';
import { Button } from '@/components/ui/button';

/**
 * AI 调用详情:
 *  - 顶部 meta(callKey / promptVersion / model / status / tokens / cost / duration)
 *  - inputSnapshot(JSON formatted,可折叠)
 *  - promptTemplate(prompt 文本,代码块)
 *  - output(JSON formatted)
 *  - errorMessage / judge 评分(若有)
 */
export function AiInvocationDetailApp({ data }: { data: AiInvocationDetail }) {
  return (
    <main className="container mx-auto max-w-5xl space-y-4 p-6">
      <MetaCard data={data} />

      <JsonCard
        title="Input Snapshot"
        description="装配给 LLM 的结构化输入(replay 时的真理源)"
        value={data.inputSnapshot}
      />

      <TextCard
        title="Prompt 模板(实际发给模型的文本)"
        description="跟 inputSnapshot 装配后的最终 prompt;超 8000 字符会截断,审计时去 prompt 仓库按 promptVersion 反查更准"
        text={data.promptTemplate}
      />

      <JsonCard
        title="Output(结构化)"
        description="LLM 通过 Zod schema 强约束返的 JSON"
        value={data.output}
      />

      {data.outputText && (
        <TextCard title="Output(文本)" description="流式调用累计文本" text={data.outputText} />
      )}

      {data.errorMessage && (
        <Card>
          <CardHeader>
            <CardTitle className="text-rose-600">错误</CardTitle>
          </CardHeader>
          <CardContent>
            <pre className="text-xs text-rose-700 whitespace-pre-wrap font-mono">{data.errorMessage}</pre>
          </CardContent>
        </Card>
      )}

      {data.judgeScore !== null && (
        <Card>
          <CardHeader>
            <CardTitle>Judge 评分</CardTitle>
            <CardDescription>LLM-as-judge 对本次产出的打分</CardDescription>
          </CardHeader>
          <CardContent className="space-y-2">
            <div className="text-2xl font-semibold nums">{data.judgeScore.toFixed(2)} <span className="text-sm text-muted-foreground">/ 5</span></div>
            {data.judgeRubric != null && <JsonBlock value={data.judgeRubric} maxHeight="20rem" />}
          </CardContent>
        </Card>
      )}
    </main>
  );
}

// ─────────────────────────────────────────────
// Meta(顶部 metadata 卡)
// ─────────────────────────────────────────────

function MetaCard({ data }: { data: AiInvocationDetail }) {
  // cache hit / reasoning 占比(同 prompt 反复调,hit 越高省钱越多;reasoning 越高说明模型"内部思考"占用)
  const cacheHitPct =
    data.promptTokens > 0 ? (data.cachedInputTokens / data.promptTokens) * 100 : 0;
  const reasoningPct =
    data.completionTokens > 0 ? (data.reasoningTokens / data.completionTokens) * 100 : 0;
  const textTokens = Math.max(0, data.completionTokens - data.reasoningTokens);

  const items: Array<{ label: string; value: React.ReactNode; mono?: boolean }> = [
    { label: 'callKey', value: <code className="text-xs">{data.callKey}</code> },
    { label: 'promptVersion', value: <code className="text-xs">{data.promptVersion}</code>, mono: true },
    { label: '模型', value: `${data.modelProvider}/${data.modelName}`, mono: true },
    { label: '状态', value: <StatusPill status={data.status} /> },
    { label: 'evalMode', value: data.evalMode },
    { label: '本地 cache', value: data.cacheHit ? '命中 (PAC 进程内)' : '未命中' },
    {
      label: 'Input tokens',
      value: (
        <span className="nums text-xs">
          {data.promptTokens}
          {data.cachedInputTokens > 0 && (
            <span className="ml-1 text-emerald-600">
              (vendor cache hit {data.cachedInputTokens} · {cacheHitPct.toFixed(0)}%)
            </span>
          )}
        </span>
      ),
    },
    {
      label: 'Output tokens',
      value: (
        <span className="nums text-xs">
          {data.completionTokens}
          {data.reasoningTokens > 0 && (
            <span className="ml-1 text-amber-600">
              (text {textTokens} + thinking {data.reasoningTokens} · {reasoningPct.toFixed(0)}%)
            </span>
          )}
        </span>
      ),
    },
    { label: '成本(估算)', value: `¥${data.costYuan.toFixed(6)}` },
    { label: '耗时', value: data.durationMs !== null ? `${data.durationMs} ms` : '—' },
    { label: '开始', value: data.startedAt.slice(0, 19).replace('T', ' '), mono: true },
    { label: '结束', value: data.endedAt ? data.endedAt.slice(0, 19).replace('T', ' ') : '—', mono: true },
    { label: 'workflowRun', value: <code className="text-[10.5px]">{data.workflowRunId.slice(0, 8)}…</code> },
    {
      label: '关联',
      value: (
        <span className="text-xs nums">
          {data.linkedPlanId ? `plan ${data.linkedPlanId.slice(0, 8)}…` : '—'}
          {data.linkedPatientId ? ` · patient ${data.linkedPatientId.slice(0, 8)}…` : ''}
        </span>
      ),
    },
  ];

  return (
    <Card>
      <CardHeader>
        <CardTitle className="flex items-center gap-2">
          <span>{data.callKey}</span>
          <Badge variant="outline" className="font-mono text-[10.5px] font-normal">
            {data.promptVersion}
          </Badge>
        </CardTitle>
        <CardDescription className="font-mono text-[10.5px]">id: {data.id}</CardDescription>
      </CardHeader>
      <CardContent>
        <dl className="grid grid-cols-3 gap-x-4 gap-y-3 text-sm">
          {items.map((it) => (
            <div key={it.label}>
              <dt className="text-xs text-muted-foreground">{it.label}</dt>
              <dd className={'mt-0.5 ' + (it.mono ? 'font-mono text-xs' : '')}>{it.value}</dd>
            </div>
          ))}
        </dl>
      </CardContent>
    </Card>
  );
}

// ─────────────────────────────────────────────
// JsonCard / TextCard / JsonBlock
// ─────────────────────────────────────────────

function JsonCard({ title, description, value }: { title: string; description?: string; value: unknown }) {
  return (
    <Card>
      <CardHeader>
        <CardTitle>{title}</CardTitle>
        {description && <CardDescription>{description}</CardDescription>}
      </CardHeader>
      <CardContent>
        <JsonBlock value={value} />
      </CardContent>
    </Card>
  );
}

function TextCard({ title, description, text }: { title: string; description?: string; text: string | null }) {
  if (!text) {
    return (
      <Card>
        <CardHeader>
          <CardTitle>{title}</CardTitle>
          {description && <CardDescription>{description}</CardDescription>}
        </CardHeader>
        <CardContent>
          <div className="text-xs text-muted-foreground">(无内容)</div>
        </CardContent>
      </Card>
    );
  }
  return (
    <Card>
      <CardHeader className="flex flex-row items-center justify-between space-y-0">
        <div>
          <CardTitle>{title}</CardTitle>
          {description && <CardDescription>{description}</CardDescription>}
        </div>
        <CopyButton text={text} />
      </CardHeader>
      <CardContent>
        <pre className="max-h-[32rem] overflow-auto rounded-md surface-inset p-3 text-xs font-mono leading-relaxed whitespace-pre-wrap">
          {text}
        </pre>
      </CardContent>
    </Card>
  );
}

function JsonBlock({ value, maxHeight = '32rem' }: { value: unknown; maxHeight?: string }) {
  const json = JSON.stringify(value, null, 2);
  return (
    <div className="space-y-2">
      <div className="flex justify-end">
        <CopyButton text={json} />
      </div>
      <pre
        className="overflow-auto rounded-md surface-inset p-3 text-xs font-mono leading-relaxed"
        style={{ maxHeight }}
      >
        {json}
      </pre>
    </div>
  );
}

function CopyButton({ text }: { text: string }) {
  const [copied, setCopied] = useState(false);
  const copy = () => {
    navigator.clipboard?.writeText(text);
    setCopied(true);
    setTimeout(() => setCopied(false), 1500);
  };
  return (
    <Button variant="outline" size="sm" onClick={copy}>
      {copied ? <><Check className="h-3.5 w-3.5" /> 已复制</> : <><Copy className="h-3.5 w-3.5" /> 复制</>}
    </Button>
  );
}

function StatusPill({ status }: { status: string }) {
  const tones: Record<string, string> = {
    succeeded: 'bg-emerald-100 text-emerald-700',
    failed: 'bg-rose-100 text-rose-700',
    cached: 'bg-slate-100 text-slate-700',
    running: 'bg-sky-100 text-sky-700',
  };
  return (
    <span className={'inline-block rounded px-1.5 py-0.5 text-xs font-medium ' + (tones[status] ?? 'bg-slate-100 text-slate-700')}>
      {status}
    </span>
  );
}
