import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime";
import { forwardRef, useRef, useImperativeHandle, useEffect, useState } from 'react';
import styled from 'styled-components';
import { defaultThemeProp } from '../../../theme';
import { useConfiguration, useFocusWithin, useI18n, useOuterEvent, useTestIds } from '../../../hooks';
import FormField from '../../FormField';
import Flex from '../../Flex';
import Icon, { registerIcon } from '../../Icon';
import * as calendarIcon from '../../Icon/icons/calendar.icon';
import DatePicker from '../Picker/DatePicker';
import { StyledFormControl } from '../../FormControl';
import { withTestIds } from '../../../utils';
import { getDateInputTestIds } from '../DateTime.test-ids';
import { getDateFormat, getDateTimeParts, parsePastedTextToDate, parseToDate, validateDate, generatePickerButtonAriaLabel } from './utils';
import StyledDateTime, { StyledDatePickerDialog, StyledDialogContent, StyledInputButton, StyledInputContainer } from './DateTime.styles';
import useAutoFocusNextInput from './useAutoFocusNextInput';
import PartInput from './PartInput';
import usePickerButton from './usePickerButton';
registerIcon(calendarIcon);
export const StyledDateInput = styled(StyledDateTime) `
  padding-inline-end: 0;
`;
StyledDateInput.defaultProps = defaultThemeProp;
const convertToCallbackParameter = (date, { year, month: monthIndex, day }) => {
    if ([year, monthIndex, day].every(Boolean)) {
        if (!validateDate(Number(year), Number(monthIndex) + 1, Number(day))) {
            return {
                valueAsISOString: '',
                valueAsTimestamp: NaN,
                state: 'invalid'
            };
        }
        date.setUTCFullYear(Number(year), Number(monthIndex), Number(day));
        return {
            valueAsISOString: date.toISOString(),
            valueAsTimestamp: date.getTime()
        };
    }
    if ([year, monthIndex, day].every(p => !p)) {
        return {
            valueAsISOString: undefined,
            valueAsTimestamp: undefined
        };
    }
    return {
        valueAsISOString: '',
        valueAsTimestamp: NaN,
        state: 'incomplete'
    };
};
const DateInput = forwardRef(function DateInput(props, ref) {
    const { locale } = useConfiguration();
    const t = useI18n();
    const { testId, value, min, max, id, label, labelHidden, info = getDateFormat(t, locale, 'date'), status, required, readOnly, disabled, onChange, onFocus, onBlur, onResolveSuggestion, showWeekNumber, picker: { renderer: PickerComp = DatePicker, rendererProps = {} } = {}, autoFocus, additionalInfo, handle, ...restProps } = props;
    const testIds = useTestIds(testId, getDateInputTestIds);
    const containerRef = useRef(null);
    const date = value !== undefined && value !== '' ? parseToDate(value) : undefined;
    const [yearInputRef, monthInputRef, dayInputRef] = [
        useRef(null),
        useRef(null),
        useRef(null)
    ];
    const [hasValue, setHasValue] = useState(!!date);
    useEffect(() => {
        setHasValue(!!(yearInputRef.current?.value || monthInputRef.current?.value || dayInputRef.current?.value));
    }, [date]);
    const pickParts = () => {
        return {
            day: dayInputRef.current?.value || undefined,
            month: monthInputRef.current?.value
                ? (Number(monthInputRef.current.value) - 1).toString()
                : undefined,
            year: yearInputRef.current?.value || undefined
        };
    };
    const currentlySelectedDate = () => {
        const parts = pickParts();
        if (Object.values(parts).every(Boolean)) {
            const year = Number(parts.year);
            const monthIndex = Number(parts.month);
            const day = Number(parts.day);
            return validateDate(year, monthIndex + 1, day)
                ? new Date(Date.UTC(year, monthIndex, day))
                : undefined;
        }
    };
    const [open, setOpen, , setPopoverRef, datePickerButtonEl, setDatePickerButtonEl] = usePickerButton();
    const inputContainerRef = useRef(null);
    const onFocusChange = (focused) => {
        const callbackParam = convertToCallbackParameter(date ? new Date(date) : new Date(), pickParts());
        if (onFocus && focused)
            onFocus(callbackParam);
        if (!focused) {
            if (inputContainerRef.current)
                inputContainerRef.current.scrollTop = 0;
            onBlur?.(callbackParam);
        }
    };
    const onInputChange = () => {
        onChange?.(convertToCallbackParameter(date ? new Date(date) : new Date(), pickParts()));
        datePickerButtonEl?.setAttribute('aria-label', generatePickerButtonAriaLabel(currentlySelectedDate(), 'date', locale, t, open));
        if (dayInputRef.current?.value || monthInputRef.current?.value || yearInputRef.current?.value) {
            setHasValue(true);
        }
        else {
            setHasValue(false);
        }
    };
    const setInputValue = (newValue) => {
        if (dayInputRef.current && monthInputRef.current && yearInputRef.current) {
            dayInputRef.current.value = newValue?.getUTCDate().toString().padStart(2, '0') ?? '';
            monthInputRef.current.value =
                (newValue && (newValue.getUTCMonth() + 1).toString().padStart(2, '0')) ?? '';
            yearInputRef.current.value = newValue?.getUTCFullYear().toString() ?? '';
            setHasValue(!!newValue);
        }
    };
    const onPaste = (e) => {
        const text = e.clipboardData.getData('text');
        const newDate = parsePastedTextToDate(text, locale, date || new Date());
        if (newDate) {
            e.preventDefault();
            setInputValue(newDate);
            onInputChange();
        }
    };
    // autoclose picker on focusing out
    useOuterEvent('focusin', [containerRef], e => {
        if (containerRef.current?.contains(e.relatedTarget))
            setOpen(false);
    });
    const displayNames = new Intl.DisplayNames(locale, { style: 'long', type: 'dateTimeField' });
    const DayInput = (_jsx(PartInput, { "data-testid": testIds.controlDay, placeholder: t('day_placeholder'), "aria-label": displayNames.of('day'), value: date?.getUTCDate(), onChange: onInputChange, size: 2, maxLength: 2, readOnly: readOnly, min: 1, max: 31, ref: dayInputRef }, 'day'));
    const MonthInput = (_jsx(PartInput, { "data-testid": testIds.controlMonth, placeholder: t('month_placeholder'), "aria-label": displayNames.of('month'), value: date ? date.getUTCMonth() + 1 : undefined, onChange: onInputChange, size: 2, maxLength: 2, readOnly: readOnly, min: 1, max: 12, ref: monthInputRef }, 'month'));
    const YearInput = (_jsx(PartInput, { "data-testid": testIds.controlYear, placeholder: t('year_placeholder'), "aria-label": displayNames.of('year'), value: date?.getUTCFullYear(), onChange: onInputChange, size: 4, maxLength: 4, padWithZeros: false, readOnly: readOnly, min: 1, ref: yearInputRef }, 'year'));
    useFocusWithin([containerRef], onFocusChange);
    useImperativeHandle(handle, () => ({ setOpen }));
    const PickerButton = (_jsxs(_Fragment, { children: [_jsx(StyledInputButton, { "data-testid": testIds.openClosePicker, variant: 'simple', icon: true, ref: setDatePickerButtonEl, onClick: () => setOpen(cur => !cur), "aria-label": generatePickerButtonAriaLabel(currentlySelectedDate(), 'date', locale, t, open), readOnly: readOnly, disabled: disabled, children: _jsx(Icon, { name: 'calendar' }) }), open && datePickerButtonEl && (_jsx(StyledDatePickerDialog, { ref: setPopoverRef, target: datePickerButtonEl, placement: 'bottom-end', "aria-label": t('choose_date'), children: _jsx(Flex, { container: { direction: 'column' }, as: StyledDialogContent, children: _jsx(PickerComp, { testId: testIds.root, selected: currentlySelectedDate(), min: min, max: max, showWeekNumber: showWeekNumber, ...rendererProps, onChange: selected => {
                            setInputValue(selected);
                            setOpen(false);
                            setTimeout(() => datePickerButtonEl?.focus());
                            onInputChange();
                            rendererProps?.onChange?.(selected);
                        } }) }) }))] }));
    const orderedRefs = [];
    const Comp = (_jsxs(Flex, { "data-testid": testIds.root, as: StyledDateInput, forwardedAs: StyledFormControl, hasSuggestion: status === 'pending' && !!onResolveSuggestion, container: { alignItems: 'center', wrap: 'nowrap', justify: 'between' }, status: status, readOnly: readOnly, disabled: disabled, ref: containerRef, onClick: (e) => {
            if (e.target === containerRef.current)
                orderedRefs[0].current?.focus();
        }, ...restProps, children: [_jsx(Flex, { ref: inputContainerRef, as: StyledInputContainer, container: { alignItems: 'center', wrap: 'wrap' }, onPaste: onPaste, children: getDateTimeParts(locale).map(part => {
                    switch (part) {
                        case 'day':
                            orderedRefs.push(dayInputRef);
                            return DayInput;
                        case 'month':
                            orderedRefs.push(monthInputRef);
                            return MonthInput;
                        case 'year':
                            orderedRefs.push(yearInputRef);
                            return YearInput;
                        default:
                            return part;
                    }
                }) }), _jsxs(Flex, { container: true, children: [!readOnly && hasValue && (_jsx(StyledInputButton, { "data-testid": testIds.clearCurrentDate, "aria-label": t('clear_current_date'), icon: true, onClick: () => {
                            setInputValue(undefined);
                            setTimeout(() => datePickerButtonEl?.focus());
                            onInputChange();
                        }, variant: 'simple', compact: true, label: t('clear'), children: _jsx(Icon, { name: 'times' }) })), !readOnly && PickerButton] })] }));
    useEffect(() => {
        if (autoFocus)
            orderedRefs[0].current?.focus();
    }, [autoFocus]);
    const { description, descriptionID } = useAutoFocusNextInput(orderedRefs);
    return label ? (_jsxs(_Fragment, { children: [_jsx(FormField, { testId: testIds, as: 'fieldset', "aria-labelledby": id, labelAs: 'legend', label: label, labelHidden: labelHidden, id: id, info: info, readOnly: readOnly, status: status, required: required, disabled: disabled, onResolveSuggestion: onResolveSuggestion, additionalInfo: additionalInfo, "aria-describedby": descriptionID, ref: ref, children: Comp }), description] })) : (Comp);
});
export default withTestIds(DateInput, getDateInputTestIds);
//# sourceMappingURL=DateInput.js.map