// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
// SPDX-License-Identifier: Apache-2.0
'use client';
import React, { useEffect, useRef, useState } from 'react';
import clsx from 'clsx';
import { useMergeRefs, useUniqueId, warnOnce } from '@cloudscape-design/component-toolkit/internal';
import Dropdown from '../dropdown/internal';
import { useInternalI18n } from '../i18n/context';
import InternalIcon from '../icon/internal';
import { getBaseProps } from '../internal/base-component';
import ButtonTrigger from '../internal/components/button-trigger';
import { useFormFieldContext } from '../internal/context/form-field-context';
import ResetContextsForModal from '../internal/context/reset-contexts-for-modal.js';
import { fireNonCancelableEvent } from '../internal/events';
import checkControlled from '../internal/hooks/check-controlled';
import useForwardFocus from '../internal/hooks/forward-focus';
import useBaseComponent from '../internal/hooks/use-base-component';
import { useFocusTracker } from '../internal/hooks/use-focus-tracker';
import { useMobile } from '../internal/hooks/use-mobile';
import { usePrevious } from '../internal/hooks/use-previous';
import { isDevelopment } from '../internal/is-development.js';
import { KeyCode } from '../internal/keycode';
import { applyDisplayName } from '../internal/utils/apply-display-name';
import { formatDateTimeWithOffset } from '../internal/utils/date-time/format-date-time-with-offset';
import { normalizeLocale } from '../internal/utils/locale';
import { joinStrings } from '../internal/utils/strings/join-strings';
import { DateRangePickerDropdown } from './dropdown';
import { normalizeTimeOffset } from './time-offset';
import { formatInitialValue, formatValue } from './utils';
import styles from './styles.css.js';
import testutilStyles from './test-classes/styles.css.js';
function renderDateRange({ locale, range, placeholder = '', formatRelativeRange, absoluteFormat, hideTimeOffset, timeOffset, }) {
    var _a;
    const firstPart = range
        ? range.type === 'relative'
            ? ((_a = formatRelativeRange === null || formatRelativeRange === void 0 ? void 0 : formatRelativeRange(range)) !== null && _a !== void 0 ? _a : '')
            : formatDateTimeWithOffset({
                date: range.startDate,
                timeOffset: timeOffset.startDate,
                hideTimeOffset,
                format: absoluteFormat,
                locale,
            })
        : placeholder;
    const secondPart = (range === null || range === void 0 ? void 0 : range.type) === 'absolute'
        ? formatDateTimeWithOffset({
            date: range.endDate,
            timeOffset: timeOffset.endDate,
            hideTimeOffset,
            format: absoluteFormat,
            locale,
        })
        : '';
    return (React.createElement("span", { className: (!range && styles['label-text']) || undefined, "aria-disabled": !range },
        React.createElement("span", { className: (range === null || range === void 0 ? void 0 : range.type) === 'absolute' ? styles['label-token-nowrap'] : undefined }, firstPart),
        React.createElement("span", null, secondPart && ' — '),
        React.createElement("span", { className: styles['label-token-nowrap'] }, secondPart)));
}
const DateRangePicker = React.forwardRef(({ locale = '', startOfWeek, isDateEnabled = () => true, dateDisabledReason, value, placeholder, readOnly = false, disabled = false, onChange, onBlur, onFocus, relativeOptions = [], i18nStrings, isValidRange = () => ({ valid: true }), showClearButton = true, dateOnly = false, ariaLabel, timeOffset, getTimeOffset, timeInputFormat = 'hh:mm:ss', dateInputFormat = 'slashed', expandToViewport = false, rangeSelectorMode = 'default', customAbsoluteRangeControl, absoluteFormat = 'iso', hideTimeOffset, customRelativeRangeUnits, renderRelativeRangeContent, granularity = 'day', ...rest }, ref) => {
    var _a, _b;
    const { __internalRootRef } = useBaseComponent('DateRangePicker', {
        props: {
            absoluteFormat,
            dateOnly,
            expandToViewport,
            rangeSelectorMode,
            readOnly,
            showClearButton,
            timeInputFormat,
            dateInputFormat,
            hideTimeOffset,
            granularity,
        },
        metadata: { hasDisabledReasons: Boolean(dateDisabledReason) },
    });
    const isMonthOnly = granularity === 'month';
    const hideTime = dateOnly || isMonthOnly;
    checkControlled('DateRangePicker', 'value', value, 'onChange', onChange);
    const normalizedTimeOffset = hideTime
        ? { startDate: undefined, endDate: undefined }
        : normalizeTimeOffset(value, getTimeOffset, timeOffset);
    value = formatInitialValue(value, dateOnly, isMonthOnly, normalizedTimeOffset);
    const baseProps = getBaseProps(rest);
    const ariaLabelId = useUniqueId('date-range-picker-arialabel-');
    const { invalid, warning, controlId, ariaDescribedby, ariaLabelledby: contextAriaLabelledby, } = useFormFieldContext({
        ariaLabelledby: (_a = rest.ariaLabelledby) !== null && _a !== void 0 ? _a : i18nStrings === null || i18nStrings === void 0 ? void 0 : i18nStrings.ariaLabelledby,
        ariaDescribedby: (_b = rest.ariaDescribedby) !== null && _b !== void 0 ? _b : i18nStrings === null || i18nStrings === void 0 ? void 0 : i18nStrings.ariaDescribedby,
        ...rest,
    });
    const ariaLabelledby = joinStrings(contextAriaLabelledby, ariaLabelId);
    const isSingleGrid = useMobile();
    const triggerRef = useRef(null);
    useForwardFocus(ref, triggerRef);
    const rootRef = useRef(null);
    const dropdownId = useUniqueId('date-range-picker-dropdown');
    const triggerContentId = useUniqueId('date-range-picker-trigger');
    useFocusTracker({ rootRef, onBlur, onFocus });
    const [isDropDownOpen, setIsDropDownOpen] = useState(false);
    const normalizedLocale = normalizeLocale('DateRangePicker', locale);
    const closeDropdown = (focusTrigger = false) => {
        var _a;
        setIsDropDownOpen(false);
        if (focusTrigger) {
            (_a = triggerRef.current) === null || _a === void 0 ? void 0 : _a.focus();
        }
    };
    const onWrapperKeyDownHandler = (event) => {
        if (event.keyCode === KeyCode.escape) {
            if (isDropDownOpen) {
                event.stopPropagation();
            }
            closeDropdown(true);
        }
    };
    const onClear = () => {
        fireNonCancelableEvent(onChange, { value: null });
    };
    const onApply = (newValue) => {
        const formattedValue = formatValue(newValue, {
            dateOnly,
            monthOnly: isMonthOnly,
            timeOffset: hideTime
                ? { startDate: undefined, endDate: undefined }
                : normalizeTimeOffset(newValue, getTimeOffset, timeOffset),
        });
        const validationResult = isValidRange(formattedValue);
        if ((validationResult === null || validationResult === void 0 ? void 0 : validationResult.valid) === false) {
            return validationResult;
        }
        if (isDevelopment) {
            if ((newValue === null || newValue === void 0 ? void 0 : newValue.type) === 'absolute') {
                const [startDateWithoutTime] = newValue.startDate.split('T');
                const [endDateWithoutTime] = newValue.endDate.split('T');
                if (!startDateWithoutTime || !endDateWithoutTime) {
                    warnOnce('DateRangePicker', 'You have provided an `isValidRange` prop that did not catch a missing start or end date.');
                }
            }
        }
        fireNonCancelableEvent(onChange, { value: formattedValue });
        return validationResult || { valid: true };
    };
    const prevDateOnly = usePrevious(dateOnly);
    useEffect(() => {
        if (prevDateOnly !== undefined && prevDateOnly !== dateOnly) {
            warnOnce('DateRangePicker', `The provided \`dateOnly\` flag has been changed from "${prevDateOnly}" to "${dateOnly}" which can lead to unexpected value format. Consider using separate components.`);
        }
    }, [prevDateOnly, dateOnly]);
    if (value && value.type !== 'absolute' && value.type !== 'relative') {
        warnOnce('DateRangePicker', 'You provided an invalid value. Reverting back to default.');
        value = null;
    }
    if (((value === null || value === void 0 ? void 0 : value.type) === 'absolute' && rangeSelectorMode === 'relative-only') ||
        ((value === null || value === void 0 ? void 0 : value.type) === 'relative' && rangeSelectorMode === 'absolute-only')) {
        warnOnce('DateRangePicker', 'The provided value does not correspond to the current range selector mode. Reverting back to default.');
        value = null;
    }
    const i18n = useInternalI18n('date-range-picker');
    const formatRelativeRange = i18n('i18nStrings.formatRelativeRange', i18nStrings === null || i18nStrings === void 0 ? void 0 : i18nStrings.formatRelativeRange, format => ({ amount, unit }) => format({ amount, unit }));
    if (isDevelopment) {
        if (!formatRelativeRange && rangeSelectorMode !== 'absolute-only') {
            warnOnce('DateRangePicker', 'A function for i18nStrings.formatRelativeRange was not provided. Relative ranges will not be correctly rendered.');
        }
    }
    const formattedDate = renderDateRange({
        locale: normalizedLocale,
        range: value,
        placeholder,
        formatRelativeRange,
        absoluteFormat,
        hideTimeOffset: hideTime || hideTimeOffset,
        timeOffset: normalizedTimeOffset,
    });
    const trigger = (React.createElement(ButtonTrigger, { ref: triggerRef, id: controlId, invalid: invalid, warning: warning, ariaLabelledby: joinStrings(ariaLabelledby, triggerContentId), ariaDescribedby: ariaDescribedby, className: clsx(testutilStyles.label, styles.label, {
            [styles['label-enabled']]: !readOnly && !disabled,
        }), hideCaret: true, onClick: () => {
            setIsDropDownOpen(true);
        }, disabled: disabled, readOnly: readOnly, ariaHasPopup: "dialog" },
        React.createElement("span", { className: styles['trigger-flexbox'] },
            React.createElement("span", { className: styles['icon-wrapper'] },
                React.createElement(InternalIcon, { name: "calendar", variant: disabled || readOnly ? 'disabled' : 'normal' })),
            React.createElement("span", { id: triggerContentId }, formattedDate))));
    const mergedRef = useMergeRefs(rootRef, __internalRootRef);
    return (React.createElement("div", { ...baseProps, ref: mergedRef, className: clsx(baseProps.className, styles.root, testutilStyles.root, absoluteFormat === 'long-localized' && !dateOnly && !isMonthOnly && styles.wide), onKeyDown: onWrapperKeyDownHandler },
        React.createElement(Dropdown, { stretchHeight: true, open: isDropDownOpen, onOutsideClick: () => closeDropdown(), trigger: trigger, expandToViewport: expandToViewport, dropdownId: dropdownId, content: 
            /* Reset form field context to prevent a wrapper form field from labelling all inputs inside the dropdown. */
            React.createElement(ResetContextsForModal, null, isDropDownOpen && (React.createElement(DateRangePickerDropdown, { startOfWeek: startOfWeek, locale: normalizedLocale, isSingleGrid: isSingleGrid, onOutsideClick: () => closeDropdown(true), value: value, showClearButton: showClearButton, isDateEnabled: isDateEnabled, dateDisabledReason: dateDisabledReason, i18nStrings: i18nStrings, onClear: onClear, onApply: onApply, getTimeOffset: getTimeOffset, timeOffset: timeOffset, relativeOptions: relativeOptions, isValidRange: isValidRange, dateOnly: dateOnly, absoluteFormat: absoluteFormat, timeInputFormat: timeInputFormat, dateInputFormat: dateInputFormat, rangeSelectorMode: rangeSelectorMode, ariaLabelledby: ariaLabelledby, ariaDescribedby: ariaDescribedby, customAbsoluteRangeControl: customAbsoluteRangeControl, customRelativeRangeUnits: customRelativeRangeUnits, renderRelativeRangeContent: renderRelativeRangeContent, granularity: granularity }))) }),
        React.createElement("div", { id: ariaLabelId, hidden: true }, ariaLabel || (i18nStrings === null || i18nStrings === void 0 ? void 0 : i18nStrings.ariaLabel))));
});
applyDisplayName(DateRangePicker, 'DateRangePicker');
export default DateRangePicker;
//# sourceMappingURL=index.js.map