"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.useDatepicker = void 0;
const date_fns_1 = require("date-fns");
const react_1 = require("react");
const react_day_picker_1 = require("react-day-picker");
const focus_1 = require("../../../utils/helpers/focus");
const i18n_hooks_1 = require("../../../utils/i18n/i18n.hooks");
const Date_locale_1 = require("../../Date.locale");
const date_utils_1 = require("../../date-utils");
const getValidationMessage = (val = {}) => (Object.assign({ isDisabled: false, isWeekend: false, isEmpty: false, isInvalid: false, isBefore: false, isAfter: false, isValidDate: true }, val));
/**
 *
 * @see 🏷️ {@link UseDatepickerOptions}
 * @see 🏷️ {@link UseDatepickerValue}
 * @see 🏷️ {@link DateValidationT}
 * @example
 * const { datepickerProps, inputProps } = useDatepicker({
 *   fromDate: new Date("Aug 23 2019"),
 *   toDate: new Date("Feb 23 2024"),
 *   onDateChange: console.log,
 *   onValidate: console.log,
 * });
 */
const useDatepicker = (opt = {}) => {
    var _a;
    const { locale: _locale, required, defaultSelected: _defaultSelected, today = new Date(), fromDate, toDate, disabled, disableWeekends, onDateChange, inputFormat, onValidate, defaultMonth, allowTwoDigitYear = true, } = opt;
    const [anchorRef, setAnchorRef] = (0, react_1.useState)(null);
    const localeFromProvider = (0, i18n_hooks_1.useDateLocale)();
    const locale = _locale ? (0, Date_locale_1.getLocaleFromString)(_locale) : localeFromProvider;
    const [defaultSelected, setDefaultSelected] = (0, react_1.useState)(_defaultSelected);
    // Initialize states
    const [month, setMonth] = (0, react_1.useState)((_a = defaultSelected !== null && defaultSelected !== void 0 ? defaultSelected : defaultMonth) !== null && _a !== void 0 ? _a : today);
    const [selectedDay, setSelectedDay] = (0, react_1.useState)(defaultSelected);
    const [open, setOpen] = (0, react_1.useState)(false);
    const defaultInputValue = defaultSelected
        ? (0, date_utils_1.formatDateForInput)(defaultSelected, locale, "date", inputFormat)
        : "";
    const [inputValue, setInputValue] = (0, react_1.useState)(defaultInputValue);
    const handleOpen = (0, react_1.useCallback)((newOpen) => {
        var _a, _b;
        setOpen(newOpen);
        if (newOpen) {
            setMonth((_b = (_a = selectedDay !== null && selectedDay !== void 0 ? selectedDay : defaultSelected) !== null && _a !== void 0 ? _a : defaultMonth) !== null && _b !== void 0 ? _b : today);
        }
    }, [defaultMonth, defaultSelected, selectedDay, today]);
    const updateDate = (date) => {
        onDateChange === null || onDateChange === void 0 ? void 0 : onDateChange(date);
        setSelectedDay(date);
    };
    const updateValidation = (val = {}) => onValidate === null || onValidate === void 0 ? void 0 : onValidate(getValidationMessage(val));
    const reset = () => {
        var _a;
        updateDate(defaultSelected);
        setMonth((_a = defaultSelected !== null && defaultSelected !== void 0 ? defaultSelected : defaultMonth) !== null && _a !== void 0 ? _a : today);
        setInputValue(defaultInputValue !== null && defaultInputValue !== void 0 ? defaultInputValue : "");
        setDefaultSelected(_defaultSelected);
    };
    const setSelected = (date) => {
        var _a;
        updateDate(date);
        setMonth((_a = date !== null && date !== void 0 ? date : defaultMonth) !== null && _a !== void 0 ? _a : today);
        setInputValue(date ? (0, date_utils_1.formatDateForInput)(date, locale, "date", inputFormat) : "");
    };
    const handleFocus = (e) => {
        if (e.target.readOnly) {
            return;
        }
        const day = (0, date_utils_1.parseDate)(e.target.value, today, locale, "date", allowTwoDigitYear);
        if ((0, date_utils_1.isValidDate)(day)) {
            setInputValue((0, date_utils_1.formatDateForInput)(day, locale, "date", inputFormat));
            const isBefore = fromDate && day && (0, date_fns_1.differenceInCalendarDays)(fromDate, day) > 0;
            const isAfter = toDate && day && (0, date_fns_1.differenceInCalendarDays)(day, toDate) > 0;
            !isBefore && !isAfter && setMonth(day);
        }
    };
    const handleBlur = (e) => {
        const day = (0, date_utils_1.parseDate)(e.target.value, today, locale, "date", allowTwoDigitYear);
        (0, date_utils_1.isValidDate)(day) &&
            setInputValue((0, date_utils_1.formatDateForInput)(day, locale, "date", inputFormat));
    };
    /* Only allow de-selecting if not required */
    const handleDayClick = (day, { selected }) => {
        if (selected && required) {
            return;
        }
        if (day && !selected) {
            handleOpen(false);
            // We use sync:false so that when Modal is used (see Date.Dialog.tsx), it is closed before
            // we try to focus the open button (since native modal dialogs don't allow focus outside).
            (0, focus_1.focusElement)(anchorRef, { sync: false, preventScroll: true });
        }
        if (selected) {
            updateDate(undefined);
            setInputValue("");
            updateValidation({ isValidDate: false, isEmpty: true });
            return;
        }
        updateDate(day);
        updateValidation();
        setMonth(day);
        setInputValue(day ? (0, date_utils_1.formatDateForInput)(day, locale, "date", inputFormat) : "");
    };
    // When changing the input field, save its value in state and check if the
    // string is a valid date. If it is a valid day, set it as selected and update
    // the calendar’s month.
    const handleChange = (e) => {
        setInputValue(e.target.value);
        const day = (0, date_utils_1.parseDate)(e.target.value, today, locale, "date", allowTwoDigitYear);
        const isBefore = fromDate && day && (0, date_fns_1.differenceInCalendarDays)(fromDate, day) > 0;
        const isAfter = toDate && day && (0, date_fns_1.differenceInCalendarDays)(day, toDate) > 0;
        if (!(0, date_utils_1.isValidDate)(day) ||
            (disableWeekends && (0, date_fns_1.isWeekend)(day)) ||
            (disabled && (0, react_day_picker_1.dateMatchModifiers)(day, disabled))) {
            updateDate(undefined);
            updateValidation({
                isInvalid: !(0, date_utils_1.isValidDate)(day),
                isWeekend: disableWeekends && (0, date_fns_1.isWeekend)(day),
                isDisabled: disabled && (0, react_day_picker_1.dateMatchModifiers)(day, disabled),
                isValidDate: false,
                isEmpty: !e.target.value,
                isBefore: isBefore !== null && isBefore !== void 0 ? isBefore : false,
                isAfter: isAfter !== null && isAfter !== void 0 ? isAfter : false,
            });
            return;
        }
        if (isBefore || isAfter) {
            updateDate(undefined);
            updateValidation({
                isValidDate: false,
                isBefore: isBefore !== null && isBefore !== void 0 ? isBefore : false,
                isAfter: isAfter !== null && isAfter !== void 0 ? isAfter : false,
            });
            return;
        }
        updateDate(day);
        updateValidation();
        setMonth(defaultMonth !== null && defaultMonth !== void 0 ? defaultMonth : day);
    };
    const datepickerProps = {
        month,
        onMonthChange: setMonth,
        onDayClick: handleDayClick,
        selected: selectedDay !== null && selectedDay !== void 0 ? selectedDay : new Date("Invalid date"),
        locale: _locale,
        fromDate,
        toDate,
        today,
        open,
        onClose: () => {
            handleOpen(false);
            (0, focus_1.focusElement)(anchorRef, { sync: false, preventScroll: true });
        },
        onOpenToggle: () => handleOpen(!open),
        disabled,
        disableWeekends,
    };
    const inputProps = {
        onChange: handleChange,
        onFocus: handleFocus,
        onBlur: handleBlur,
        value: inputValue,
        setAnchorRef,
    };
    return { datepickerProps, inputProps, reset, selectedDay, setSelected };
};
exports.useDatepicker = useDatepicker;
//# sourceMappingURL=useDatepicker.js.map