import EventWithData from '@/Events/EventWithData'
import { type IEventCallback, type IEventWithData, type IEventManager } from '@/Events/Types'

class EventManager implements IEventManager {
  _eventListeners: Record<string, IEventCallback[]> = {}

  on (eventType: string, callback: IEventCallback): void {
    this.addEventListener(eventType, callback)
  }

  addEventListener (eventType: string, callback: IEventCallback): void {
    if (this._eventListeners[eventType] === undefined) {
      this._eventListeners[eventType] = []
    }
    this._eventListeners[eventType].push(callback)
  }

  off (eventType: string, callback: IEventCallback): void {
    this.removeEventListener(eventType, callback)
  }

  removeEventListener (eventType: string, callback: IEventCallback): void {
    const listeners = this._eventListeners[eventType]
    if (listeners !== undefined) {
      this._eventListeners[eventType] = listeners.filter(cb => cb !== callback)
    }
  }

  dispatchEvent (event: IEventWithData): void {
    const listeners = this._eventListeners[event.type]
    if (listeners !== undefined) {
      listeners.forEach(callback => { callback(event) })
    }
  }

  dispatchEventWithData (eventType: string, data?: any, nativeEvent?: Event): void {
    this.dispatchEvent(new EventWithData(eventType, {
      data,
      nativeEvent
    }))
  }
}

export default EventManager
