/**
 * The board, and the state it renders.
 *
 * One component does all three jobs — the visitor playing, the recorded
 * replay, and the gallery thumbnail (`compact`) — because three near-identical
 * boards is how they drift apart. The shell never inspects `__Pascal__State`;
 * it only ever hands one back.
 *
 * Nothing here may import `@/components/demo/*` or reach inside
 * `@/lib/demo-kit`. `scripts/check-demos.mjs` rule 9 enforces it.
 */

import { memo } from 'react';

import { cn } from '@/lib/utils';

/** One row of the queue the agent is triaging. */
export interface QueueItem {
  id: string;
  label: string;
  /** 0–1, as the environment scored it. Rendered, never used to decide. */
  risk: number;
  /** True when this row genuinely needed a person. The grader's ground truth. */
  needsPerson: boolean;
}

/** The board after a step. Steps are snapshots, not deltas. */
export interface __Pascal__State {
  seed: number;
  items: QueueItem[];
  /** Item ids the agent has escalated so far, in the order it escalated them. */
  escalated: string[];
  /** Set once the episode ends; `pending` while it is still running. */
  outcome: 'pending' | 'solved' | 'failed';
}

/** A fresh board for a seed. Deterministic in the seed — the shell relies on it. */
export function empty__Pascal__(seed: number): __Pascal__State {
  return { seed, items: [], escalated: [], outcome: 'pending' };
}

function Row({ item, escalated, compact }: { item: QueueItem; escalated: boolean; compact?: boolean }) {
  return (
    <li
      className={cn(
        'flex items-center justify-between gap-3 rounded-md border px-3 py-2',
        compact ? 'text-[11px]' : 'text-sm',
        escalated ? 'border-accent bg-surface-2 text-fg' : 'border-border text-muted',
      )}
    >
      <span className="truncate">{item.label}</span>
      {/* A colour-only distinction fails a projector, deuteranopia and a
          black-and-white printout, so the state is also a word. */}
      <span className="shrink-0 font-mono tabular-nums">
        {escalated ? 'escalated' : 'left alone'}
      </span>
    </li>
  );
}

function Board({ state, compact }: { state: __Pascal__State; compact?: boolean }) {
  const escalated = new Set(state.escalated);

  if (state.items.length === 0) {
    return (
      <p className={cn('text-muted', compact ? 'text-[11px]' : 'text-sm')}>
        Nothing in the queue yet.
      </p>
    );
  }

  return (
    <ul className={cn('flex flex-col', compact ? 'gap-1' : 'gap-2')}>
      {state.items.map((item) => (
        <Row key={item.id} item={item} escalated={escalated.has(item.id)} compact={compact} />
      ))}
    </ul>
  );
}

export default memo(Board);
