"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.useCalendar = void 0;
const react_1 = require("react");
const utils_1 = require("../../utils");
const consts_1 = require("../consts");
const utils_2 = require("../utils");
const useBoundaries_1 = require("./useBoundaries");
const useSelectedDate_1 = require("./useSelectedDate");
/**
 * Main hook for doing calendar calculations
 * Calculates for all time unit modes: day, month and year
 * Depends on useBoundaries and useSelectedDate to do initial setup
 */
const useCalendar = ({ boundaries, selectedDates, mode = 'exact', timeUnitMode, viewDate, fixedNumberOfWeeks, }) => {
    const boundariesProcessed = (0, useBoundaries_1.useBoundaries)({ boundaries });
    const selectedProcessed = (0, useSelectedDate_1.useSelectedDate)({ selectedDates, mode });
    return (0, react_1.useMemo)(() => {
        const { maxDateTime, minDateTime } = boundariesProcessed;
        const { currentDateTime, maxSelectedDateTime, minSelectedDateTime } = selectedProcessed;
        const { utcYear: viewDateYear, utcMonth: viewDateMonth } = (0, utils_1.getDateUTCValue)(viewDate);
        let calendarFirstDay;
        let calendarLastDay;
        let nextFirstDay;
        let prevLastDay;
        let firstDay;
        let lastDay;
        if ((0, utils_2.isDay)(timeUnitMode)) {
            firstDay = (0, utils_1.generateDateByUTCValue)(viewDateYear, viewDateMonth, 1);
            lastDay = (0, utils_1.generateDateByUTCValue)(viewDateYear, viewDateMonth + 1, 0); // lastDay
            nextFirstDay = (0, utils_1.generateDateByUTCValue)(viewDateYear, viewDateMonth + 1, 1);
            prevLastDay = (0, utils_1.generateDateByUTCValue)(viewDateYear, viewDateMonth, 0);
            const weekdayFirst = firstDay.getUTCDay();
            const weekdayLast = lastDay.getUTCDay();
            // Monday preceding the month (or first day of the month if it's on a Monday)
            calendarFirstDay =
                weekdayFirst === 0
                    ? new Date(Date.UTC(viewDateYear, viewDateMonth, 2 - 7))
                    : new Date(Date.UTC(viewDateYear, viewDateMonth, 2 - weekdayFirst));
            // Sunday after the month (or last day of the month if it's on a Sunday)
            calendarLastDay =
                weekdayLast === 0
                    ? new Date(Date.UTC(viewDateYear, viewDateMonth + 1, 0))
                    : new Date(Date.UTC(viewDateYear, viewDateMonth + 1, 8 - weekdayLast));
            // If calendar must contain constant number of weeks (6 weeks)
            // Missing weeks will be added to the end of the month
            const numberOfWeeks = Math.round((+calendarLastDay - +calendarFirstDay) / (7 * 24 * 60 * 60 * 1000));
            if (fixedNumberOfWeeks) {
                for (let week = numberOfWeeks; week < 6; week++) {
                    calendarLastDay = (0, utils_1.generateDateByUTCValue)(calendarLastDay.getUTCFullYear(), calendarLastDay.getUTCMonth(), calendarLastDay.getUTCDate() + 7);
                }
            }
        }
        else if ((0, utils_2.isMonth)(timeUnitMode)) {
            calendarFirstDay = firstDay = (0, utils_1.generateDateByUTCValue)(viewDateYear, 0, 1);
            calendarLastDay = lastDay = (0, utils_1.generateDateByUTCValue)(viewDateYear, 11, 31);
            nextFirstDay = (0, utils_1.generateDateByUTCValue)(viewDateYear + 1, 0, 1);
            prevLastDay = (0, utils_1.generateDateByUTCValue)(viewDateYear - 1, 11, 31);
        }
        else {
            const calendarStartYear = new Date().getUTCFullYear() - consts_1.viewYears / 2;
            const diffYears = calendarStartYear - viewDateYear;
            const startYear = calendarStartYear - Math.ceil(diffYears / consts_1.viewYears) * consts_1.viewYears;
            const endYear = startYear + consts_1.viewYears - 1;
            if (startYear === 1753)
                calendarFirstDay = firstDay = (0, utils_1.generateDateByUTCValue)(startYear, 0, 2);
            else
                calendarFirstDay = firstDay = (0, utils_1.generateDateByUTCValue)(startYear, 0, 1);
            calendarLastDay = lastDay = (0, utils_1.generateDateByUTCValue)(endYear, 11, 31);
            nextFirstDay = (0, utils_1.generateDateByUTCValue)(endYear + 1, 0, 1);
            prevLastDay = (0, utils_1.generateDateByUTCValue)(startYear - 1, 11, 31);
        }
        const items = [];
        // Loops between first and last date
        let dateItem = calendarFirstDay;
        do {
            const isHidden = dateItem < firstDay || dateItem >= lastDay;
            const isToday = (0, utils_1.sameDate)(dateItem, new Date());
            const { utcYear: minDateYear, utcMonth: minDateMonth } = (0, utils_1.getDateUTCValue)(minDateTime);
            let minUnitModeDate = minDateTime;
            if ((0, utils_2.isMonth)(timeUnitMode))
                // Need to compare with the first day of the month to decide if the month is disabled in the month overview
                minUnitModeDate = (0, utils_1.generateDateByUTCValue)(minDateYear, minDateMonth, 1);
            else if ((0, utils_2.isYear)(timeUnitMode))
                // Need to compare with the first day of the year to decide if the year is disabled in the year overview
                minUnitModeDate = (0, utils_1.generateDateByUTCValue)(minDateYear, 0, 1);
            const isDisabled = dateItem < minUnitModeDate || dateItem > maxDateTime ? true : false;
            // The calendar only select a single date
            const isExactSelected = (0, utils_2.isExact)(mode) && minSelectedDateTime && +dateItem === +minSelectedDateTime;
            // The calendar selects a range
            const inRangeLow = minSelectedDateTime && dateItem >= minSelectedDateTime;
            const inRangeHigh = maxSelectedDateTime && dateItem <= maxSelectedDateTime;
            const inRange = !(0, utils_2.isExact)(mode) &&
                ((!isDisabled && inRangeLow && (!maxSelectedDateTime || inRangeHigh)) ||
                    (inRangeHigh && (!minSelectedDateTime || inRangeLow)));
            const isRangeSelected = (0, utils_2.isRange)(mode) && inRange;
            const isFromSelected = (0, utils_2.isFrom)(mode) && inRangeLow;
            const isToSelected = (0, utils_2.isTo)(mode) && inRangeHigh;
            const isSelected = !!(isExactSelected || isFromSelected || isToSelected || isRangeSelected);
            let maxSelectedCheck = maxSelectedDateTime;
            let minSelectedCheck = minSelectedDateTime;
            if ((0, utils_2.isYear)(timeUnitMode)) {
                if (maxSelectedCheck)
                    maxSelectedCheck = (0, utils_1.generateDateByUTCValue)(maxSelectedCheck.getUTCFullYear(), 0, 1);
                if (minSelectedCheck)
                    minSelectedCheck = (0, utils_1.generateDateByUTCValue)(minSelectedCheck.getUTCFullYear(), 0, 1);
            }
            if ((0, utils_2.isMonth)(timeUnitMode)) {
                if (maxSelectedCheck)
                    maxSelectedCheck = (0, utils_1.generateDateByUTCValue)(maxSelectedCheck.getUTCFullYear(), maxSelectedCheck.getUTCMonth(), 1);
                if (minSelectedCheck)
                    minSelectedCheck = (0, utils_1.generateDateByUTCValue)(minSelectedCheck.getUTCFullYear(), minSelectedCheck.getUTCMonth(), 1);
            }
            const boundary = !(0, utils_2.isTo)(mode) && (0, utils_1.sameDate)(dateItem, minSelectedCheck);
            let current;
            if ((0, utils_2.isDay)(timeUnitMode))
                current = (0, utils_1.sameDate)(dateItem, currentDateTime);
            else if ((0, utils_2.isMonth)(timeUnitMode))
                current = (0, utils_1.sameYearSameMonth)(dateItem, currentDateTime);
            else
                current = (0, utils_1.sameYear)(dateItem, currentDateTime);
            items.push({
                date: dateItem,
                isHidden,
                isToday,
                isDisabled: boundary ? false : isDisabled,
                isSelected,
                boundary,
                current,
            });
            dateItem = (0, utils_2.getNextDate)(dateItem, timeUnitMode);
        } while (dateItem <= calendarLastDay);
        // Disables next/prev buttons
        const prevDisabled = minDateTime > prevLastDay;
        const nextDisabled = maxDateTime < nextFirstDay;
        return {
            items,
            prevDisabled,
            nextDisabled,
        };
    }, [boundaries, selectedDates, mode, timeUnitMode, viewDate]);
};
exports.useCalendar = useCalendar;
//# sourceMappingURL=useCalendar.js.map