/**
 * Quick HEAD_TO_HEAD: new AI vs legacy AI — 20 seeds × 2 seat swaps = 40 matches each.
 * Run with: tsx src/game/ai-h2h-quick.ts
 */

import { chooseMove } from './ai';
import { chooseMove as chooseMoveOld } from './ai-legacy';
import { CardTracker } from './card-tracker';
import { CardInferenceEngine } from './card-inference';
import { applyMove, teamOf, nextPlayer, createInitialState, getMatchOutcome } from './engine';
import { AIMove, Difficulty, GameState, PlayerIndex } from './types';

// ---- seeded RNG -------------------------------------------------------
function mulberry32(seed: number): () => number {
  let s = seed >>> 0;
  return () => {
    s = (s + 0x6d2b79f5) >>> 0;
    let t = Math.imul(s ^ (s >>> 15), s | 1);
    t ^= t + Math.imul(t ^ (t >>> 7), t | 61);
    return ((t ^ (t >>> 14)) >>> 0) / 4294967296;
  };
}
function seedFromParts(...parts: number[]): number {
  let h = 2166136261;
  for (const p of parts) { h ^= p >>> 0; h = Math.imul(h, 16777619); }
  return h >>> 0;
}

// ---- simulated timing (same as benchmark) ----------------------------
function simulatedTiming() {
  let t = 0;
  return {
    now: () => t,
    advance: (ms: number) => { t += ms; return t; },
    isSimulated: true as const,
  };
}

// ---- single match ----------------------------------------------------
async function runMatch(
  difficulty: Difficulty,
  seed: number,
  newAITeam: 0 | 1,
): Promise<'new' | 'old' | 'draw'> {
  const SUITE_KEY = 0xabcd1234;
  const MAX_ROUNDS = 20;
  const initialDealer = (seed % 4) as PlayerIndex;
  let state = createInitialState(
    initialDealer,
    mulberry32(seedFromParts(SUITE_KEY, seed, 1, 0)),
  );
  const matchStartingPlayer = state.matchStartingPlayer;
  const tracker = new CardTracker();
  const inference = new CardInferenceEngine(tracker);
  let rounds = 1;
  let turn = 0;

  while (rounds <= MAX_ROUNDS) {
    while (!state.roundOver) {
      const playerIdx = state.currentPlayer;
      const isNew = teamOf(playerIdx) === newAITeam;
      const timing = simulatedTiming();
      const rng = mulberry32(seedFromParts(SUITE_KEY, seed, rounds, turn, playerIdx));

      const move: AIMove = isNew
        ? await chooseMove(state, playerIdx, difficulty, tracker, undefined, { rng, timingSource: timing, inference })
        : await chooseMoveOld(state, playerIdx, difficulty, tracker, undefined, { rng, timingSource: timing });

      const tableBeforeMove = [...state.table];
      const { nextState, capture } = applyMove(
        state, playerIdx, move.card,
        move.capture.length > 0 ? move.capture : undefined,
      );
      tracker.trackPlay(move.card);
      if (capture) tracker.trackCapture(capture.captured);
      inference.onMove(playerIdx, move, tableBeforeMove);
      state = nextState;
      turn++;
    }

    const outcome = getMatchOutcome(state.teamScores);
    if (!outcome.continueMatch) break;
    if (rounds === MAX_ROUNDS) break;

    rounds++;
    const totals: [number, number] = [state.teamScores[0].totalPoints, state.teamScores[1].totalPoints];
    tracker.reset();
    inference.reset();
    state = createInitialState(
      nextPlayer(state.dealer),
      mulberry32(seedFromParts(SUITE_KEY, seed, rounds, 0)),
    );
    state.matchStartingPlayer = matchStartingPlayer;
    state.teamScores[0].totalPoints = totals[0];
    state.teamScores[1].totalPoints = totals[1];
    state.roundNumber = rounds;
  }

  const outcome = getMatchOutcome(state.teamScores);
  if (outcome.winner === null) return 'draw';
  return outcome.winner === newAITeam ? 'new' : 'old';
}

// ---- main ------------------------------------------------------------
async function main() {
  const SEEDS = Array.from({ length: 20 }, (_, i) => 3000 + i);
  const SWAPS = [0, 1] as const;

  for (const difficulty of ['master', 'advanced'] as Difficulty[]) {
    let wins = 0, losses = 0, draws = 0;
    const total = SEEDS.length * SWAPS.length;

    console.log(`\nH2H ${difficulty.toUpperCase()} — ${total} matches`);

    for (const seed of SEEDS) {
      for (const newAITeam of SWAPS) {
        const result = await runMatch(difficulty, seed, newAITeam);
        if (result === 'new') wins++;
        else if (result === 'old') losses++;
        else draws++;

        const done = wins + losses + draws;
        if (done === 1 || done % 10 === 0 || done === total) {
          const pct = ((wins / done) * 100).toFixed(1);
          console.log(`  [${done}/${total}] new=${wins} old=${losses} draw=${draws} new-win%=${pct}%`);
        }
      }
    }

    const target = difficulty === 'master' ? 60 : 55;
    const winRate = (wins / total) * 100;
    const pass = winRate >= target;
    console.log(`RESULT: new AI wins ${winRate.toFixed(1)}% — target ≥${target}% — ${pass ? '✓ PASS' : '✗ FAIL'}`);
  }
}

main().catch(console.error);
