import { map, remove, filter } from 'lodash-es';

class HeartBeatClass {
  static _instance = null;
  handlers = [];
  time = 1000;
  maxHandlerTimes = 1;
  _initTimes = 0;
  timer = 0;
  instance = null;

  constructor(time = 2000, maxHandlerTimes = 30000) {
    this.time = time;
    this.maxHandlerTimes = maxHandlerTimes;
  }

  static getInstance() {
    if (!HeartBeatClass._instance) {
      HeartBeatClass._instance = new HeartBeatClass();
    }
    return HeartBeatClass._instance;
  }

  hasType(type) {
    return this.handlers.findIndex((item) => item.type === type) > -1;
  }

  remove(type) {
    if (this.hasType(type)) {
      remove(this.handlers, (item) => {
        return item.type === type;
      });
    }
  }

  handle({ type, handler, intervalTimes }) {
    clearInterval(this.timer);
    const hasType = this.hasType(type);

    if (hasType) {
      this.remove(type);
    }

    this.handlers.push({ type, handler, intervalTimes });

    if (!this.handlers.length) {
      return;
    }

    this.timer = setInterval(() => {
      const execHandlers = filter(this.handlers, (handlerItem) => {
        return (
          !handlerItem.intervalTimes ||
          (handlerItem.intervalTimes &&
            this._initTimes % handlerItem.intervalTimes === 0)
        );
      });

      if (this._initTimes < this.maxHandlerTimes) {
        this._initTimes++;

        Promise.all(
          map(execHandlers, (handleItem) => {
            return handleItem.handler();
          })
        ).then((res) => {
          remove(this.handlers, (item, index) => {
            return res[index];
          });

          if (!this.handlers.length) {
            clearInterval(this.timer);
          }
        });
      } else {
        this.destory();
      }
    }, this.time);
  }

  destory() {
    this._instance = null;
    this.handlers = [];
    clearInterval(this.timer);
  }
}

const HeartBeat = {
  getInstance: HeartBeatClass.getInstance
};

export default HeartBeat;
