import { describe, expect, it, vi } from 'vitest';
import { EventBus } from '../src/core/EventBus';

describe('EventBus', () => {
  it('delivers typed payloads to subscribers', () => {
    const bus = new EventBus();
    const fn = vi.fn();
    bus.on('clock:tick', fn);
    bus.emit('clock:tick', { clockMin: 5 });
    expect(fn).toHaveBeenCalledWith({ clockMin: 5 });
  });

  it('on() returns an unsubscribe function', () => {
    const bus = new EventBus();
    const fn = vi.fn();
    const off = bus.on('clock:tick', fn);
    off();
    bus.emit('clock:tick', { clockMin: 1 });
    expect(fn).not.toHaveBeenCalled();
  });

  it('once() fires exactly once', () => {
    const bus = new EventBus();
    const fn = vi.fn();
    bus.once('clock:tick', fn);
    bus.emit('clock:tick', { clockMin: 1 });
    bus.emit('clock:tick', { clockMin: 2 });
    expect(fn).toHaveBeenCalledTimes(1);
  });

  it('unsubscribing a later handler during emit prevents its delivery', () => {
    const bus = new EventBus();
    const calls: string[] = [];
    let offB: () => void = () => {};
    bus.on('clock:tick', () => {
      calls.push('a');
      offB();
    });
    offB = bus.on('clock:tick', () => calls.push('b'));
    bus.emit('clock:tick', { clockMin: 1 });
    expect(calls).toEqual(['a']);
  });

  it('subscribing during emit does not deliver to the new handler this emit', () => {
    const bus = new EventBus();
    const calls: string[] = [];
    bus.on('clock:tick', () => {
      calls.push('a');
      bus.on('clock:tick', () => calls.push('late'));
    });
    bus.emit('clock:tick', { clockMin: 1 });
    expect(calls).toEqual(['a']);
  });
});
