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

import { adapt } from './adapter';
import { answerForSeed, emptyBoard, type BoardState } from './engine';
import Keyboard from './keyboard';
import meta from './meta';
import { narrative } from './narrative';
import { parseGuess } from './parse';
import { recompute, reward } from './reward';
import Board from './surface';
import { ANSWERS } from './words';

export default defineDemo<BoardState>({
  meta,
  narrative,
  reward,
  anatomy: {
    task: 'Find a hidden five-letter word in six guesses.',
    actions:
      'One five-letter word per turn, from a fixed 11,846-word list. Anything else is refused and costs a turn.',
    grader:
      'Compares the guess to the answer letter by letter and returns green, yellow or grey. It computes; it does not judge.',
    score:
      'Half for winning, a third for winning quickly, a fifth for never spending a turn on a word that could not have won.',
  },
  provenance: {
    envPackage: 'wordle_five',
    tasksetId: 'wordle-five',
    verifiersVersion: '0.3.2.dev12',
    command: 'uv run python envs/probe.py',
    credits: [
      {
        label: 'prime-rl — Wordle as a starter example',
        href: 'https://github.com/PrimeIntellect-ai/prime-rl/tree/main/examples/basic/wordle',
      },
      {
        label: 'verifiers — the wordle environment',
        href: 'https://github.com/PrimeIntellect-ai/verifiers/tree/main/environments/wordle',
      },
      {
        label: 'TextArena — the engine those wrap',
        href: 'https://github.com/LeonGuertler/TextArena',
      },
      {
        label: 'Our word lists and how they were built',
        href: 'https://git.karti.ai/PIG/PIG-Demo/src/branch/main/envs/wordle_five/words/PROVENANCE.md',
      },
    ],
  },
  adapt,
  Surface: Board,
  interactive: {
    init: (seed: number) => emptyBoard(seed, answerForSeed(seed, ANSWERS)),
    Controls: Keyboard,
  },
  /**
   * Re-derive the score from the recorded moves.
   *
   * This is what the verify badge renders. It deliberately reads
   * `reference_depth` off the recorded metrics rather than recomputing it — the
   * reference depth comes from a search the browser has no business running,
   * and a missing one makes the run *unverifiable* rather than wrong.
   */
  verify: (episode: DemoEpisode): RewardValues | null => {
    const answer = (episode as DemoEpisode & { answer?: string }).answer;
    if (!answer) return null;

    const guesses: string[] = [];
    let rejected = 0;
    for (const turn of episode.turns) {
      const guess = parseGuess(turn.reply);
      if (guess === null || guess.length !== 5 || guesses.includes(guess)) {
        rejected += 1;
        continue;
      }
      guesses.push(guess);
    }

    const depth = episode.metrics?.['reference_depth'];
    return recompute(answer, guesses, rejected, typeof depth === 'number' ? depth : null);
  },
});
