// Deterministic multiple-choice quiz generation from glossary entries. No model,
// NO randomness — given the same entries, the same quiz is produced every time
// (important for reproducible tests and stable UI across re-renders).
//
// IMPORTANT: relative imports only inside src/lib (vitest has no '@/*' alias).

import type { GlossaryEntry } from './glossary';

/** One MCQ: a definition prompt, term options, and the correct option index. */
export interface QuizQuestion {
  question: string;
  options: string[];
  answerIndex: number;
  /** Source start time (seconds). */
  start?: number;
  /** Source segment id. */
  segmentId?: string;
}

const OPTION_COUNT = 4;

/**
 * Generate up to `count` questions from `entries`.
 *
 * Requires at least {@link OPTION_COUNT} (4) distinct terms so every question
 * can have one correct answer + 3 distinct distractors; with fewer entries we
 * return [].
 *
 * Determinism: for question `i`, the correct answer is placed at index
 * `i % OPTION_COUNT`, and the remaining slots are filled with distractor terms
 * drawn from the OTHER entries by rotating through the list (offset by `i`), so
 * the layout is a pure function of the input order.
 */
export function generateQuiz(
  entries: GlossaryEntry[],
  opts?: { count?: number },
): QuizQuestion[] {
  const count = opts?.count ?? 8;
  if (entries.length < OPTION_COUNT || count <= 0) return [];

  const questions: QuizQuestion[] = [];
  const n = entries.length;
  const limit = Math.min(count, n);

  for (let i = 0; i < limit; i++) {
    const correct = entries[i];
    if (!correct) continue; // unreachable (i < limit <= n), satisfies the checker

    // Collect 3 distinct distractor terms from other entries, rotating the
    // start point by `i` so different questions get different wrong answers.
    const distractors: string[] = [];
    const seen = new Set<string>([correct.term.toLowerCase()]);
    let j = 1;
    while (distractors.length < OPTION_COUNT - 1 && j <= n) {
      const cand = entries[(i + j) % n];
      j++;
      if (!cand) continue;
      const key = cand.term.toLowerCase();
      if (!seen.has(key)) {
        seen.add(key);
        distractors.push(cand.term);
      }
    }

    // Defensive: if duplicate terms left us short, skip this question rather
    // than emit one with fewer than 4 options. (glossary() dedupes, so this is
    // effectively unreachable for real input.)
    if (distractors.length < OPTION_COUNT - 1) continue;

    // Place the answer at a deterministic index; fill the rest with distractors.
    const answerIndex = i % OPTION_COUNT;
    const options: string[] = [];
    let d = 0;
    for (let slot = 0; slot < OPTION_COUNT; slot++) {
      options.push(slot === answerIndex ? correct.term : (distractors[d++] as string));
    }

    questions.push({
      question: `Which term means: "${correct.definition}"?`,
      options,
      answerIndex,
      start: correct.start,
      segmentId: correct.segmentId,
    });
  }

  return questions;
}
