import { describe, expect, test } from "vitest";

import { encodeAction, legalActionMask, resetFromOrder, step } from "./engine";
import { scoreBreakdown } from "./scoring";
import { DRAW_DECK, N_CARDS, PLAY } from "./types";
import { boardScore } from "./engine";

const orderedDeck = Array.from({ length: N_CARDS }, (_, index) => index);

describe("score breakdown", () => {
  test("an untouched board scores nothing everywhere", () => {
    const breakdown = scoreBreakdown(resetFromOrder(orderedDeck), 0);
    expect(breakdown.total).toBe(0);
    expect(breakdown.colors).toHaveLength(5);
    expect(breakdown.colors.every((color) => color.cards === 0 && color.score === 0)).toBe(true);
  });

  test("an opened expedition costs 20 and handshakes multiply it", () => {
    // Player 0 holds cards 0..7 of the red suit: three handshakes then 2,3,4,5.
    let state = resetFromOrder(orderedDeck);
    const mask = legalActionMask(state);
    expect(mask[encodeAction(0, PLAY, DRAW_DECK)]).toBe(true);
    state = step(state, encodeAction(0, PLAY, DRAW_DECK)); // red handshake

    const red = scoreBreakdown(state, 0).colors[0];
    expect(red.cards).toBe(1);
    expect(red.handshakes).toBe(1);
    expect(red.rankSum).toBe(0);
    // (0 - 20) * (1 + 1) = -40
    expect(red.score).toBe(-40);
  });

  test("totals agree with the engine's board score", () => {
    let state = resetFromOrder(orderedDeck);
    for (let ply = 0; ply < 12; ply += 1) {
      const action = legalActionMask(state).findIndex((legal, index) => legal && index % 6 === 0);
      state = step(state, action);
    }
    const engine = boardScore(state);
    expect(scoreBreakdown(state, 0).total).toBe(engine[0]);
    expect(scoreBreakdown(state, 1).total).toBe(engine[1]);
  });
});
