import { describe, expect, it } from 'vitest';
import { BOT_MIN_DELAY_MS, botAccuracy, botDecision } from '../src/index';
import { CATS, makePack, mcQuestion } from './helpers';

const questions = makePack(CATS, 40, 'b').questions;

function stats(skill: number, difficulty?: 'STANDARD' | 'DIFFICULT') {
  let correct = 0;
  let delay = 0;
  let n = 0;
  for (const q0 of questions) {
    const q = difficulty ? { ...q0, difficulty } : q0;
    const d = botDecision({ seed: `bot-${skill}`, question: q, skill, windowMs: 15_000 });
    if (d.optionId === q.correctOptionId) correct++;
    delay += d.delayMs;
    n++;
  }
  return { accuracy: correct / n, meanDelay: delay / n };
}

describe('botDecision', () => {
  it('is deterministic per seed + question', () => {
    const q = mcQuestion('q1', 'pop');
    const a = botDecision({ seed: 'bot', question: q, skill: 0.5, windowMs: 15_000 });
    expect(botDecision({ seed: 'bot', question: q, skill: 0.5, windowMs: 15_000 })).toEqual(a);
    const others = new Set(Array.from({ length: 20 }, (_, i) => JSON.stringify(botDecision({ seed: `bot-${i}`, question: q, skill: 0.5, windowMs: 15_000 }))));
    expect(others.size).toBeGreaterThan(1);
  });

  it('always picks a real option and answers between 1.5 s and window − 1 s', () => {
    for (const q of questions.slice(0, 100)) {
      for (const skill of [0, 0.3, 0.7, 1]) {
        const d = botDecision({ seed: 's', question: q, skill, windowMs: 20_000 });
        expect(q.options.map((o) => o.id)).toContain(d.optionId);
        expect(d.delayMs).toBeGreaterThanOrEqual(BOT_MIN_DELAY_MS);
        expect(d.delayMs).toBeLessThanOrEqual(19_000);
        expect(Number.isInteger(d.delayMs)).toBe(true);
      }
    }
    expect(botDecision({ seed: 's', question: questions[0]!, skill: 0.5, windowMs: 2_000 }).delayMs).toBe(BOT_MIN_DELAY_MS);
  });

  it('accuracy ≈ 0.35 + 0.5·skill, lower on DIFFICULT; skilled bots are faster', () => {
    expect(botAccuracy(0, 'STANDARD')).toBeCloseTo(0.35);
    expect(botAccuracy(1, 'STANDARD')).toBeCloseTo(0.85);
    expect(botAccuracy(1, 'DIFFICULT')).toBeLessThan(botAccuracy(1, 'STANDARD'));
    const weak = stats(0.1, 'STANDARD');
    const strong = stats(0.9, 'STANDARD');
    expect(Math.abs(weak.accuracy - botAccuracy(0.1, 'STANDARD'))).toBeLessThan(0.06);
    expect(Math.abs(strong.accuracy - botAccuracy(0.9, 'STANDARD'))).toBeLessThan(0.06);
    expect(stats(0.9, 'DIFFICULT').accuracy).toBeLessThan(strong.accuracy);
    expect(strong.meanDelay).toBeLessThan(weak.meanDelay);
  });
});
