import { useCallback, useMemo, useState } from "react";
import { dateMatchModifiers } from "react-day-picker";
import { focusElement } from "../../../utils/helpers/focus.js";
import { useDateLocale } from "../../../utils/i18n/i18n.hooks.js";
import { getLocaleFromString } from "../../Date.locale.js";
import { formatDateForInput, isValidDate, parseDate } from "../../date-utils/index.js";
const getValidationMessage = (val = {}) => (Object.assign({ isDisabled: false, isEmpty: false, isInvalid: false, isBefore: false, isAfter: false, isValidMonth: true }, val));
const getIsBefore = (opt) => opt.fromDate &&
    opt.date &&
    (opt.fromDate.getFullYear() > opt.date.getFullYear() ||
        (opt.fromDate.getFullYear() === opt.date.getFullYear() &&
            opt.fromDate.getMonth() > opt.date.getMonth()));
const getIsAfter = (opt) => opt.toDate &&
    opt.date &&
    (opt.toDate.getFullYear() < opt.date.getFullYear() ||
        (opt.toDate.getFullYear() === opt.date.getFullYear() &&
            opt.toDate.getMonth() < opt.date.getMonth()));
/**
 *
 * @see 🏷️ {@link UseMonthPickerOptions}
 * @see 🏷️ {@link UseMonthPickerValue}
 * @see 🏷️ {@link MonthValidationT}
 * @example
 * const { monthpickerProps, inputProps } = useMonthpicker({
 *   fromDate: new Date("Aug 23 2019"),
 *   toDate: new Date("Feb 23 2024"),
 *   onMonthChange: console.log,
 *   onValidate: console.log,
 * });
 */
