import { test } from 'node:test';
import assert from 'node:assert/strict';
import { Game, Games } from '../dist/game.js';

test('game rules: seats, ownership, turns, bounds, revision conflicts and immutable snapshots', () => {
    const game = new Game();
    assert.throws(() => game.snapshot('alice'), /Join/);
    game.join('alice'); game.join('alice');
    assert.throws(() => game.move('alice', 0, 0), /second/);
    game.join('bob');
    assert.throws(() => game.join('carol'), /full/);
    assert.throws(() => game.move('carol', 0, 0), /Join/);
    assert.throws(() => game.move('bob', 0, 0), /turn/);
    for (const cell of [-1, 9, 1.5, NaN]) assert.throws(() => game.move('alice', cell, 0), /empty/);
    const view = game.snapshot('alice'); view.board[0] = 'O'; view.players.push('eve');
    assert.equal(game.snapshot('alice').board[0], null);
    game.move('alice', 0, 0);
    assert.throws(() => game.move('bob', 1, 0), /changed/);
    assert.throws(() => game.move('bob', 0, 1), /empty/);
    game.move('bob', 1, 1);
    assert.equal(game.snapshot('bob').you, 'O');
});

test('every winning line, both marks, draws, and finished games', () => {
    const lines = [[0,1,2],[3,4,5],[6,7,8],[0,3,6],[1,4,7],[2,5,8],[0,4,8],[2,4,6]];
    for (const line of lines) {
        const game = new Game(); game.join('alice'); game.join('bob');
        const other = Array.from({ length: 9 }, (_, i) => i).filter(i => !line.includes(i));
        [line[0], other[0], line[1], other[1], line[2]].forEach((cell, revision) => game.move(revision % 2 ? 'bob' : 'alice', cell, revision));
        assert.equal(game.snapshot('alice').result, 'X');
        assert.throws(() => game.move('bob', other[2], 5), /finished/);
    }
    for (const [moves, result] of [[[0,3,1,4,8,5], 'O'], [[0,1,2,4,3,5,7,6,8], 'draw']]) {
        const game = new Game(); game.join('alice'); game.join('bob');
        moves.forEach((cell, revision) => game.move(revision % 2 ? 'bob' : 'alice', cell, revision));
        assert.equal(game.snapshot('bob').result, result);
    }
});

test('bounded rooms and authenticated, idempotent resume', () => {
    const games = new Games();
    assert.throws(() => games.resume('absent', 'alice'), /not found/);
    const game = games.join('room', 'alice');
    assert.equal(games.join('room', 'bob'), game);
    assert.equal(games.resume('room', 'alice'), game);
    assert.throws(() => games.resume('room', 'carol'), /Join/);
    for (let i = 1; i < 100; i++) games.join(String(i), 'alice');
    assert.throws(() => games.join('overflow', 'alice'), /capacity/);
});
