import type { ModelCall } from '@/lib/demo-kit/types';
import { cn } from '@/lib/utils';
import { DASH, formatInt, formatMs, humaniseToken } from './format';

export interface ModelCallPanelProps {
  call: ModelCall | null;
  /** The model's visible reply for this step, verbatim. */
  reply?: string | null;
  className?: string;
  title?: string;
}

interface Row {
  label: string;
  value: string;
  hint?: string;
}

/**
 * The model call, straight off the trace.
 *
 * Nothing here is computed, averaged or estimated. Every field is a value the
 * recorder wrote down, and a field the recorder did not write down renders as
 * an em dash — never as zero, and never quietly omitted. A provider that does
 * not report reasoning tokens is a fact about the trace, and hiding the row
 * would turn "we do not know" into "there were none".
 */
export function ModelCallPanel({
  call,
  reply = null,
  className,
  title = 'Model call',
}: ModelCallPanelProps) {
  const rows: Row[] = [
    {
      label: 'prompt tokens',
      value: formatInt(call?.promptTokens ?? null),
      hint: 'Everything sent in: system, board, history',
    },
    {
      label: 'completion tokens',
      value: formatInt(call?.completionTokens ?? null),
      hint: 'The visible reply',
    },
    {
      label: 'reasoning tokens',
      value: formatInt(call?.reasoningTokens ?? null),
      hint: 'Billed thinking, when the provider reports it',
    },
    {
      label: 'duration',
      value: formatMs(call?.durationMs ?? null),
      hint: 'Real elapsed time when the run was recorded',
    },
    {
      label: 'finish reason',
      value: call?.finishReason ? humaniseToken(call.finishReason) : DASH,
      hint: 'Why the model stopped generating',
    },
  ];

  return (
    <section
      aria-label={title}
      className={cn('overflow-hidden rounded-lg border border-border bg-surface-2', className)}
    >
      <header className="border-b border-border px-3 py-2">
        <h3 className="font-mono text-label uppercase tracking-label text-muted">{title}</h3>
      </header>
      {call === null ? (
        <p className="max-w-measure px-3 py-3 text-prose text-muted">
          This step did not involve a model call — it is a state change the environment made on
          its own.
        </p>
      ) : (
        <dl className="grid grid-cols-[auto_minmax(0,1fr)] gap-x-4 px-3 py-1.5 font-mono text-mono-data">
          {rows.map((row) => (
            <div key={row.label} className="col-span-2 grid grid-cols-subgrid items-baseline py-1">
              <dt className="text-label uppercase tracking-label text-muted" title={row.hint}>
                {row.label}
              </dt>
              <dd className="text-right text-fg">{row.value}</dd>
            </div>
          ))}
        </dl>
      )}

      {reply ? (
        <div className="border-t border-border">
          <h4 className="px-3 pt-2 font-mono text-label uppercase tracking-label text-muted">Reply</h4>
          <pre className="m-3 mt-1.5 overflow-x-auto whitespace-pre-wrap break-words rounded-md border border-border bg-surface-3 p-2.5 font-mono text-caption leading-relaxed text-fg [font-feature-settings:'liga'_0]">
            {reply}
          </pre>
        </div>
      ) : null}
    </section>
  );
}
