import { describe, it, expect } from 'vitest';
import { activeByKind, capFor, isKindLocked } from './gamelimits';
import { GameKind, type GameView, type GameLimits } from './model';

// game builds a minimal GameView for the count: only kind, status and (optionally) hotseat matter.
function game(kind: number, status: string, extra: Partial<GameView> = {}): GameView {
  return {
    id: 'g',
    variant: 'scrabble_en',
    dictVersion: '',
    status,
    players: 2,
    toMove: 0,
    turnTimeoutSecs: 0,
    multipleWordsPerTurn: true,
    noRepeatWords: false,
    moveCount: 0,
    endReason: '',
    lastActivityUnix: 0,
    vsAi: false,
    unreadChat: false,
    unreadMessages: false,
    kind,
    seats: [],
    ...extra,
  };
}

describe('activeByKind', () => {
  it('counts open+active games per kind, skipping finished, hotseat and untagged (kind 0)', () => {
    const by = activeByKind([
      game(GameKind.vsAi, 'active'),
      game(GameKind.random, 'open'),
      game(GameKind.random, 'active'),
      game(GameKind.random, 'finished'), // finished → not counted
      game(GameKind.vsAi, 'active', { hotseat: true }), // local pass-and-play → not counted
      game(0, 'active'), // pre-existing / untagged → not counted
    ]);
    expect(by[GameKind.vsAi]).toBe(1);
    expect(by[GameKind.random]).toBe(2);
  });
});

describe('capFor', () => {
  const limits: GameLimits = { vsAi: 1, random: 10, friends: 0 };
  it('maps each kind to its tier cap; unknown kind and absent limits are unlimited (-1)', () => {
    expect(capFor(limits, GameKind.vsAi)).toBe(1);
    expect(capFor(limits, GameKind.random)).toBe(10);
    expect(capFor(limits, GameKind.friends)).toBe(0);
    expect(capFor(limits, 0)).toBe(-1);
    expect(capFor(undefined, GameKind.vsAi)).toBe(-1);
  });
});

describe('isKindLocked', () => {
  const guest: GameLimits = { vsAi: 1, random: 1, friends: 0 };
  const durable: GameLimits = { vsAi: 10, random: 10, friends: 10 };

  it('locks a guest at the per-kind cap, not another kind', () => {
    const games = [game(GameKind.vsAi, 'active')];
    expect(isKindLocked(games, guest, GameKind.vsAi)).toBe(true);
    expect(isKindLocked(games, guest, GameKind.random)).toBe(false);
  });

  it('a cap of 0 always locks (a guest cannot start friend games)', () => {
    expect(isKindLocked([], guest, GameKind.friends)).toBe(true);
  });

  it('an unlimited cap (-1) or absent limits never lock', () => {
    const many = [game(GameKind.random, 'active'), game(GameKind.random, 'active')];
    expect(isKindLocked(many, { vsAi: -1, random: -1, friends: -1 }, GameKind.random)).toBe(false);
    expect(isKindLocked(many, undefined, GameKind.random)).toBe(false);
  });

  it('a durable account stays well under its higher cap', () => {
    expect(isKindLocked([game(GameKind.random, 'active')], durable, GameKind.random)).toBe(false);
  });

  it('locks only the reached kind: at the vs_ai cap, random with no games stays open', () => {
    const limits = { vsAi: 3, random: 2, friends: 1 };
    const games = [game(GameKind.vsAi, 'active'), game(GameKind.vsAi, 'active'), game(GameKind.vsAi, 'active')];
    expect(isKindLocked(games, limits, GameKind.vsAi)).toBe(true);
    expect(isKindLocked(games, limits, GameKind.random)).toBe(false);
    expect(isKindLocked(games, limits, GameKind.friends)).toBe(false);
  });
});
