import type { EventMap } from '../data/types';

type Handler<K extends keyof EventMap> = (payload: EventMap[K]) => void;

// Typed pub/sub. Handlers added/removed during an emit don't affect that emit
// (we snapshot the handler list), matching what scenes need on shutdown.
export class EventBus {
  private handlers = new Map<keyof EventMap, Set<Handler<never>>>();

  on<K extends keyof EventMap>(event: K, fn: Handler<K>): () => void {
    let set = this.handlers.get(event);
    if (!set) {
      set = new Set();
      this.handlers.set(event, set);
    }
    set.add(fn as Handler<never>);
    return () => this.off(event, fn);
  }

  once<K extends keyof EventMap>(event: K, fn: Handler<K>): () => void {
    const off = this.on(event, (payload) => {
      off();
      fn(payload);
    });
    return off;
  }

  off<K extends keyof EventMap>(event: K, fn: Handler<K>): void {
    this.handlers.get(event)?.delete(fn as Handler<never>);
  }

  emit<K extends keyof EventMap>(event: K, payload: EventMap[K]): void {
    const set = this.handlers.get(event);
    if (!set) return;
    for (const fn of [...set]) {
      if (set.has(fn)) (fn as Handler<K>)(payload);
    }
  }

  removeAll(): void {
    this.handlers.clear();
  }
}
