var __makeTemplateObject = (this && this.__makeTemplateObject) || function (cooked, raw) {
    if (Object.defineProperty) { Object.defineProperty(cooked, "raw", { value: raw }); } else { cooked.raw = raw; }
    return cooked;
};
var __assign = (this && this.__assign) || function () {
    __assign = Object.assign || function(t) {
        for (var s, i = 1, n = arguments.length; i < n; i++) {
            s = arguments[i];
            for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p))
                t[p] = s[p];
        }
        return t;
    };
    return __assign.apply(this, arguments);
};
import React, { useImperativeHandle, useLayoutEffect, useRef, useState } from 'react';
import { useEmotion, useStyles } from '../../lib/renderEnvironment/index.js';
import { MobilePopup } from '../../internal/MobilePopup/index.js';
import { useLocaleForControl } from '../../lib/locale/useLocaleForControl.js';
import { ThemeContext } from '../../lib/theming/ThemeContext.js';
import { CommonWrapper } from '../../internal/CommonWrapper/index.js';
import { Calendar, CalendarDay } from '../Calendar/index.js';
import { Popup } from '../../internal/Popup/index.js';
import { DateInput } from '../DateInput/index.js';
import { isBetween, isGreater, isGreaterOrEqual, isLess, isLessOrEqual } from '../../lib/date/comparison.js';
import { ZIndex } from '../../internal/ZIndex/index.js';
import { getRootNode } from '../../lib/rootNode/index.js';
import { getMenuPositions } from '../../lib/getMenuPositions.js';
import { Button } from '../Button/index.js';
import { useResponsiveLayout } from '../ResponsiveLayout/index.js';
import { InternalDate } from '../../lib/date/InternalDate.js';
import { InternalDateGetter } from '../../lib/date/InternalDateGetter.js';
import { ArrowAUpIcon16Light } from '../../internal/icons2022/ArrowAUpIcon/ArrowAUp16Light.js';
import { NativeDateInput } from '../../internal/NativeDateInput/index.js';
import { forwardRefAndName } from '../../lib/forwardRefAndName.js';
import { LocaleContext } from '../../lib/locale/index.js';
import { isIOS } from '../../lib/client.js';
import { getFontSize, getStyles } from './DateRangePicker.styles.js';
import { DateRangePickerSeparator } from './DateRangePickerSeparator.js';
import { DateRangePickerContext } from './DateRangePickerContext.js';
import { DateRangePickerEnd, DateRangePickerStart } from './DateRangePickerInput.js';
import { getDateRangePickerTheme, getMobileDateRangePickerTheme } from './DateRangePickerTheme.js';
import { DateRangePickerLocaleHelper } from './locale/index.js';
import { validateDateRangePicker } from './helpers/validateDateRangePicker.js';
import { getStateForValue } from './helpers/getStateForValue.js';
export var DateRangePickerDataTids = {
    root: 'DateRangePicker__root',
    start: 'DateRangePicker__start',
    end: 'DateRangePicker__end',
    popup: 'DateRangePicker__popup',
    calendar: 'DateRangePicker__calendar',
    todayButton: 'DateRangePicker__todayButton',
    startOptionalButton: 'DateRangePicker__startOptionalButton',
    endOptionalButton: 'DateRangePicker__endOptionalButton',
    mobileStart: 'DateRangePicker__mobileStart',
    mobileEnd: 'DateRangePicker__mobileEnd',
    rangeStart: 'DateRangePicker__rangeStart',
    rangeEnd: 'DateRangePicker__rangeEnd',
};
var DayDateAttribute = 'data-date-range-picker-day';
export var DateRangePicker = Object.assign({
    Start: DateRangePickerStart,
    End: DateRangePickerEnd,
    Separator: DateRangePickerSeparator,
    validate: validateDateRangePicker,
}, forwardRefAndName('DateRangePicker', function (props, ref) {
    var _a = useEmotion(), css = _a.css, cx = _a.cx;
    var styles = useStyles(getStyles);
    var isMobile = useResponsiveLayout().isMobile;
    var locale = useLocaleForControl('DateRangePicker', DateRangePickerLocaleHelper);
    var _b = useState(), startValue = _b[0], setStartValue = _b[1];
    var _c = useState(false), startOptional = _c[0], setStartOptional = _c[1];
    var _d = useState(false), startDisabled = _d[0], setStartDisabled = _d[1];
    var _e = useState(), endValue = _e[0], setEndValue = _e[1];
    var _f = useState(false), endOptional = _f[0], setEndOptional = _f[1];
    var _g = useState(false), endDisabled = _g[0], setEndDisabled = _g[1];
    var _h = useState(''), minDate = _h[0], setMinDate = _h[1];
    var _j = useState(''), maxDate = _j[0], setMaxDate = _j[1];
    var _k = useState(null), hoveredDay = _k[0], setHoveredDay = _k[1];
    var _l = useState(false), showCalendar = _l[0], setShowCalendar = _l[1];
    var _m = useState(null), focusInput = _m[0], setFocusInput = _m[1];
    var dateRangePickerRef = useRef(null);
    var calendarRef = useRef(null);
    var startRef = useRef(null);
    var endRef = useRef(null);
    var mobileStartRef = useRef(null);
    var mobileEndRef = useRef(null);
    var mobileNativeStartRef = useRef(null);
    var mobileNativeEndRef = useRef(null);
    var isCalendarOpen = !startDisabled && !endDisabled && showCalendar;
    var updateDateRangeValues = function (value) {
        if (value === void 0) { value = ''; }
        var currentValues = {
            currentStart: startValue,
            currentEnd: endValue,
            minDate: minDate,
            maxDate: maxDate,
        };
        var updatedState = getStateForValue(focusInput, value, currentValues);
        setStartValue(updatedState.start);
        setEndValue(updatedState.end);
        if (updatedState.isOpen && updatedState.focus) {
            focus(updatedState.focus);
        }
        if (!updatedState.isOpen) {
            close();
        }
    };
    var open = function (inputType) {
        if (inputType === void 0) { inputType = 'start'; }
        setFocusInput(inputType);
        setShowCalendar(true);
    };
    var close = function () {
        setShowCalendar(false);
        setHoveredDay(null);
    };
    var focus = function (inputType) {
        if (inputType === void 0) { inputType = 'start'; }
        setFocusInput(inputType);
    };
    var setEmpty = function (type) {
        switch (type) {
            case 'start':
                setStartValue('');
                focus('end');
                break;
            case 'end':
                setEndValue('');
                close();
                break;
        }
    };
    useImperativeHandle(ref, function () { return ({
        open: open,
        close: close,
        scrollToMonth: function (month, year) {
            var _a, _b;
            (_b = (_a = calendarRef.current) === null || _a === void 0 ? void 0 : _a.scrollToMonth) === null || _b === void 0 ? void 0 : _b.call(_a, month, year);
        },
        getRootNode: function () { return dateRangePickerRef.current; },
    }); }, []);
    useLayoutEffect(function () {
        if (!focusInput) {
            return;
        }
        // fix DateInput flushSync warning in React 18
        setTimeout(function () {
            var _a, _b, _c, _d;
            var isStart = focusInput === 'start';
            var currentFieldRef;
            // Mobile Native Picker
            if (isMobile && props.useMobileNativeDatePicker) {
                currentFieldRef = isStart ? mobileNativeStartRef : mobileNativeEndRef;
                if (isIOS) {
                    (_a = currentFieldRef.current) === null || _a === void 0 ? void 0 : _a.focus();
                }
                else {
                    // Android open native datepicker only via click
                    (_b = currentFieldRef.current) === null || _b === void 0 ? void 0 : _b.click();
                }
                return;
            }
            // Mobile
            if (isMobile) {
                currentFieldRef = isStart ? mobileStartRef : mobileEndRef;
                (_c = currentFieldRef.current) === null || _c === void 0 ? void 0 : _c.focus();
                return;
            }
            // Desktop
            currentFieldRef = isStart ? startRef : endRef;
            (_d = currentFieldRef.current) === null || _d === void 0 ? void 0 : _d.focus();
        });
    }, [focusInput]);
    var dateRangePickerContextProps = {
        startValue: startValue,
        startOptional: startOptional,
        startDisabled: startDisabled,
        endValue: endValue,
        endOptional: endOptional,
        endDisabled: endDisabled,
        minDate: minDate,
        maxDate: maxDate,
        size: props.size,
        setStartValue: setStartValue,
        setStartOptional: setStartOptional,
        setStartDisabled: setStartDisabled,
        setEndValue: setEndValue,
        setEndOptional: setEndOptional,
        setEndDisabled: setEndDisabled,
        setMinDate: setMinDate,
        setMaxDate: setMaxDate,
        setFocusInput: setFocusInput,
        open: open,
        close: close,
        dateRangePickerRef: dateRangePickerRef,
        startRef: startRef,
        endRef: endRef,
    };
    var renderCalendar = function (theme, widthAuto) {
        var _a;
        if (widthAuto === void 0) { widthAuto = false; }
        return (React.createElement(LocaleContext.Provider, { value: {
                locale: {
                    Calendar: {
                        months: locale.months,
                        dayCellChooseDateAriaLabel: locale.dayCellChooseDateAriaLabel,
                        selectMonthAriaLabel: locale.selectMonthAriaLabel,
                        selectYearAriaLabel: locale.selectYearAriaLabel,
                        selectChosenAriaLabel: locale.selectChosenAriaLabel,
                    },
                },
            } },
            React.createElement(Calendar, { value: focusInput === 'start' ? startValue : endValue, minDate: minDate, maxDate: maxDate, renderDay: function (dayProps) { return renderCalendarRange(dayProps, theme, props.renderDay); }, onValueChange: function (value) { return updateDateRangeValues(value); }, ref: calendarRef, onMonthChange: props.onMonthChange, className: cx((_a = {}, _a[styles.calendarWidthAuto()] = widthAuto, _a)) })));
    };
    var renderMobileCalendar = function (theme) {
        var _a, _b;
        return (React.createElement(MobilePopup, { opened: true, headerChildComponent: React.createElement("div", { className: cx(styles.root(theme), styles.inputWrapperWidthFull()) },
                React.createElement(DateInput, { withIcon: true, value: startValue, width: "auto", size: "medium", className: cx((_a = {}, _a[styles.inputVisuallyFocus(theme)] = focusInput === 'start', _a)), disabled: startDisabled, onValueChange: setStartValue, onFocus: function () { return setFocusInput('start'); }, ref: mobileStartRef, "data-tid": DateRangePickerDataTids.mobileStart }),
                React.createElement(DateRangePicker.Separator, null),
                React.createElement(DateInput, { withIcon: true, value: endValue, width: "auto", size: "medium", className: cx((_b = {}, _b[styles.inputVisuallyFocus(theme)] = focusInput === 'end', _b)), disabled: endDisabled, onValueChange: setEndValue, onFocus: function () { return setFocusInput('end'); }, ref: mobileEndRef, "data-tid": DateRangePickerDataTids.mobileEnd })), onCloseRequest: function () { return close(); }, footerChildComponent: renderButtons() },
            React.createElement(ThemeContext.Provider, { value: getMobileDateRangePickerTheme(theme) }, renderCalendar(theme, true))));
    };
    var getAnchorElement = function () {
        var menuAnchorElement = props.menuAnchorElement;
        if (menuAnchorElement === 'focused') {
            return getRootNode(focusInput === 'start' ? startRef.current : endRef.current);
        }
        if (React.isValidElement(menuAnchorElement)) {
            return menuAnchorElement;
        }
        if (menuAnchorElement && typeof menuAnchorElement === 'object' && 'current' in menuAnchorElement) {
            return getRootNode(menuAnchorElement.current);
        }
        return getRootNode(startRef.current) || getRootNode(endRef.current) || getRootNode(dateRangePickerRef.current);
    };
    var renderDesktopCalendar = function (theme) { return (React.createElement(Popup, { opened: true, hasShadow: true, priority: ZIndex.priorities.PopupMenu, positions: getMenuPositions(props.menuPos, props.menuAlign), "data-tid": DateRangePickerDataTids.root, anchorElement: getAnchorElement(), margin: parseInt(theme.datePickerMenuOffsetY) },
        React.createElement("div", { className: styles.calendarWrapper(theme), onMouseDown: function (e) { return e.preventDefault(); }, onMouseMove: handleCalendarRangeMouseMove },
            renderCalendar(theme),
            renderButtons()))); };
    var renderButtons = function () {
        var today = new InternalDate(locale)
            .setComponents(InternalDateGetter.getTodayComponents())
            .toString({ withPad: true, withSeparator: true });
        var hasOptionalButtons = startOptional || endOptional;
        return (React.createElement("div", { className: cx(styles.buttonWrap()) },
            hasOptionalButtons && (React.createElement(React.Fragment, null,
                focusInput === 'start' && startOptional && (React.createElement(Button, { width: "100%", "data-tid": DateRangePickerDataTids.startOptionalButton, onClick: function () { return setEmpty('start'); } }, locale.startDateEmpty)),
                focusInput === 'end' && endOptional && (React.createElement(Button, { width: "100%", "data-tid": DateRangePickerDataTids.endOptionalButton, onClick: function () { return setEmpty('end'); } }, locale.endDateEmpty)))),
            props.enableTodayLink && (React.createElement(Button, { icon: React.createElement(ArrowAUpIcon16Light, null), "aria-label": locale.todayAriaLabel, "data-tid": DateRangePickerDataTids.todayButton, onClick: function () { return updateDateRangeValues(today); } }, !hasOptionalButtons && locale.today))));
    };
    var renderMobileNativeDateInput = function () { return (React.createElement(React.Fragment, null,
        React.createElement(NativeDateInput, { value: startValue, minDate: minDate, maxDate: maxDate, onValueChange: setStartValue, disabled: startDisabled, ref: mobileNativeStartRef }),
        React.createElement(NativeDateInput, { value: endValue, minDate: minDate, maxDate: maxDate, onValueChange: setEndValue, disabled: endDisabled, ref: mobileNativeEndRef }))); };
    return (React.createElement(ThemeContext.Consumer, null, function (theme) { return (React.createElement(ThemeContext.Provider, { value: getDateRangePickerTheme(theme) },
        React.createElement(DateRangePickerContext.Provider, { value: dateRangePickerContextProps },
            React.createElement(CommonWrapper, __assign({}, props),
                React.createElement("div", { className: cx(styles.root(theme), styles.inputWrapperWidth(theme), css(templateObject_1 || (templateObject_1 = __makeTemplateObject(["\n                      font-size: ", ";\n                    "], ["\n                      font-size: ", ";\n                    "])), getFontSize(theme, props.size))), role: "group", "aria-describedby": props['aria-describedby'], "aria-label": props['aria-label'], "aria-labelledby": props['aria-labelledby'], "data-tid": DateRangePickerDataTids.root, ref: dateRangePickerRef, style: { width: props.width } },
                    props.children,
                    props.useMobileNativeDatePicker && isMobile
                        ? renderMobileNativeDateInput()
                        : isCalendarOpen && (isMobile ? renderMobileCalendar(theme) : renderDesktopCalendar(theme))))))); }));
    // Use parent mousemove event instead each CalendarDay's mouseenter / mouseover
    function handleCalendarRangeMouseMove(e) {
        if (!startValue && !endValue) {
            return;
        }
        var hoveredElement = e.target;
        if (!hoveredElement.hasAttribute(DayDateAttribute) && hoveredDay === null) {
            return;
        }
        var date = String(hoveredElement === null || hoveredElement === void 0 ? void 0 : hoveredElement.getAttribute(DayDateAttribute)) || null;
        setHoveredDay(date);
    }
    function renderCalendarRange(props, t, renderDayFn) {
        var _a, _b;
        var day = props.date;
        var isDayFirst = startValue === day;
        var isDayLast = endValue === day;
        var isDayInPeriod = Boolean(startValue && endValue && isBetween(day, startValue, endValue));
        var hasHoveredDay = hoveredDay !== null;
        var isDayInHoveredPeriod = hasHoveredDay &&
            Boolean((focusInput === 'start' && endValue && isBetween(day, hoveredDay, endValue)) ||
                (focusInput === 'end' && startValue && isBetween(day, startValue, hoveredDay)));
        var hasLeftRoundings;
        var hasRightRoundings;
        if (hasHoveredDay) {
            var isDayBeforeFirstInPeriod = startValue ? isLess(hoveredDay, startValue) : endValue;
            var isDayAfterLastInPeriod = endValue ? isGreater(hoveredDay, endValue) : startValue;
            if (isDayFirst && (isGreaterOrEqual(hoveredDay, startValue) || focusInput === 'end')) {
                hasLeftRoundings = true;
            }
            if (isDayLast && (isLessOrEqual(hoveredDay, endValue) || focusInput === 'start')) {
                hasRightRoundings = true;
            }
            var isDayHovered = hoveredDay === day;
            if (isDayHovered) {
                if (isDayBeforeFirstInPeriod) {
                    hasLeftRoundings = true;
                }
                if (isDayAfterLastInPeriod) {
                    hasRightRoundings = true;
                }
            }
        }
        else {
            if (isDayFirst) {
                hasLeftRoundings = true;
            }
            if (isDayLast) {
                hasRightRoundings = true;
            }
        }
        var renderDayProps = __assign(__assign({}, props), (_a = {}, _a[DayDateAttribute] = props.date, _a));
        var dataTid = null;
        if (isDayFirst) {
            dataTid = DateRangePickerDataTids.rangeStart;
        }
        else if (isDayLast) {
            dataTid = DateRangePickerDataTids.rangeEnd;
        }
        return (React.createElement("div", { className: cx(styles.rangeCalendarDay(), css(templateObject_2 || (templateObject_2 = __makeTemplateObject(["\n              background: ", ";\n              border-top-left-radius: ", ";\n              border-bottom-left-radius: ", ";\n              border-top-right-radius: ", ";\n              border-bottom-right-radius: ", ";\n            "], ["\n              background: ", ";\n              border-top-left-radius: ", ";\n              border-bottom-left-radius: ", ";\n              border-top-right-radius: ", ";\n              border-bottom-right-radius: ", ";\n            "])), isDayInPeriod && t.rangeCalendarCellBg, hasLeftRoundings && t.calendarCellBorderRadius, hasLeftRoundings && t.calendarCellBorderRadius, hasRightRoundings && t.calendarCellBorderRadius, hasRightRoundings && t.calendarCellBorderRadius), (_b = {},
                _b[styles.rangeCalendarDayEnd(t)] = isDayFirst || isDayLast,
                _b[styles.rangeCalendarDayHoverInPeriod(t)] = isDayInPeriod,
                _b[styles.rangeCalendarDayInHoveredPeriod(t)] = isDayInHoveredPeriod,
                _b)), "data-tid": dataTid }, renderDayFn ? renderDayFn(renderDayProps) : React.createElement(CalendarDay, __assign({}, renderDayProps))));
    }
}));
var templateObject_1, templateObject_2;
//# sourceMappingURL=DateRangePicker.js.map