import type { Vue, VueConstructor } from 'vue/types/vue'

export interface BusEventType {
  $on(event: string | string[], callback: Function): void

  $once(event: string | string[], callback: Function): void

  $off(event?: string | string[], callback?: Function): void

  $emit(event: string, ...args: any[]): void
}

export class BusEvent implements BusEventType {
  private bus: Vue

  constructor(Vue: VueConstructor) {
    this.bus = new Vue()
    Vue.prototype.bus = this
  }

  /**
   * Register a listener on Alice's built-in event bus
   */
  $on(event: string | string[], callback: Function): void {
    this.bus.$on(event, callback)
    // $on(event: string | string[], callback: Function): this
  }

  /**
   * Register a one-time listener on the event bus
   */
  $once(event: string | string[], callback: Function): void {
    this.bus.$once(event, callback)
  }

  /**
   * Unregister an listener on the event bus
   */
  $off(event?: string | string[], callback?: Function): void {
    this.bus.$off(event, callback)
  }

  /**
   * Emit an event on the event bus
   */
  $emit(event: string, ...args: any[]): void {
    this.bus.$emit(event, ...args)
  }
}

let instance: BusEventType

export default function receiveBus(Vue: VueConstructor): BusEventType {
  if (!instance) {
    instance = new BusEvent(Vue)
  }
  return instance
}