export const useMonthpicker = (opt = {}) => {
    var _a;
    const { locale: _locale, defaultSelected: _defaultSelected, fromDate, toDate, disabled, required, onMonthChange, inputFormat, onValidate, defaultYear, allowTwoDigitYear = true, } = opt;
    const [anchorRef, setAnchorRef] = useState(null);
    const [defaultSelected, setDefaultSelected] = useState(_defaultSelected);
    const today = useMemo(() => new Date(), []);
    const localeFromProvider = useDateLocale();
    const locale = _locale ? getLocaleFromString(_locale) : localeFromProvider;
    // Initialize states
    const [year, setYear] = useState((_a = defaultSelected !== null && defaultSelected !== void 0 ? defaultSelected : defaultYear) !== null && _a !== void 0 ? _a : today);
    const [selectedMonth, setSelectedMonth] = useState(defaultSelected);
    const [open, setOpen] = useState(false);
    const defaultInputValue = defaultSelected
        ? formatDateForInput(defaultSelected, locale, "month", inputFormat)
        : "";
    const [inputValue, setInputValue] = useState(defaultInputValue);
    const handleOpen = useCallback((newOpen) => {
        var _a, _b;
        setOpen(newOpen);
        newOpen &&
            setYear((_b = (_a = selectedMonth !== null && selectedMonth !== void 0 ? selectedMonth : defaultSelected) !== null && _a !== void 0 ? _a : defaultYear) !== null && _b !== void 0 ? _b : today);
    }, [defaultSelected, defaultYear, selectedMonth, today]);
    const updateMonth = (date) => {
        onMonthChange === null || onMonthChange === void 0 ? void 0 : onMonthChange(date);
        setSelectedMonth(date);
    };
    const updateValidation = (val = {}) => onValidate === null || onValidate === void 0 ? void 0 : onValidate(getValidationMessage(val));
    const reset = () => {
        var _a;
        updateMonth(defaultSelected);
        setYear((_a = defaultSelected !== null && defaultSelected !== void 0 ? defaultSelected : defaultYear) !== null && _a !== void 0 ? _a : today);
        setInputValue(defaultInputValue !== null && defaultInputValue !== void 0 ? defaultInputValue : "");
        setDefaultSelected(_defaultSelected);
    };
    const setSelected = (date) => {
        var _a;
        updateMonth(date);
        setYear((_a = date !== null && date !== void 0 ? date : defaultYear) !== null && _a !== void 0 ? _a : today);
        setInputValue(date ? formatDateForInput(date, locale, "month", inputFormat) : "");
    };
    const handleFocus = (e) => {
        var _a;
        if (e.target.readOnly) {
            return;
        }
        const day = parseDate(e.target.value, today, locale, "month", allowTwoDigitYear);
        const isBefore = getIsBefore({ fromDate, date: day });
        const isAfter = getIsAfter({ toDate, date: day });
        if (isValidDate(day)) {
            !isBefore && !isAfter && setYear(day);
            setInputValue(formatDateForInput(day, locale, "month", inputFormat));
        }
        else {
            setYear((_a = defaultSelected !== null && defaultSelected !== void 0 ? defaultSelected : defaultYear) !== null && _a !== void 0 ? _a : today);
        }
    };
    const handleBlur = (e) => {
        const day = parseDate(e.target.value, today, locale, "month", allowTwoDigitYear);
        isValidDate(day) &&
            setInputValue(formatDateForInput(day, locale, "month", inputFormat));
    };
    /* Only allow de-selecting if not required */
    const handleMonthClick = (month) => {
        if (!month && required) {
            return;
        }
        if (month) {
            handleOpen(false);
            setYear(month);
            anchorRef === null || anchorRef === void 0 ? void 0 : anchorRef.focus();
        }
        if (!month) {
            updateMonth(undefined);
            updateValidation({ isValidMonth: false, isEmpty: true });
            setInputValue("");
            setYear(defaultYear !== null && defaultYear !== void 0 ? defaultYear : today);
            return;
        }
        updateMonth(month);
        updateValidation();
        setInputValue(month ? formatDateForInput(month, locale, "month", 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 month = parseDate(e.target.value, today, locale, "month", allowTwoDigitYear);
        const isBefore = getIsBefore({ fromDate, date: month });
        const isAfter = getIsAfter({ toDate, date: month });
        if (!isValidDate(month) ||
            (disabled && dateMatchModifiers(month, disabled))) {
            updateMonth(undefined);
            updateValidation({
                isInvalid: isValidDate(month),
                isDisabled: disabled && dateMatchModifiers(month, disabled),
                isValidMonth: false,
                isEmpty: !e.target.value,
                isBefore: isBefore !== null && isBefore !== void 0 ? isBefore : false,
                isAfter: isAfter !== null && isAfter !== void 0 ? isAfter : false,
            });
            return;
        }
        if (isAfter ||
            isBefore ||
            (fromDate &&
                toDate &&
                !dateMatchModifiers(month, [{ from: fromDate, to: toDate }]))) {
            updateMonth(undefined);
            updateValidation({
                isValidMonth: false,
                isBefore: isBefore !== null && isBefore !== void 0 ? isBefore : false,
                isAfter: isAfter !== null && isAfter !== void 0 ? isAfter : false,
            });
            return;
        }
        updateMonth(month);
        updateValidation();
        setYear(month);
    };
    const monthpickerProps = {
        year,
        onYearChange: (y) => setYear(y !== null && y !== void 0 ? y : today),
        onMonthSelect: handleMonthClick,
        selected: selectedMonth,
        locale: _locale,
        fromDate,
        toDate,
        open,
        onOpenToggle: () => handleOpen(!open),
        onClose: () => {
            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).
            focusElement(anchorRef, { sync: false, preventScroll: true });
        },
        disabled,
    };
    const inputProps = {
        onChange: handleChange,
        onFocus: handleFocus,
        onBlur: handleBlur,
        value: inputValue,
        setAnchorRef,
    };
    return { monthpickerProps, inputProps, reset, selectedMonth, setSelected };
};
//# sourceMappingURL=useMonthPicker.js.map