import { describe, expect, it } from 'vitest';
import { EventBus } from '../src/core/EventBus';
import { GameClock, ageOn, type ClockConfig } from '../src/core/GameClock';

const FAST: ClockConfig = { nightClockMinutes: 360, nightRealMinutes: 13, nightDate: '2026-07-18' };

describe('GameClock', () => {
  it('emits one tick per in-game minute, in order', () => {
    const bus = new EventBus();
    const ticks: number[] = [];
    bus.on('clock:tick', ({ clockMin }) => ticks.push(clockMin));
    const clock = new GameClock(bus, FAST);
    clock.start();
    const msPerClockMin = (FAST.nightRealMinutes * 60_000) / FAST.nightClockMinutes;
    for (let i = 0; i < 50; i++) clock.update(msPerClockMin / 5); // uneven small steps
    expect(ticks).toEqual(Array.from({ length: ticks.length }, (_, i) => i));
    expect(clock.clockMin).toBe(ticks[ticks.length - 1]);
  });

  it('does not advance while paused or before start', () => {
    const bus = new EventBus();
    const clock = new GameClock(bus, FAST);
    clock.update(10_000);
    expect(clock.clockMin).toBe(0);
    clock.start();
    clock.update(5_000);
    const at = clock.clockMin;
    clock.pause();
    clock.update(60_000);
    expect(clock.clockMin).toBe(at);
  });

  it('caps at night end', () => {
    const bus = new EventBus();
    const clock = new GameClock(bus, FAST);
    clock.start();
    clock.update(FAST.nightRealMinutes * 60_000 * 3);
    expect(clock.clockMin).toBe(360);
    expect(clock.isOver).toBe(true);
  });

  it('formats the label from a 9 PM start', () => {
    const bus = new EventBus();
    const clock = new GameClock(bus, FAST);
    expect(clock.label).toBe('9:00 PM');
  });
});

describe('ageOn (the ID birthday math)', () => {
  const night = new Date('2026-07-18T00:00:00');

  it('18th birthday IS tonight → 18 (they get in)', () => {
    expect(ageOn('2008-07-18', night)).toBe(18);
  });

  it('18th birthday is tomorrow → 17 (denied, so close)', () => {
    expect(ageOn('2008-07-19', night)).toBe(17);
  });

  it('birthday was yesterday → 18', () => {
    expect(ageOn('2008-07-17', night)).toBe(18);
  });

  it('leap-day DOB counts the year correctly', () => {
    expect(ageOn('2008-02-29', night)).toBe(18);
    expect(ageOn('2008-02-29', new Date('2026-02-28T00:00:00'))).toBe(17);
    expect(ageOn('2008-02-29', new Date('2026-03-01T00:00:00'))).toBe(18);
  });
});
