interface EventCallback {
  (...args: any[]): any
}

class EventBus<E = any> {
  private listeners: Map<E, EventCallback[]> = new Map()

  on(eventName: E, callback: EventCallback) {
    const callbacks = this.listeners.get(eventName)
    if (callbacks) {
      callbacks.push(callback)
    }
    else {
      this.listeners.set(eventName, [callback])
    }
  }

  emit<T = any>(eventName: E, data?: T) {
    const callbacks = this.listeners.get(eventName)
    if (callbacks) {
      callbacks.forEach((callback) => {
        callback(data)
      })
    }
  }
}

let eventBusInstance: EventBus | null = null

function createEventBus<E>() {
  if (!eventBusInstance) {
    eventBusInstance = new EventBus<E>()
  }
  return eventBusInstance as EventBus<E>
}

export { createEventBus }
