type Listener = (...args: any[]) => void;
type OffOn = (event: string, listener: Listener) => void;
type Emit = (event: string, ...args: any[]) => void;

/**
 * . . .
 * @example
 * ```typescript
 *
 *     const event = emmiter()
 *
 *     const callback1 = (message: string) => console.log(message);
 *
 *     event.on("exampleEvent", callback1);
 *
 *     event.emit("exampleEvent", "Hello World") // prints Hello World to console
 *
 *     event.off("exampleEvent", callback1)
 *     event.emit("exampleEvent", "Hello World") // does nothing
 */

const emmiter = (): {
  listeners: Map<string, Set<Listener>>;
  on: OffOn;
  off: OffOn;
  emit: Emit;
} => {
  const listeners = new Map<string, Set<Listener>>();

  const on = (event: string, listener: Listener) => {
    let eventListeners = listeners.get(event);
    if (!eventListeners) {
      eventListeners = new Set();
      listeners.set(event, eventListeners);
    }
    eventListeners.add(listener);
  };

  const off = (event: string, listener: Listener) => {
    const eventListeners = listeners.get(event);
    eventListeners?.delete(listener);
  };

  const emit = (event: string, ...args: any[]) => {
    const eventListeners = listeners.get(event);
    eventListeners?.forEach((listener) => listener(...args));
  };

  return { listeners, on, off, emit };
};

export default emmiter;
