import { isFunctionAsync } from "../utils/Utils";

/**
 * 事件总线demo
 */
export class EventBusDemo {
  _events:Map<string,Function|Array<Function>>;
  constructor () {
    this._events = new Map(); // 存储事件／回调键值对
  }

  /**
   * on 监听
   * @param type 消息类型 
   * @param fn 处理函数返回Promise<any>
   */
  $on(type:string, fn:Function){
    const handler = this._events.get(type)||[]; // 获取对应事件名称的函数清单
    if (!handler) {
        this._events.set(type, fn)
    } else if (handler && typeof handler === 'function') {
        // 如果handler是函数，说明当前只有一个监听者
        // 再次添加监听者，需要改用 数组储存
        this._events.set(type, [handler, fn]);
    } else {
        // 已有多个监听者，直接往数组里push函数即可
        handler.push(fn);
        this._events.set(type, handler);
    }
    return this
  }

  /**
   * 提交事件
   * @param type 消息类型
   * @param args 参数
   * @returns 
   */
  $emit(type:string, ...args:any):Promise<any>{
    return new Promise(async(resolve,reject)=>{
      let handler = this._events.get(type)
    if(!handler)return Promise.resolve('');//无任何监听则退出
    
    if (Array.isArray(handler)) {
      // 是数组，说明有多个监听者，需要依次触发里边的函数
      for (let i = 0; i < handler.length; ++i) {
        if(isFunctionAsync(handler[i])){
          let res=await handler[i].call(this, ...args)
          resolve(res)
        }else{
          let res=handler[i].call(this, ...args)
          resolve(res)
        }
      }
    } else {
      // 单个函数的情况直接触发即可
      if(isFunctionAsync(handler)){
        let res=await handler.call(this,...args)
        resolve(res)
      }else{
        let res=handler.call(this,...args)
        resolve(res)
      }
    }
    return Promise.resolve('')
    })
  }

  /**
   * 移除监听
   * @param type 类型
   * @param fn 处理函数
   */
  $off(type:string, fn:Function){
    const handler = this._events.get(type)
    if (handler && typeof handler === 'function') {
        // 函数，说明只有一个监听者，直接删除就行
        this._events.delete(type)
    } else if(Array.isArray(handler)) {
      handler.splice(handler.findIndex(e => e === fn), 1)
    }
    return this
  }

  /**
   * 单次执行
   * @param type 类型
   * @param fn 处理函数
   */
  $once(type:string, fn:Function){
    let _self = this
    function handler() {
      _self.$off(type, handler)
      fn.apply(null, arguments)
    }
    return this.$on(type, handler)
  }
}


// 下面是 测试代码
function test1 (...params:any) {
  console.log(11, params)
}

function test2 (...params:any) {
  console.log(22, params)
}

function test3 (...params:any) {
  console.log(33, params)
}

function test4 (...params:any) {
  console.log(params)
  console.log(33, params)
}

//测试用例
// let eb = new EventBusDemo()
// eb.on('event1', test1)
// eb.on('event1', test2)
// eb.on('event1', test3)
// eb.emit('event1', '第一次')

// eb.off('event1', test1)
// eb.emit('event1', ['第二次1', '第二次2'])

// eb.once('once', test4);
// eb.emit('once', '执行一次', 1, 2, 3)
const $bus=new EventBusDemo();
export default $bus