// Tiny typed event dispatcher shared by media players, sockets, and (later) nodes. Keeps the
// addEventListener / removeEventListener / dispatch boilerplate in one place.

export type EventMap = Record<string, (...args: any[]) => void>

export class Emitter<E extends EventMap> {
  private _listeners: { [K in keyof E]?: E[K][] } = {}

  addEventListener<K extends keyof E>(channel: K, callback: E[K]): void {
    const list = this._listeners[channel]
    if (list) list.push(callback)
    else this._listeners[channel] = [ callback ]
  }

  removeEventListener<K extends keyof E>(channel: K, callback: E[K]): void {
    const list = this._listeners[channel]
    if (!list) return
    const i = list.indexOf(callback)
    if (i >= 0) list.splice(i, 1)
  }

  /** Fire all listeners on a channel. Protected: only the owning class emits. */
  protected dispatch<K extends keyof E>(channel: K, ...args: Parameters<E[K]>): void {
    const list = this._listeners[channel]
    if (!list) return
    for (const fn of list.slice()) fn(...args)
  }

  protected hasListeners<K extends keyof E>(channel: K): boolean {
    const list = this._listeners[channel]
    return !!list && list.length > 0
  }

  /** Drop every listener on every channel (used when the owning object is disposed). */
  protected clearListeners(): void {
    this._listeners = {}
  }
}
