import { QueueModel } from 'src/modules/queue/data/models/queue.model';
import { toTime } from '../../helpers/time.helper';
import * as math from 'mathjs';
import { QueueTimeFormula } from './queue-time.formula';
import * as moment from 'moment';

export class QueueCondition {
  private ticketItems = {};
  constructor(readonly items: QueueModel[]) {
    items.forEach((item) => {
      const item_id = item.item_queue_id;
      const currentItem = this.ticketItems[item_id];
      this.ticketItems[item_id] = currentItem ? [...currentItem, item] : [item];
    });
  }

  condition(item_id: string) {
    const queues: QueueModel[] = this.ticketItems[item_id] ?? [];
    const playEstimation = queues[0]?.average ?? 0;
    const peakLevel = queues[0]?.peak_level ?? 100;
    const [time, last] = this.queueTime(queues, playEstimation);
    const nearest = time ? toTime(time) : 0;
    const lastTime = last ? toTime(last + playEstimation) : 0;

    const queuePeople = this.queuePeople(queues, peakLevel);

    return {
      available: queuePeople == 0,
      average: this.averageTime(queues),
      nearest: nearest,
      crowded_level: queuePeople,
      available_time: lastTime,
    };
  }

  queuePeople(queues: QueueModel[], peakLevel): number {
    const queue = this.activeQueue(queues);
    const level = peakLevel / 100;
    const queuePeople = queue.reduce((acc, q) => {
      return acc + q.qty;
    }, 0);
    return queuePeople * level;
  }

  activeQueue(queues: QueueModel[]) {
    return queues.filter((q) => q.status == 'waiting');
  }

  queueTime(queues: QueueModel[], average = 0): number[] {
    const calledQueue = queues.filter((q) =>
      ['called', 'done'].includes(q.status),
    );
    const lastCalledQueue = calledQueue[calledQueue.length - 1];
    const activeQueues = this.activeQueue(queues);

    const queueTimes = QueueTimeFormula.queueTime(
      activeQueues,
      lastCalledQueue,
      average,
    );

    const queueEstimation = Object.values<number>(queueTimes);

    const first = queueEstimation[0] ?? moment().valueOf();
    const last = queueEstimation[queueEstimation.length - 1] ?? 0;
    return [first, last];
  }

  averageTime(queues: QueueModel[]) {
    if (queues.length == 0) return 0;
    const calledQueue = queues.filter((q) =>
      ['called', 'done'].includes(q.status),
    );

    if (calledQueue.length < 1) return 0;

    const times = calledQueue.map((queue) => {
      return (queue.call_time - queue.time) / 1000;
    });

    const avg = Math.ceil(math.mean(times));
    return Math.max(0, avg);
  }
}
