import { isDate } from '@astral/utils/date/isDate';
import { DAYS_IN_WEEK } from '../../../constants';
import { buildIsoDate } from '../buildIsoDate';
import { checkIsDateInRange } from '../checkIsDateInRange';
import { compareDateDayByUTC } from '../compareDateDayByUTC';
import { DateCompareDeep, isDateOutOfRange } from '../isDateOutOfRange';
const FULL_ROWS_COUNT = 6;
export const DAYS_CALENDAR_ITEMS_COUNT = FULL_ROWS_COUNT * DAYS_IN_WEEK;
export const buildDaysCalendarGrid = ({ minDate, maxDate, selectedDate, selectedRanges, hoveredDate, baseDate, isMondayFirst = true, productionCalendarStorage, }) => {
    /**
     * нормализованный номер месяца от базовой даты
     */
    const month = baseDate.getUTCMonth() + 1;
    /**
     * получаем новую дату, т.к. пропс может содержать дни, часы, минуты, что собьет наш счет
     */
    const startDate = buildIsoDate({ year: baseDate.getUTCFullYear(), month });
    /**
     * отступ для компенсации первого дня недели, 1 для понедельника, 0 для воскресенья
     */
    const firstWeekDayGap = Number(isMondayFirst);
    /**
     * номер первого дня текущего месяца в календаре, зависит от флага isMondayFirst
     */
    let startWeekDay = startDate.getUTCDay();
    if (startWeekDay === 0 && isMondayFirst) {
        startWeekDay = DAYS_IN_WEEK;
    }
    /**
     * текущая дата пользователя
     */
    const currentDate = new Date();
    return Array.from({ length: DAYS_CALENDAR_ITEMS_COUNT }).map((_, index) => {
        // текущая дата в счетчике
        const date = new Date(startDate);
        date.setUTCDate(startDate.getUTCDate() + index - startWeekDay + firstWeekDayGap);
        /**
         * нормализованный номер месяца
         */
        const dateMonth = date.getUTCMonth() + 1;
        const productionCalendarDay = productionCalendarStorage?.get(date.toISOString());
        const hasBothEdgeDates = Boolean(minDate && maxDate);
        const isDisabled = (hasBothEdgeDates &&
            isDateOutOfRange({
                date,
                dateA: minDate,
                dateB: maxDate,
                deep: DateCompareDeep.Day,
            })) ||
            (Boolean(minDate) && date < minDate) ||
            (Boolean(maxDate) && date > maxDate);
        return {
            ...productionCalendarDay,
            isOutOfAvailableRange: dateMonth !== month,
            index,
            isSelected: ((isDate(selectedDate) &&
                compareDateDayByUTC(selectedDate, date)) ||
                selectedRanges?.some(({ dateA, dateB }) => compareDateDayByUTC(dateA, date) ||
                    compareDateDayByUTC(dateB, date))) ??
                false,
            isCurrentInUserLocalTime: date.getUTCFullYear() === currentDate.getFullYear() &&
                date.getUTCDate() === currentDate.getDate() &&
                date.getUTCMonth() === currentDate.getMonth(),
            date,
            isInSelectedRange: selectedRanges?.some(({ dateA, dateB }) => checkIsDateInRange({
                date,
                dateA,
                dateB,
                deep: DateCompareDeep.Day,
            })) ?? false,
            isInHoveredRange: checkIsDateInRange({
                date,
                dateA: selectedDate,
                dateB: hoveredDate,
                deep: DateCompareDeep.Day,
            }),
            monthDay: date.getUTCDate(),
            isDisabled,
        };
    });
};
