/**
 * Copyrigt (C) 2022 imengyu.top
 */

export class SimpleDelay<T = any> {

  private executor: (data: T) => void;
  private interval: number;
  private data: T;
  private timer = 0;

  public constructor(data: T, executor: (d: T) => void, interval: number) {
    this.executor = executor;
    this.interval = interval;
    this.data = data;
  }

  public start() {
    if (this.timer)
      clearTimeout(this.timer);
    this.timer = setTimeout(() => 
      this.executor(this.data), 
      this.interval
    ) as unknown as number;
    return this;
  }
  public stop() {
    if (this.timer) {
      clearTimeout(this.timer);
      this.timer = 0;
    }
    return this;
  }

}
export class SimpleTimer<T = any> {

  private executor: (data: T) => void;
  private interval: number;
  private data: T;
  private timer = 0;
  private executorTimeLimitWarnCount = 0;
  private lasExecuteTime = 0;

  public constructor(data: T, executor: (d: T) => void, interval: number) {
    this.executor = executor;
    this.interval = interval;
    this.data = data;
  }

  public start() {
    if (this.timer)
      clearInterval(this.timer);
    this.timer = setInterval(() => {

      const startTime = new Date();
      this.executor(this.data);

      //计算执行时间
      const executeTime = new Date().getTime() - startTime.getTime();

      //如果与上一次触发时间过近，则取消
      const lastInterval = startTime.getTime() - this.lasExecuteTime
      if (this.lasExecuteTime > 0 && lastInterval < (this.interval - 200)) {
        console.warn('The execution time of the timer is too fast, lastInterval: ' + lastInterval, 'executor:', this.executor);
        return;
      }

      this.lasExecuteTime = startTime.getTime();

      //如果执行时间过长，则警告
      if (executeTime > this.interval * 0.5 && this.executorTimeLimitWarnCount < 1) {
        console.warn('The execution time of the timer is too long, exceeding the timing for ' + this.interval + 'ms. executor:', this.executor, 'count:', this.executorTimeLimitWarnCount);
        this.executorTimeLimitWarnCount++;
      } else
        this.executorTimeLimitWarnCount--;

    }, this.interval) as unknown as number;
    return this; 
  }
  public stop() {
    if (this.timer) {
      clearInterval(this.timer);
      this.timer = 0;
    }
    return this; 
  }

}

export function exactDelay(cb: () => void, ms: number) {
  const startTime = new Date().getTime();

  return setTimeout(() => {
    const execTime = new Date().getTime() - startTime;
    if (execTime > (ms + (ms < 500 ? 100 : 1000)))
      console.warn('warn: exactDelay slow! execTime/ms:', execTime, '/', ms);
    cb();
  }, ms);
}