import { EventResult } from "./EventResult";

function nextTick(callback: VoidFunction) {
  if (typeof window === "object" && window.requestAnimationFrame) {
    window.requestAnimationFrame(callback);
  } else if (typeof setTimeout === "function") {
    setTimeout(callback, 1);
  } else {
    callback();
  }
}

export class Events<EventMap extends Record<string, any> = Record<string, any>> {
  private listeners: Record<any, Array<(...args: any) => any>> = {};

  /* 绑定事件监听器 */
  on<K extends keyof EventMap>(
    type: K,
    handler: (ev: EventMap[K], eventResult: EventResult) => void
  ) {
    const list = this.listeners[type] || [];
    list.push(handler);
    this.listeners[type] = list;
    return () => this.off(type, handler);
  }

  /* 移除事件监听器 */
  off<K extends keyof EventMap>(
    type: K,
    handler?: (ev: EventMap[K], eventResult: EventResult) => void
  ) {
    const list = this.listeners[type] || [];
    this.listeners[type] = handler ? list.filter(f => f !== handler) : [];
  }

  /* 移除所有监听器 */
  offAll() {
    Object.keys(this.listeners).forEach(k => {
      this.listeners[k] = [];
    });
  }

  /* 触发事件（同步执行） */
  emit<K extends keyof EventMap>(type: K, event?: EventMap[K]): EventResult {
    const eventResult = new EventResult();
    const list = this.listeners[type] || [];
    for (let i = 0; i < list.length; i++) {
      const handler = list[i];
      handler(event || {}, eventResult);
      if (eventResult.isStopped) {
        break;
      }
    }
    return eventResult;
  }

  /* 触发事件（下一帧执行） */
  emitAsync<K extends keyof EventMap>(type: K, event?: EventMap[K]) {
    nextTick(() => this.emit(type, event));
  }
}
