'use strict';

class EventEmitter extends EventTarget {
  _events;
  _eventsCount;
  constructor() {
    super();
    this._events = {};
    this._eventsCount = 0;
  }
  /**
   * @param {string} type
   * @param {(event: CustomEvent, ...args: any[]) => void} listener
   * @returns
   */
  addListener(type, listener) {
    if (typeof listener !== "function") {
      throw new TypeError("listener must be a function");
    }
    if (!this._events[type]) {
      this._events[type] = [];
    }
    function wrappedListener(event) {
      listener.call(this, event, ...event.detail);
    }
    wrappedListener.listener = listener;
    this._events[type].push(wrappedListener);
    this._eventsCount++;
    this.addEventListener(type, wrappedListener.bind(this));
    return this;
  }
  /**
   * @alias addListener
   * @param {string} type
   * @param {(event: CustomEvent, ...args: any[]) => void} listener
   * @returns
   */
  on(type, listener) {
    return this.addListener(type, listener);
  }
  /**
   * @param {string} type
   * @param {any[]} args
   * @returns
   */
  trigger(type, ...args) {
    if (!this._events[type]) {
      return void 0;
    }
    const event = new CustomEvent(type, {
      detail: args,
      cancelable: true
    });
    return this.dispatchEvent(event);
  }
  /**
   * @alias trigger
   * @param {string} type
   * @param {any[]} args
   * @returns
   */
  emit(type, ...args) {
    return this.trigger(type, ...args);
  }
  /**
   * @param {string} type
   * @param {(event: CustomEvent, ...args: any[]) => void} listener
   * @returns
   */
  removeListener(type, listener) {
    if (!this._events[type]) {
      return this;
    }
    this._events[type] = this._events[type].filter((wrappedListener) => {
      if (wrappedListener.listener !== listener) {
        return true;
      }
      this.removeEventListener(type, wrappedListener);
      return false;
    });
    if (this._events[type].length === 0) {
      delete this._events[type];
      this._eventsCount--;
    }
    return this;
  }
  /**
   * @param {string} type
   * @returns
   */
  removeAllListeners(type) {
    if (type === void 0) {
      Object.keys(this._events).forEach((eventType) => {
        this.removeAllListeners(eventType);
      });
      return this;
    }
    if (this._events[type]) {
      this._events[type].forEach((wrappedListener) => {
        this.removeEventListener(type, wrappedListener);
      });
      delete this._events[type];
      this._eventsCount--;
    }
    return this;
  }
  /**
   * @param {string} type
   * @param {(event: CustomEvent, ...args: any[]) => void} listener
   * @returns
   */
  off(type, listener) {
    if (type === void 0) {
      return this.removeAllListeners();
    }
    if (listener === void 0) {
      return this.removeAllListeners(type);
    }
    return this.removeListener(type, listener);
  }
}

exports.EventEmitter = EventEmitter;
