import dayjs from "../../utils/day";

const DEFAULT_WORKING_DAYS = [1, 2, 3, 4, 5]; // Default to Monday-Friday

// Module-level state for holidays and working weekdays
let holidays = [];
let workingWeekdays = DEFAULT_WORKING_DAYS;

/**
 * Sets the holidays for the business logic.
 * @param newHolidays
 */
export const setHolidays = (newHolidays = []) => {
  holidays = newHolidays;
};

/**
 * Clears the holidays.
 */
export const clearHolidays = () => {
  holidays = [];
};

/**
 * Sets the working weekdays for the business logic.
 * @param newWorkingWeekdays
 */
export const setWorkingWeekdays = (newWorkingWeekdays = DEFAULT_WORKING_DAYS) => {
  workingWeekdays = newWorkingWeekdays;
};

/**
 * Clears the working weekdays, resetting to default (Monday-Friday).
 */
export const clearWorkingWeekdays = () => {
  workingWeekdays = DEFAULT_WORKING_DAYS; // Reset to default
};

/**
 * Translates the bodyshop working days settings to an array of weekdays.
 * @returns {*[]}
 */
export const getHolidays = () => {
  return holidays;
};

/**
 * Translates the working days settings from the bodyshop to an array of weekdays.
 * @returns {number[]}
 */
export const getWorkingWeekdays = () => {
  return workingWeekdays;
};

/**
 * Calculates the number of working days in the current month, excluding holidays.
 * @returns {number}
 * @constructor
 */
export const CalculateWorkingDaysThisMonth = () => {
  const businessDays = dayjs().businessDaysInMonth();
  return businessDays.filter((day) => !holidays.includes(dayjs(day).format("MM-DD-YYYY"))).length;
};

/**
 * Calculates the number of working days in a given period, excluding holidays.
 * @param start
 * @param end
 * @returns {number}
 * @constructor
 */
export const CalculateWorkingDaysInPeriod = (start, end) => {
  let businessDays = dayjs(end).businessDiff(dayjs(start));
  if (dayjs(end).isBusinessDay() && !holidays.includes(dayjs(end).format("MM-DD-YYYY"))) {
    businessDays += 1;
  }
  return businessDays;
};

/**
 * Calculates the number of working days as of today, excluding holidays.
 * @returns {number}
 * @constructor
 */
export const CalculateWorkingDaysAsOfToday = () => {
  const today = dayjs().startOf("day");
  let businessDays = today.businessDiff(dayjs().startOf("month"));
  if (today.isBusinessDay() && !holidays.includes(today.format("MM-DD-YYYY"))) {
    businessDays += 1;
  }
  return businessDays;
};

/**
 * Calculates the number of working days in the last month, excluding holidays.
 * @returns {number}
 * @constructor
 */
export const CalculateWorkingDaysLastMonth = () => {
  const businessDays = dayjs().subtract(1, "month").businessDaysInMonth();
  return businessDays.filter((day) => !holidays.includes(dayjs(day).format("MM-DD-YYYY"))).length;
};

/**
 * Calculates the weekly target hours based on daily target hours and the number of working days in the current week.
 * @param dailyTargetHrs
 * @returns {number}
 * @constructor
 */
export const WeeklyTargetHrs = (dailyTargetHrs) =>
  dailyTargetHrs * CalculateWorkingDaysInPeriod(dayjs().startOf("week"), dayjs().endOf("week"));

/**
 * Calculates the weekly target hours for a specific period.
 * @param dailyTargetHrs
 * @param start
 * @param end
 * @returns {number}
 * @constructor
 */
export const WeeklyTargetHrsInPeriod = (dailyTargetHrs, start, end) =>
  dailyTargetHrs * CalculateWorkingDaysInPeriod(start, end);

/**
 * Calculates the monthly target hours based on daily target hours and the number of working days in the current month.
 * @param dailyTargetHrs
 * @returns {number}
 * @constructor
 */
export const MonthlyTargetHrs = (dailyTargetHrs) => dailyTargetHrs * CalculateWorkingDaysThisMonth();

/**
 * Calculates the monthly target hours for the last month based on daily target hours and the number of working days
 * in the last month.
 * @param dailyTargetHrs
 * @returns {number}
 * @constructor
 */
export const LastMonthTargetHrs = (dailyTargetHrs) => dailyTargetHrs * CalculateWorkingDaysLastMonth();

/**
 * Calculates the target hours as of today based on daily target hours and the number of working days as of today.
 * @param dailyTargetHrs
 * @returns {number}
 * @constructor
 */
export const AsOfTodayTargetHrs = (dailyTargetHrs) => dailyTargetHrs * CalculateWorkingDaysAsOfToday();

/**
 * Calculates the target hours as of a specific date based on daily target hours and the number of business days up to
 * that date.
 * @param dailyTargetHours
 * @param date
 * @returns {number}
 * @constructor
 */
export const AsOfDateTargetHours = (dailyTargetHours, date) => {
  let businessDays = dayjs(date).businessDiff(dayjs().startOf("month"));
  if (dayjs(date).isBusinessDay() && !holidays.includes(dayjs(date).format("MM-DD-YYYY"))) {
    businessDays += 1;
  }
  return dailyTargetHours * businessDays;
};

/**
 * Generates a list of all days in the current month.
 * @returns {*[]}
 * @constructor
 */
export const ListOfDaysInCurrentMonth = () => {
  const days = [];
  let dateStart = dayjs().startOf("month");
  const dateEnd = dayjs().endOf("month");
  while (dateEnd.diff(dateStart, "day") > 0) {
    days.push(dateStart.format("YYYY-MM-DD"));
    dateStart = dateStart.add(1, "day");
  }
  days.push(dateEnd.format("YYYY-MM-DD"));
  return days;
};

/**
 * Generates a list of all days between two dates.
 * @param start
 * @param end
 * @returns {*[]}
 * @constructor
 */
export const ListDaysBetween = ({ start, end }) => {
  const days = [];
  let dateStart = dayjs(start);
  const dateEnd = dayjs(end);
  while (dateEnd.diff(dateStart, "day") >= 0) {
    days.push(dateStart.format("YYYY-MM-DD"));
    dateStart = dateStart.add(1, "day");
  }
  return days;
};
