import type { DemoEpisode, DemoStep } from '@/lib/demo-kit';

import { announceRow, scoreGuess, type BoardState, type Pattern } from './engine';
import { parseGuess } from './parse';

/**
 * A recorded episode becomes a list of board snapshots.
 *
 * Snapshots, not deltas: the scrubber lets you jump to any step, and rebuilding
 * state by replaying deltas from zero on every seek is both slower and the kind
 * of thing that goes subtly wrong when a step is skipped.
 */
export function adapt(episode: DemoEpisode): DemoStep<BoardState>[] {
  const answer = (episode as DemoEpisode & { answer?: string }).answer ?? '';
  const rows: { guess: string; pattern: Pattern }[] = [];
  let rejected = 0;

  return episode.turns.map((turn, index) => {
    const guess = parseGuess(turn.reply);
    let announce: string;
    let caption: string | undefined;

    const alreadyPlayed = guess !== null && rows.some((r) => r.guess === guess);
    const legal = guess !== null && guess.length === 5 && !alreadyPlayed;

    if (!legal) {
      rejected += 1;
      const why =
        guess === null
          ? 'no guess found in the reply'
          : alreadyPlayed
            ? `repeated ${guess.toUpperCase()}`
            : `${guess.toUpperCase()} is not five letters`;
      announce = `Turn ${index + 1} refused: ${why}.`;
      caption = why;
    } else {
      const pattern = scoreGuess(guess, answer);
      rows.push({ guess, pattern });
      announce = announceRow(guess, pattern);
      caption =
        pattern === 'GGGGG'
          ? 'solved'
          : `${[...pattern].filter((t) => t === 'G').length} placed, ${
              [...pattern].filter((t) => t === 'Y').length
            } present`;
    }

    const won = rows.length > 0 && rows[rows.length - 1]!.pattern === 'GGGGG';

    return {
      index,
      state: {
        seed: episode.seed,
        answer,
        rows: rows.map((r) => ({ ...r })),
        draft: '',
        rejected,
        status: won ? 'won' : rows.length >= 6 ? 'lost' : 'playing',
        invalid: legal ? null : announce,
        hardMode: false,
      },
      reply: turn.reply,
      reasoning: turn.reasoning,
      call: turn.call,
      announce,
      caption,
    };
  });
}
