/**
 * The two word lists, loaded the way each is actually used.
 *
 * `answers` is inlined: the board needs it before first paint to turn a seed
 * into a hidden word, and a fetch there would mean a visible empty board on a
 * cold cache. At 4,603 words it costs about 14 kB gzipped inside this demo's
 * lazy chunk, and never touches the entry chunk.
 *
 * `guesses` is fetched. It is nearly three times larger, and it is only needed
 * the first time somebody presses Enter — by which point it has long arrived.
 * Until it does, `isAllowed` falls back to the answer list, which accepts
 * strictly fewer words: the failure mode is "your real word was rejected for a
 * moment", not "a non-word was accepted", and that is the right way round.
 */

import answersJson from '../../../envs/wordle_five/words/answers.json';

export const ANSWERS: readonly string[] = answersJson;

let guesses: Set<string> | null = null;
let inFlight: Promise<Set<string>> | null = null;

/** Kick off the guess-list fetch. Safe to call more than once. */
export function primeGuessList(): Promise<Set<string>> {
  if (guesses) return Promise.resolve(guesses);
  if (!inFlight) {
    inFlight = fetch('/words/guesses.json')
      .then((r) => (r.ok ? r.json() : Promise.reject(new Error(String(r.status)))))
      .then((words: string[]) => {
        guesses = new Set(words);
        return guesses;
      })
      .catch(() => {
        // Degrade to the answer list rather than blocking play. A demo that
        // shows an error card because a 106 kB asset was slow would be a worse
        // failure than a briefly stricter dictionary.
        guesses = new Set(ANSWERS);
        return guesses;
      });
  }
  return inFlight;
}

/** The set currently available for validation. Never null. */
export function allowedNow(): ReadonlySet<string> {
  return guesses ?? new Set(ANSWERS);
}

export function guessListReady(): boolean {
  return guesses !== null;
}
