import { VegaCalendarBaseEventLayoutGenerator } from './base-event-layout-generator';
import { VegaCalendarFullDayEventLayout } from './full-day-event-layout';
import { VegaCalendarFullDayEventLayoutRow } from './full-day-event-layout-row';
/** The `VegaCalendarLongEventLayoutGenerator` class in TypeScript generates a layout for long calendar events with overlapping prevention logic. */
export class VegaCalendarFullDayEventLayoutGenerator extends VegaCalendarBaseEventLayoutGenerator {
  /**
   * The function generates a long event layout for a calendar based on the input calendar events.
   *
   * @param {CalendarEvent[][]} calendarEvents - CalendarEvent[][] is a two-dimensional array where each
   * element represents a day in the calendar and contains an array of CalendarEvent objects representing events on that day.
   * @returns {VegaCalendarFullDayEventLayout} A new instance of `VegaCalendarFullDayEventLayout` is being returned, which is constructed
   * using the `layoutRows` array containing `VegaCalendarFullDayEventLayoutRow` objects.
   */
  generate(calendarEvents) {
    const allShouldOrderLongEvents = this.collectAllShouldOrderLongEvents(calendarEvents);
    const layoutRows = [this.createNewLayoutCell()];
    allShouldOrderLongEvents.forEach((eventView) => {
      this.addCurrentEventToLayout(layoutRows, eventView);
    });
    return new VegaCalendarFullDayEventLayout(layoutRows);
  }
  /**
   * The function creates a new instance of VegaCalendarFullDayEventLayoutRow.
   *
   * @returns {VegaCalendarFullDayEventLayoutRow} An instance of the class `VegaCalendarFullDayEventLayoutRow` is being returned.
   */
  createNewLayoutCell() {
    return new VegaCalendarFullDayEventLayoutRow();
  }
  /**
   * Filter the all should order group event from event list
   *
   * @param {CalendarEvent[][]} allEvents all event list
   * @returns {VegaCalendarFullDayEventView[]} the group event view list
   */
  collectAllShouldOrderLongEvents(allEvents) {
    const allLongEventViews = {};
    allEvents.forEach((items, index) => {
      const longEvents = items.filter((item) => item && item.isGroupEvent());
      longEvents.forEach((groupEvent) => {
        if (!allLongEventViews[groupEvent.eventKey]) {
          allLongEventViews[groupEvent.eventKey] = {
            start: index,
            end: index,
            event: groupEvent,
          };
        }
        else {
          allLongEventViews[groupEvent.eventKey] = Object.assign(Object.assign({}, allLongEventViews[groupEvent.eventKey]), { end: index, start: index - allLongEventViews[groupEvent.eventKey].end !== 1
              ? index
              : allLongEventViews[groupEvent.eventKey].start });
        }
      });
    });
    const shouldSortLongEventViews = Object.values(allLongEventViews);
    return this.sortLongEventViews(shouldSortLongEventViews);
  }
  /**
   * This function sorts an array of VegaCalendarFullDayEventView objects based on their start and end times.
   *
   * @param {VegaCalendarFullDayEventView[]} eventViews - The `eventViews` parameter is an array of
   * `VegaCalendarFullDayEventView` objects that represent long events in a calendar. The function
   * `sortLongEventViews` takes this array as input and sorts it based on the start and end times of the events.
   * @returns {VegaCalendarFullDayEventView[]} The function `sortLongEventViews` is returning an array of `VegaCalendarFullDayEventView`
   * objects that have been sorted based on the comparison logic provided in the sorting function. The sorting is done based on the `start` and `end` properties of the objects in the array.
   */
  sortLongEventViews(eventViews) {
    return eventViews.sort((itemA, itemB) => {
      const { startDate: startA, endDate: endA } = itemA.event;
      const { startDate: startB, endDate: endB } = itemB.event;
      startA.setHours(0, 0, 0);
      startB.setHours(0, 0, 0);
      endA.setHours(23, 59, 59);
      endB.setHours(23, 59, 59);
      const num = endB.valueOf() - startB.valueOf() - (endA.valueOf() - startA.valueOf());
      if (startA.valueOf() !== startB.valueOf()) {
        return startA.valueOf() - startB.valueOf();
      }
      else {
        return num;
      }
    });
  }
}
