interface EventMap {
  [key: string]: Function[]
}

class EventProvider {
  private _events: EventMap = {}
  on (type: string, fn: Function) {
    const types = type.split(' ')
    types.forEach((typ) => {
      if (!this._events[typ]) {
        this._events[typ] = [fn]
      } else {
        this._events[typ].push(fn)
      }
    })
    return this
  }

  one (type: string, fn: Function) {
    const once = (...args: any[]) => {
      fn.apply(null, args)
      this.off(type, once)
    }
    const types = type.split(' ')

    types.forEach((typ) => {
      if (!this._events[typ]) {
        this._events[typ] = [once]
      } else {
        this._events[typ].push(once)
      }
    })

    return this
  }

  off (type: string, fn: Function) {
    const types = type.split(' ')
    types.forEach((typ) => {
      if (!this._events[typ]) return
      const index = this._events[typ].indexOf(fn)
      if (index > -1) {
        this._events[typ].splice(index, 1)
      }
    })
    return this
  }

  trigger (type: string, ...args: any[]) {
    if (!this._events[type]) return

    this._events[type].forEach(fn => {
      try {
        fn.apply(null, args)
      } catch (e) {
        this.off(type, fn)
        this.trigger('error', `Error by event[${type}]`)
      }
    })
    return this
  }
}

export {
  EventProvider
}
