/**
 * Demo-room bots. Deterministic: the same seed + question always yields the same choice and delay,
 * so a replayed demo game is identical. Pass a per-bot seed (e.g. `${round.seed}:${botId}`).
 */
import { createRng, pick } from './rng';
import type { QuestionInput } from './types';

export interface BotDecisionInput {
  seed: string;
  question: QuestionInput;
  /** 0 (weak, slow) … 1 (strong, fast). */
  skill: number;
  /** Answer window of this question (windowFor). */
  windowMs: number;
}

export interface BotDecision {
  optionId: string;
  /** Delay after the question opens. */
  delayMs: number;
}

/** Bots never answer faster than a person could read the question. */
export const BOT_MIN_DELAY_MS = 1_500;
/** …and always leave a second of slack before the window closes. */
export const BOT_CLOSE_MARGIN_MS = 1_000;
const DIFFICULT_PENALTY = 0.15;

const clamp = (x: number, lo: number, hi: number): number => Math.min(hi, Math.max(lo, x));

/** Probability that a bot of `skill` answers correctly: 0.35 + 0.5·skill, lower for DIFFICULT. */
export function botAccuracy(skill: number, difficulty: QuestionInput['difficulty']): number {
  const s = clamp(Number.isFinite(skill) ? skill : 0, 0, 1);
  return clamp(0.35 + 0.5 * s - (difficulty === 'DIFFICULT' ? DIFFICULT_PENALTY : 0), 0.05, 0.95);
}

export function botDecision({ seed, question, skill, windowMs }: BotDecisionInput): BotDecision {
  const rng = createRng(`${seed}:${question.id}:bot`);
  const s = clamp(Number.isFinite(skill) ? skill : 0, 0, 1);
  const wrong = question.options.filter((o) => o.id !== question.correctOptionId);
  const correct = rng() < botAccuracy(s, question.difficulty) || wrong.length === 0;
  const optionId = correct ? question.correctOptionId : pick(wrong, rng).id;
  const min = BOT_MIN_DELAY_MS;
  const max = Math.max(min, windowMs - BOT_CLOSE_MARGIN_MS);
  // Skilled bots answer early; a random component keeps them from answering in lockstep.
  const fraction = clamp((1 - s) * 0.6 + rng() * 0.4, 0, 1);
  return { optionId, delayMs: Math.round(min + (max - min) * fraction) };
}
