"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.useDualCalendar = void 0;
const vue_1 = require("vue");
const date_fns_1 = require("date-fns");
const utils_1 = require("../utils");
const use_panel_common_1 = require("./use-panel-common");
const interface_1 = require("../interface");
const useDualCalendarProps = Object.assign(Object.assign({}, use_panel_common_1.usePanelCommon.props), { actions: {
        type: Array,
        default: () => ['clear', 'confirm']
    } });
// eslint-disable-next-line @typescript-eslint/explicit-function-return-type
function useDualCalendar(props, type = 'datetime') {
    const { isDateDisabledRef, isStartHourDisabledRef, isEndHourDisabledRef, isStartMinuteDisabledRef, isEndMinuteDisabledRef, isStartSecondDisabledRef, isEndSecondDisabledRef, isStartDateInvalidRef, isEndDateInvalidRef, isStartTimeInvalidRef, isEndTimeInvalidRef, isStartValueInvalidRef, isEndValueInvalidRef, isRangeInvalidRef, localeRef, rangesRef, closeOnSelectRef, updateValueOnCloseRef, firstDayOfWeekRef, datePickerSlots
    // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
     } = (0, vue_1.inject)(interface_1.datePickerInjectionKey);
    const validation = {
        isDateDisabled: isDateDisabledRef,
        isStartHourDisabled: isStartHourDisabledRef,
        isEndHourDisabled: isEndHourDisabledRef,
        isStartMinuteDisabled: isStartMinuteDisabledRef,
        isEndMinuteDisabled: isEndMinuteDisabledRef,
        isStartSecondDisabled: isStartSecondDisabledRef,
        isEndSecondDisabled: isEndSecondDisabledRef,
        isStartDateInvalid: isStartDateInvalidRef,
        isEndDateInvalid: isEndDateInvalidRef,
        isStartTimeInvalid: isStartTimeInvalidRef,
        isEndTimeInvalid: isEndTimeInvalidRef,
        isStartValueInvalid: isStartValueInvalidRef,
        isEndValueInvalid: isEndValueInvalidRef,
        isRangeInvalid: isRangeInvalidRef
    };
    const panelCommon = (0, use_panel_common_1.usePanelCommon)(props);
    const startDatesElRef = (0, vue_1.ref)(null);
    const endDatesElRef = (0, vue_1.ref)(null);
    const startCalendarDateTimeRef = (0, vue_1.ref)(Date.now());
    const endCalendarDateTimeRef = (0, vue_1.ref)((0, date_fns_1.getTime)((0, date_fns_1.addMonths)(Date.now(), 1)));
    const nowRef = (0, vue_1.ref)(Date.now());
    const isSelectingRef = (0, vue_1.ref)(false);
    const memorizedStartDateTimeRef = (0, vue_1.ref)(0);
    const { value, dateFormat } = props;
    const startDateInput = (0, vue_1.ref)(Array.isArray(value)
        ? (0, date_fns_1.format)(value[0], dateFormat, panelCommon.dateFnsOptions.value)
        : '');
    const endDateInputRef = (0, vue_1.ref)(Array.isArray(value)
        ? (0, date_fns_1.format)(value[1], dateFormat, panelCommon.dateFnsOptions.value)
        : '');
    if (Array.isArray(value)) {
        syncCalendarTimeWithValue(value);
    }
    // derived computed
    const selectingPhaseRef = (0, vue_1.computed)(() => {
        if (isSelectingRef.value)
            return 'end';
        else
            return 'start';
    });
    const startDateArrayRef = (0, vue_1.computed)(() => {
        var _a;
        return (0, utils_1.dateArray)(startCalendarDateTimeRef.value, props.value, nowRef.value, (_a = firstDayOfWeekRef.value) !== null && _a !== void 0 ? _a : localeRef.value.firstDayOfWeek);
    });
    const endDateArrayRef = (0, vue_1.computed)(() => {
        var _a;
        return (0, utils_1.dateArray)(endCalendarDateTimeRef.value, props.value, nowRef.value, (_a = firstDayOfWeekRef.value) !== null && _a !== void 0 ? _a : localeRef.value.firstDayOfWeek);
    });
    const weekdaysRef = (0, vue_1.computed)(() => {
        return startDateArrayRef.value.slice(0, 7).map((dateItem) => {
            const { ts } = dateItem;
            return (0, date_fns_1.format)(ts, localeRef.value.dayFormat, panelCommon.dateFnsOptions.value);
        });
    });
    const startCalendarMonthRef = (0, vue_1.computed)(() => {
        return (0, date_fns_1.format)(startCalendarDateTimeRef.value, localeRef.value.monthFormat, panelCommon.dateFnsOptions.value);
    });
    const endCalendarMonthRef = (0, vue_1.computed)(() => {
        return (0, date_fns_1.format)(endCalendarDateTimeRef.value, localeRef.value.monthFormat, panelCommon.dateFnsOptions.value);
    });
    const startCalendarYearRef = (0, vue_1.computed)(() => {
        return (0, date_fns_1.format)(startCalendarDateTimeRef.value, localeRef.value.yearFormat, panelCommon.dateFnsOptions.value);
    });
    const endCalendarYearRef = (0, vue_1.computed)(() => {
        return (0, date_fns_1.format)(endCalendarDateTimeRef.value, localeRef.value.yearFormat, panelCommon.dateFnsOptions.value);
    });
    const startTimeValueRef = (0, vue_1.computed)(() => {
        const { value } = props;
        if (Array.isArray(value))
            return value[0];
        return null;
    });
    const endTimeValueRef = (0, vue_1.computed)(() => {
        const { value } = props;
        if (Array.isArray(value))
            return value[1];
        return null;
    });
    const shortcutsRef = (0, vue_1.computed)(() => {
        const { shortcuts } = props;
        return shortcuts || rangesRef.value;
    });
    (0, vue_1.watch)((0, vue_1.computed)(() => props.value), (value) => {
        if (value !== null && Array.isArray(value)) {
            const [startMoment, endMoment] = value;
            const { dateFormat } = props;
            startDateInput.value = (0, date_fns_1.format)(startMoment, dateFormat, panelCommon.dateFnsOptions.value);
            endDateInputRef.value = (0, date_fns_1.format)(endMoment, dateFormat, panelCommon.dateFnsOptions.value);
            if (!isSelectingRef.value) {
                syncCalendarTimeWithValue(value);
            }
        }
        else {
            startDateInput.value = '';
            endDateInputRef.value = '';
        }
    });
    function handleCalendarChange(value, oldValue) {
        if ((0, date_fns_1.getYear)(value) !== (0, date_fns_1.getYear)(oldValue) ||
            (0, date_fns_1.getMonth)(value) !== (0, date_fns_1.getMonth)(oldValue)) {
            panelCommon.disableTransitionOneTick();
        }
    }
    (0, vue_1.watch)(startCalendarDateTimeRef, handleCalendarChange);
    (0, vue_1.watch)(endCalendarDateTimeRef, handleCalendarChange);
    // change calendar
    function adjustCalendarTimes(byStartCalendarTime) {
        const startTime = (0, date_fns_1.startOfMonth)(startCalendarDateTimeRef.value);
        const endTime = (0, date_fns_1.startOfMonth)(endCalendarDateTimeRef.value);
        if (startTime >= endTime) {
            if (byStartCalendarTime) {
                endCalendarDateTimeRef.value = (0, date_fns_1.getTime)((0, date_fns_1.addMonths)(startTime, 1));
            }
            else {
                startCalendarDateTimeRef.value = (0, date_fns_1.getTime)((0, date_fns_1.addMonths)(endTime, -1));
            }
        }
    }
    function startCalendarNextYear() {
        startCalendarDateTimeRef.value = (0, date_fns_1.getTime)((0, date_fns_1.addMonths)(startCalendarDateTimeRef.value, 12));
        adjustCalendarTimes(true);
    }
    function startCalendarPrevYear() {
        startCalendarDateTimeRef.value = (0, date_fns_1.getTime)((0, date_fns_1.addMonths)(startCalendarDateTimeRef.value, -12));
        adjustCalendarTimes(true);
    }
    function startCalendarNextMonth() {
        startCalendarDateTimeRef.value = (0, date_fns_1.getTime)((0, date_fns_1.addMonths)(startCalendarDateTimeRef.value, 1));
        adjustCalendarTimes(true);
    }
    function startCalendarPrevMonth() {
        startCalendarDateTimeRef.value = (0, date_fns_1.getTime)((0, date_fns_1.addMonths)(startCalendarDateTimeRef.value, -1));
        adjustCalendarTimes(true);
    }
    function endCalendarNextYear() {
        endCalendarDateTimeRef.value = (0, date_fns_1.getTime)((0, date_fns_1.addMonths)(endCalendarDateTimeRef.value, 12));
        adjustCalendarTimes(false);
    }
    function endCalendarPrevYear() {
        endCalendarDateTimeRef.value = (0, date_fns_1.getTime)((0, date_fns_1.addMonths)(endCalendarDateTimeRef.value, -12));
        adjustCalendarTimes(false);
    }
    function endCalendarNextMonth() {
        endCalendarDateTimeRef.value = (0, date_fns_1.getTime)((0, date_fns_1.addMonths)(endCalendarDateTimeRef.value, 1));
        adjustCalendarTimes(false);
    }
    function endCalendarPrevMonth() {
        endCalendarDateTimeRef.value = (0, date_fns_1.getTime)((0, date_fns_1.addMonths)(endCalendarDateTimeRef.value, -1));
        adjustCalendarTimes(false);
    }
    // The function is used on date panel, not the date-picker value validation
    function mergedIsDateDisabled(ts) {
        const isDateDisabled = isDateDisabledRef.value;
        if (!isDateDisabled)
            return false;
        if (!Array.isArray(props.value))
            return isDateDisabled(ts, 'start', null);
        if (selectingPhaseRef.value === 'start') {
            // before you really start to select
            return isDateDisabled(ts, 'start', null);
        }
        else {
            const { value: memorizedStartDateTime } = memorizedStartDateTimeRef;
            // after you starting to select
            if (ts < memorizedStartDateTimeRef.value) {
                return isDateDisabled(ts, 'start', [
                    memorizedStartDateTime,
                    memorizedStartDateTime
                ]);
            }
            else {
                return isDateDisabled(ts, 'end', [
                    memorizedStartDateTime,
                    memorizedStartDateTime
                ]);
            }
        }
    }
    function resetSelectingStatus(e) {
        var _a, _b;
        if (((_a = startDatesElRef.value) === null || _a === void 0 ? void 0 : _a.contains(e.target)) ||
            ((_b = endDatesElRef.value) === null || _b === void 0 ? void 0 : _b.contains(e.target))) {
            // do nothing
        }
        else {
            isSelectingRef.value = false;
        }
    }
    function syncCalendarTimeWithValue(value) {
        if (value === null)
            return;
        const [startMoment, endMoment] = value;
        startCalendarDateTimeRef.value = startMoment;
        if ((0, date_fns_1.startOfMonth)(endMoment) <= (0, date_fns_1.startOfMonth)(startMoment)) {
            endCalendarDateTimeRef.value = (0, date_fns_1.getTime)((0, date_fns_1.startOfMonth)((0, date_fns_1.addMonths)(startMoment, 1)));
        }
        else {
            endCalendarDateTimeRef.value = (0, date_fns_1.getTime)((0, date_fns_1.startOfMonth)(endMoment));
        }
    }
    function handleDateClick(dateItem) {
        if (mergedIsDateDisabled(dateItem.ts)) {
            return;
        }
        if (!isSelectingRef.value) {
            isSelectingRef.value = true;
            memorizedStartDateTimeRef.value = dateItem.ts;
            changeStartEndTime(dateItem.ts);
        }
        else {
            isSelectingRef.value = false;
            if (closeOnSelectRef.value && type === 'daterange') {
                if (updateValueOnCloseRef.value) {
                    closeCalendar();
                }
                else {
                    handleConfirmClick();
                }
            }
        }
    }
    function handleDateMouseEnter(dateItem) {
        if (isSelectingRef.value) {
            if (mergedIsDateDisabled(dateItem.ts))
                return;
            if (dateItem.ts >= memorizedStartDateTimeRef.value) {
                changeStartEndTime(memorizedStartDateTimeRef.value, dateItem.ts);
            }
            else {
                changeStartEndTime(dateItem.ts, memorizedStartDateTimeRef.value);
            }
        }
    }
    function handleConfirmClick() {
        if (isRangeInvalidRef.value) {
            return;
        }
        panelCommon.doConfirm();
        closeCalendar();
    }
    function closeCalendar() {
        isSelectingRef.value = false;
        if (props.active) {
            panelCommon.doClose();
        }
    }
    function changeStartDateTime(time) {
        if (typeof time !== 'number') {
            time = (0, date_fns_1.getTime)(time);
        }
        if (props.value === null) {
            panelCommon.doUpdateValue([time, time], false);
        }
        else if (Array.isArray(props.value)) {
            panelCommon.doUpdateValue([time, Math.max(props.value[1], time)], false);
        }
    }
    function changeEndDateTime(time) {
        if (typeof time !== 'number') {
            time = (0, date_fns_1.getTime)(time);
        }
        if (props.value === null) {
            panelCommon.doUpdateValue([time, time], false);
        }
        else if (Array.isArray(props.value)) {
            panelCommon.doUpdateValue([Math.min(props.value[0], time), time], false);
        }
    }
    function changeStartEndTime(startTime, endTime) {
        if (endTime === undefined)
            endTime = startTime;
        if (typeof startTime !== 'number') {
            startTime = (0, date_fns_1.getTime)(startTime);
        }
        if (typeof endTime !== 'number') {
            endTime = (0, date_fns_1.getTime)(endTime);
        }
        panelCommon.doUpdateValue([startTime, endTime], false);
    }
    function sanitizeValue(datetime) {
        if (type === 'datetimerange') {
            return (0, date_fns_1.getTime)((0, date_fns_1.startOfSecond)(datetime));
        }
        else {
            // daterange
            return (0, date_fns_1.getTime)((0, date_fns_1.startOfDay)(datetime));
        }
    }
    function handleStartDateInput(value) {
        const date = (0, utils_1.strictParse)(value, props.dateFormat, new Date(), panelCommon.dateFnsOptions.value);
        if ((0, date_fns_1.isValid)(date)) {
            if (!props.value) {
                const newValue = (0, date_fns_1.set)(new Date(), {
                    year: (0, date_fns_1.getYear)(date),
                    month: (0, date_fns_1.getMonth)(date),
                    date: (0, date_fns_1.getDate)(date)
                });
                changeStartDateTime(sanitizeValue((0, date_fns_1.getTime)(newValue)));
            }
            else if (Array.isArray(props.value)) {
                const newValue = (0, date_fns_1.set)(props.value[0], {
                    year: (0, date_fns_1.getYear)(date),
                    month: (0, date_fns_1.getMonth)(date),
                    date: (0, date_fns_1.getDate)(date)
                });
                changeStartDateTime(sanitizeValue((0, date_fns_1.getTime)(newValue)));
            }
        }
        else {
            startDateInput.value = value;
        }
    }
    function handleEndDateInput(value) {
        /** strict check when input */
        const date = (0, utils_1.strictParse)(value, props.dateFormat, new Date(), panelCommon.dateFnsOptions.value);
        if ((0, date_fns_1.isValid)(date)) {
            if (props.value === null) {
                const newValue = (0, date_fns_1.set)(new Date(), {
                    year: (0, date_fns_1.getYear)(date),
                    month: (0, date_fns_1.getMonth)(date),
                    date: (0, date_fns_1.getDate)(date)
                });
                changeEndDateTime(sanitizeValue((0, date_fns_1.getTime)(newValue)));
            }
            else if (Array.isArray(props.value)) {
                const newValue = (0, date_fns_1.set)(props.value[1], {
                    year: (0, date_fns_1.getYear)(date),
                    month: (0, date_fns_1.getMonth)(date),
                    date: (0, date_fns_1.getDate)(date)
                });
                changeEndDateTime(sanitizeValue((0, date_fns_1.getTime)(newValue)));
            }
        }
        else {
            endDateInputRef.value = value;
        }
    }
    function handleStartDateInputBlur() {
        const date = (0, utils_1.strictParse)(startDateInput.value, props.dateFormat, new Date(), panelCommon.dateFnsOptions.value);
        const { value } = props;
        if ((0, date_fns_1.isValid)(date)) {
            if (value === null) {
                const newValue = (0, date_fns_1.set)(new Date(), {
                    year: (0, date_fns_1.getYear)(date),
                    month: (0, date_fns_1.getMonth)(date),
                    date: (0, date_fns_1.getDate)(date)
                });
                changeStartDateTime(sanitizeValue((0, date_fns_1.getTime)(newValue)));
            }
            else if (Array.isArray(value)) {
                const newValue = (0, date_fns_1.set)(value[0], {
                    year: (0, date_fns_1.getYear)(date),
                    month: (0, date_fns_1.getMonth)(date),
                    date: (0, date_fns_1.getDate)(date)
                });
                changeStartDateTime(sanitizeValue((0, date_fns_1.getTime)(newValue)));
            }
        }
        else {
            refreshDisplayDateString();
        }
    }
    function handleEndDateInputBlur() {
        const date = (0, utils_1.strictParse)(endDateInputRef.value, props.dateFormat, new Date(), panelCommon.dateFnsOptions.value);
        const { value } = props;
        if ((0, date_fns_1.isValid)(date)) {
            if (value === null) {
                const newValue = (0, date_fns_1.set)(new Date(), {
                    year: (0, date_fns_1.getYear)(date),
                    month: (0, date_fns_1.getMonth)(date),
                    date: (0, date_fns_1.getDate)(date)
                });
                changeEndDateTime(sanitizeValue((0, date_fns_1.getTime)(newValue)));
            }
            else if (Array.isArray(value)) {
                const newValue = (0, date_fns_1.set)(value[1], {
                    year: (0, date_fns_1.getYear)(date),
                    month: (0, date_fns_1.getMonth)(date),
                    date: (0, date_fns_1.getDate)(date)
                });
                changeEndDateTime(sanitizeValue((0, date_fns_1.getTime)(newValue)));
            }
        }
        else {
            refreshDisplayDateString();
        }
    }
    function refreshDisplayDateString(times) {
        // If not selected, display nothing,
        // else update datetime related string
        const { value } = props;
        if (value === null || !Array.isArray(value)) {
            startDateInput.value = '';
            endDateInputRef.value = '';
            return;
        }
        const { dateFormat } = props;
        if (times === undefined) {
            times = value;
        }
        startDateInput.value = (0, date_fns_1.format)(times[0], dateFormat, panelCommon.dateFnsOptions.value);
        endDateInputRef.value = (0, date_fns_1.format)(times[1], dateFormat, panelCommon.dateFnsOptions.value);
    }
    function handleStartTimePickerChange(value) {
        changeStartDateTime(value);
    }
    function handleEndTimePickerChange(value) {
        changeEndDateTime(value);
    }
    function handleRangeShortcutMouseenter(shortcut) {
        panelCommon.cachePendingValue();
        const shortcutValue = panelCommon.getShortcutValue(shortcut);
        if (!Array.isArray(shortcutValue))
            return;
        changeStartEndTime(...shortcutValue);
    }
    function handleRangeShortcutClick(shortcut) {
        const shortcutValue = panelCommon.getShortcutValue(shortcut);
        if (!Array.isArray(shortcutValue))
            return;
        changeStartEndTime(...shortcutValue);
        panelCommon.clearPendingValue();
        handleConfirmClick();
    }
    return Object.assign(Object.assign(Object.assign({ startDatesElRef,
        endDatesElRef,
        resetSelectingStatus,
        handleDateClick,
        handleDateMouseEnter,
        handleConfirmClick,
        startCalendarPrevYear,
        startCalendarPrevMonth,
        startCalendarNextYear,
        startCalendarNextMonth,
        endCalendarPrevYear,
        endCalendarPrevMonth,
        endCalendarNextMonth,
        endCalendarNextYear,
        mergedIsDateDisabled,
        changeStartEndTime, ranges: rangesRef, startCalendarMonth: startCalendarMonthRef, startCalendarYear: startCalendarYearRef, endCalendarMonth: endCalendarMonthRef, endCalendarYear: endCalendarYearRef, weekdays: weekdaysRef, startDateArray: startDateArrayRef, endDateArray: endDateArrayRef, handleRangeShortcutMouseenter,
        handleRangeShortcutClick }, panelCommon), validation), { 
        // datetimerangeonly
        startDateDisplayString: startDateInput, endDateInput: endDateInputRef, timePickerSize: panelCommon.timePickerSize, startTimeValue: startTimeValueRef, endTimeValue: endTimeValueRef, handleFocusDetectorFocus: panelCommon.handleFocusDetectorFocus, handleStartTimePickerChange,
        handleEndTimePickerChange,
        handleStartDateInput,
        handleStartDateInputBlur,
        handleEndDateInput,
        handleEndDateInputBlur,
        datePickerSlots, shortcuts: shortcutsRef });
}
exports.useDualCalendar = useDualCalendar;
useDualCalendar.props = useDualCalendarProps;
