import SplitIO from '../../../types/splitio';
import { IEventsCacheSync } from '../types';

const MAX_QUEUE_BYTE_SIZE = 5 * 1024 * 1024; // 5M

export class EventsCacheInMemory implements IEventsCacheSync {

  public name = 'events';
  private onFullQueue?: () => void;
  private readonly maxQueue: number;
  private queue: SplitIO.EventData[];
  private queueByteSize: number;

  /**
   *
   * @param eventsQueueSize - number of queued events to call onFullQueueCb.
   * Default value is 0, that means no maximum value, in case we want to avoid this being triggered.
   */
  constructor(eventsQueueSize: number = 0) {
    this.maxQueue = eventsQueueSize;
    this.queue = [];
    this.queueByteSize = 0;
  }

  setOnFullQueueCb(cb: () => void) {
    this.onFullQueue = cb;
  }

  /**
   * Add a new event object at the end of the queue.
   */
  track(data: SplitIO.EventData, size = 0) {
    this.queueByteSize += size;
    this.queue.push(data);

    this._checkForFlush();

    return true;
  }

  /**
   * Clear the data stored on the cache.
   */
  clear() {
    this.queue = [];
    this.queueByteSize = 0;
  }

  /**
   * Pop the collected data, used as payload for posting.
   */
  pop(toMerge?: SplitIO.EventData[]) {
    const data = this.queue;
    this.clear();
    return toMerge ? toMerge.concat(data) : data;
  }

  /**
   * Check if the cache is empty.
   */
  isEmpty() {
    return this.queue.length === 0;
  }

  /**
   * Check if the cache queue is full and we need to flush it.
   */
  private _checkForFlush() {
    if (
      (this.queueByteSize > MAX_QUEUE_BYTE_SIZE) ||
      // 0 means no maximum value, in case we want to avoid this being triggered. Size limit is not affected by it.
      (this.maxQueue > 0 && this.queue.length >= this.maxQueue)
    ) {
      this.onFullQueue && this.onFullQueue();
    }
  }
}
