import dayjs from "dayjs";
import customParseFormat from "dayjs/plugin/customParseFormat.js";
import duration from "dayjs/plugin/duration.js";
import isBetween from "dayjs/plugin/isBetween.js";
import isToday from "dayjs/plugin/isToday.js";
import localizedFormat from "dayjs/plugin/localizedFormat.js";
import minmax from "dayjs/plugin/minMax.js";
import relativeTime from "dayjs/plugin/relativeTime.js";
import timeZone from "dayjs/plugin/timezone.js";
import toArray from "dayjs/plugin/toArray.js";
import utc from "dayjs/plugin/utc.js";
const BusinessDaysPlugin = (options = {}, dayjsClass, dayjsFactory) => {
  const defaultWorkingWeekdays = [1, 2, 3, 4, 5];
  dayjsFactory.getWorkingWeekdays = function() {
    return options.workingWeekdays || defaultWorkingWeekdays;
  };
  dayjsFactory.setWorkingWeekdays = function(workingWeekdays) {
    options.workingWeekdays = workingWeekdays;
  };
  dayjsFactory.getHolidays = function() {
    return options.holidays || [];
  };
  dayjsFactory.setHolidays = function(holidays) {
    options.holidays = holidays;
  };
  dayjsFactory.getHolidayFormat = function() {
    return options.holidayFormat;
  };
  dayjsFactory.setHolidayFormat = function(holidayFormat) {
    options.holidayFormat = holidayFormat;
  };
  dayjsFactory.getAdditionalWorkingDays = function() {
    return options.additionalWorkingDays || [];
  };
  dayjsFactory.setAdditionalWorkingDays = function(additionalWorkingDays) {
    options.additionalWorkingDays = additionalWorkingDays;
  };
  dayjsFactory.getAdditionalWorkingDayFormat = function() {
    return options.additionalWorkingDayFormat;
  };
  dayjsFactory.setAdditionalWorkingDayFormat = function(additionalWorkingDayFormat) {
    options.additionalWorkingDayFormat = additionalWorkingDayFormat;
  };
  dayjsClass.prototype.isHoliday = function() {
    if (!options.holidays) {
      return false;
    }
    if (options.holidays.includes(this.format(options.holidayFormat))) {
      return true;
    }
    return false;
  };
  dayjsClass.prototype.isBusinessDay = function() {
    const workingWeekdays = options.workingWeekdays || defaultWorkingWeekdays;
    if (this.isHoliday()) {
      return false;
    }
    if (this.isAdditionalWorkingDay()) {
      return true;
    }
    if (workingWeekdays.includes(this.day())) {
      return true;
    }
    return false;
  };
  dayjsClass.prototype.isAdditionalWorkingDay = function() {
    if (!options.additionalWorkingDays) {
      return false;
    }
    if (options.additionalWorkingDays.includes(this.format(options.additionalWorkingDayFormat))) {
      return true;
    }
    return false;
  };
  dayjsClass.prototype.businessDaysAdd = function(days) {
    const numericDirection = days < 0 ? -1 : 1;
    let currentDay = this.clone();
    let daysRemaining = Math.abs(days);
    while (daysRemaining > 0) {
      currentDay = currentDay.add(numericDirection, `d`);
      if (currentDay.isBusinessDay()) {
        daysRemaining -= 1;
      }
    }
    return currentDay;
  };
  dayjsClass.prototype.businessDaysSubtract = function(days) {
    let currentDay = this.clone();
    currentDay = currentDay.businessDaysAdd(days * -1);
    return currentDay;
  };
  dayjsClass.prototype.businessDiff = function(date) {
    const day1 = this.clone();
    const day2 = date.clone();
    const isPositiveDiff = day1 >= day2;
    let start = isPositiveDiff ? day2 : day1;
    const end = isPositiveDiff ? day1 : day2;
    let daysBetween = 0;
    if (start.isSame(end)) {
      return daysBetween;
    }
    while (start < end) {
      if (start.isBusinessDay()) {
        daysBetween += 1;
      }
      start = start.add(1, `d`);
    }
    return isPositiveDiff ? daysBetween : -daysBetween;
  };
  dayjsClass.prototype.nextBusinessDay = function() {
    const searchLimit = 7;
    let currentDay = this.clone();
    let loopIndex = 1;
    while (loopIndex < searchLimit) {
      currentDay = currentDay.add(1, `day`);
      if (currentDay.isBusinessDay()) {
        break;
      }
      loopIndex += 1;
    }
    return currentDay;
  };
  dayjsClass.prototype.prevBusinessDay = function() {
    const searchLimit = 7;
    let currentDay = this.clone();
    let loopIndex = 1;
    while (loopIndex < searchLimit) {
      currentDay = currentDay.subtract(1, `day`);
      if (currentDay.isBusinessDay()) {
        break;
      }
      loopIndex += 1;
    }
    return currentDay;
  };
  dayjsClass.prototype.businessDaysInMonth = function() {
    if (!this.isValid()) {
      return [];
    }
    let currentDay = this.clone().startOf(`month`);
    const monthEnd = this.clone().endOf(`month`);
    const businessDays = [];
    let monthComplete = false;
    while (!monthComplete) {
      if (currentDay.isBusinessDay()) {
        businessDays.push(currentDay.clone());
      }
      currentDay = currentDay.add(1, `day`);
      if (currentDay.isAfter(monthEnd)) {
        monthComplete = true;
      }
    }
    return businessDays;
  };
  dayjsClass.prototype.lastBusinessDayOfMonth = function() {
    const businessDays = this.businessDaysInMonth();
    const lastBusinessDay = businessDays[businessDays.length - 1];
    return lastBusinessDay;
  };
  dayjsClass.prototype.businessWeeksInMonth = function() {
    if (!this.isValid()) {
      return [];
    }
    let currentDay = this.clone().startOf(`month`);
    const monthEnd = this.clone().endOf(`month`);
    const businessWeeks = [];
    let businessDays = [];
    let monthComplete = false;
    while (!monthComplete) {
      if (currentDay.isBusinessDay()) {
        businessDays.push(currentDay.clone());
      }
      if (currentDay.day() === 5 || currentDay.isSame(monthEnd, `day`)) {
        businessWeeks.push(businessDays);
        businessDays = [];
      }
      currentDay = currentDay.add(1, `day`);
      if (currentDay.isAfter(monthEnd)) {
        monthComplete = true;
      }
    }
    return businessWeeks;
  };
};
dayjs.extend(customParseFormat);
dayjs.extend(BusinessDaysPlugin);
dayjs.extend(isBetween);
dayjs.extend(isToday);
dayjs.extend(localizedFormat);
dayjs.extend(relativeTime);
dayjs.extend(timeZone);
dayjs.extend(toArray);
dayjs.extend(utc);
dayjs.extend(minmax);
dayjs.extend(duration);
