import * as plugins from './classes.plugins.js';

export interface ITimedAggregatorOptions<T> {
  aggregationIntervalInMillis: number;
  functionForAggregation: (input: T[]) => void;
}

export class TimedAggregtor<T> {
  public options: ITimedAggregatorOptions<T>;
  private storageArray: T[] = [];
  private isStopped = false;

  constructor(optionsArg: ITimedAggregatorOptions<T>) {
    this.options = optionsArg;
  }

  private aggregationTimer: plugins.smarttime.Timer;
  private checkAggregationStatus() {
    if (this.isStopped) {
      return;
    }
    const addAggregationTimer = () => {
      this.aggregationTimer = new plugins.smarttime.Timer(this.options.aggregationIntervalInMillis);
      this.aggregationTimer.completed.then(() => {
        if (this.isStopped) {
          this.aggregationTimer = null;
          return;
        }
        const aggregateForProcessing = this.storageArray;
        if (aggregateForProcessing.length === 0) {
          this.aggregationTimer = null;
          return;
        }
        this.storageArray = [];
        addAggregationTimer();
        this.options.functionForAggregation(aggregateForProcessing);
      });
      this.aggregationTimer.start();
    };
    if (!this.aggregationTimer) {
      addAggregationTimer();
    }
  }

  public add(aggregationArg: T) {
    if (this.isStopped) {
      return;
    }
    this.storageArray.push(aggregationArg);
    this.checkAggregationStatus();
  }

  /**
   * stops the aggregation timer chain
   * @param flushRemaining if true, calls functionForAggregation with any remaining items
   */
  public stop(flushRemaining: boolean = false) {
    this.isStopped = true;
    if (this.aggregationTimer) {
      this.aggregationTimer.reset();
      this.aggregationTimer = null;
    }
    if (flushRemaining && this.storageArray.length > 0) {
      const remaining = this.storageArray;
      this.storageArray = [];
      this.options.functionForAggregation(remaining);
    } else {
      this.storageArray = [];
    }
  }

  public restart(): void {
    this.isStopped = false;
  }
}

// correctly-spelled alias
export { TimedAggregtor as TimedAggregator };
