import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
import { useRef, forwardRef, useEffect, useState } from 'react';
import styled from 'styled-components';
import FormField from '../../FormField';
import Flex from '../../Flex';
import Select, { Option } from '../../Select';
import Icon, { registerIcon } from '../../Icon';
import * as clockIcon from '../../Icon/icons/clock.icon';
import Popover from '../../Popover';
import TimePicker from '../Picker/TimePicker';
import { useConfiguration, useConsolidatedRef, useFocusWithin, useI18n, useTestIds } from '../../../hooks';
import { StyledFormControl } from '../../FormControl';
import { sameWidth } from '../../Popover/modifiers';
import { createClassName, hasProp, withTestIds } from '../../../utils';
import { getTimeInputTestIds } from '../DateTime.test-ids';
import { getAdjustedUTCDateTime } from '../utils';
import { getDateFormat, getDateTimeParts, parseToDate, is12HClockFormat, validateTime, getTimeOptions } from './utils';
import StyledDateTime, { StyledInputContainer, StyledInputButton } from './DateTime.styles';
import PartInput from './PartInput';
import usePickerButton from './usePickerButton';
import useAutoFocusNextInput from './useAutoFocusNextInput';
registerIcon(clockIcon);
export const StyledTimeInput = styled(StyledDateTime) `
  padding-inline-end: 0;
`;
function getMeridiem(hour) {
    return hour && hour >= 12 ? 'PM' : 'AM';
}
const convertTo12h = (hour) => {
    let converted = hour;
    if (hour > 12)
        converted = hour - 12;
    else if (hour === 0)
        converted = 12;
    return converted;
};
const convertTo24h = (hour, meridiem) => {
    let converted = hour;
    if (meridiem === 'PM' && hour < 12)
        converted = hour + 12;
    else if (meridiem === 'AM' && hour === 12)
        converted = 0;
    return converted;
};
const convertToCallbackParameter = (date, parts) => {
    const resultDate = Number.isNaN(date.getTime())
        ? new Date(new Date().setUTCHours(0, 0, 0, 0))
        : new Date(date);
    const withSeconds = hasProp(parts, 'second');
    const { hour, minute, second = resultDate.getUTCSeconds().toString(), dayPeriod: meridiem } = parts;
    const toValidate = withSeconds ? [hour, minute, second] : [hour, minute];
    if (toValidate.every(Boolean)) {
        const is12h = meridiem !== undefined;
        if (!validateTime(Number(hour), Number(minute), Number(second), 0, is12h)) {
            return {
                valueAsISOString: '',
                valueAsTimestamp: NaN,
                state: 'invalid'
            };
        }
        resultDate.setUTCHours(is12h ? convertTo24h(Number(hour), meridiem) : Number(hour), Number(minute), Number(second), date.getUTCMilliseconds() || 0);
        return {
            valueAsISOString: resultDate.toISOString(),
            valueAsTimestamp: resultDate.getTime()
        };
    }
    if ([hour, minute].every(p => !p)) {
        return {
            valueAsISOString: undefined,
            valueAsTimestamp: undefined
        };
    }
    return {
        valueAsISOString: '',
        valueAsTimestamp: NaN,
        state: 'incomplete'
    };
};
const TimeInput = forwardRef(function TimeInput(props, ref) {
    const { locale } = useConfiguration();
    const t = useI18n();
    const { testId, value, id, label, labelHidden, status, withSeconds = false, pickerInterval = 30, clockFormat, info = getDateFormat(t, locale, withSeconds ? 'time+seconds' : 'time'), required, readOnly, disabled, onChange, onFocus, onBlur, onResolveSuggestion, autoFocus, additionalInfo, className, ...restProps } = props;
    const testIds = useTestIds(testId, getTimeInputTestIds);
    const date = value !== undefined && value !== '' ? parseToDate(value) : undefined;
    const is12h = clockFormat ? clockFormat === 12 : is12HClockFormat(locale);
    const [hourInputRef, minuteInputRef, secondInputRef, meridiemSelectRef] = [
        useRef(null),
        useRef(null),
        useRef(null),
        useRef(null)
    ];
    const [hasValue, setHasValue] = useState(!!date);
    useEffect(() => {
        setHasValue(!!(hourInputRef.current?.value ||
            minuteInputRef.current?.value ||
            (withSeconds && secondInputRef.current?.value)));
    }, [date]);
    const { description, descriptionID } = useAutoFocusNextInput([
        hourInputRef,
        minuteInputRef,
        secondInputRef
    ]);
    const pickParts = () => {
        const parts = {
            hour: hourInputRef.current?.value || undefined,
            minute: minuteInputRef.current?.value || undefined
        };
        if (withSeconds)
            parts.second = secondInputRef.current?.value;
        if (is12h)
            parts.dayPeriod = meridiemSelectRef.current?.value;
        return parts;
    };
    const currentlySelectedTime = () => {
        const parts = pickParts();
        if (Object.values(parts).every(Boolean)) {
            const hour = Number(parts.hour);
            const minute = Number(parts.minute);
            const second = parts.second ? Number(parts.second) : 0;
            const current = date !== undefined ? new Date(date) : getAdjustedUTCDateTime();
            return validateTime(hour, minute, second, 0, is12h)
                ? new Date(current.setUTCHours(is12h ? convertTo24h(hour, parts.dayPeriod) : hour, minute, second, date?.getUTCMilliseconds() || 0))
                : undefined;
        }
    };
    const [open, setOpen, , setPopoverRef, timePickerButtonEl, setTimePickerButtonEl] = 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()));
        setHasValue(!!(hourInputRef.current?.value ||
            minuteInputRef.current?.value ||
            (withSeconds && secondInputRef.current?.value)));
    };
    useEffect(() => {
        if (is12h && meridiemSelectRef.current) {
            meridiemSelectRef.current.value = getMeridiem(date?.getUTCHours());
        }
    }, [is12h, date?.getUTCHours()]);
    const displayNames = new Intl.DisplayNames(locale, { style: 'long', type: 'dateTimeField' });
    const hour = date && is12h ? convertTo12h(date.getUTCHours()) : date?.getUTCHours();
    const HourInput = (_jsx(PartInput, { "data-testid": testIds.controlHour, placeholder: t('hour_placeholder'), "aria-label": displayNames.of('hour'), value: hour, onChange: onInputChange, size: 2, maxLength: 2, readOnly: readOnly, min: is12h ? 1 : 0, max: is12h ? 12 : 23, ref: hourInputRef, autoFocus: autoFocus }, 'hour'));
    const MinuteInput = (_jsx(PartInput, { "data-testid": testIds.controlMinute, placeholder: t('minute_placeholder'), "aria-label": displayNames.of('minute'), value: date?.getUTCMinutes(), onChange: onInputChange, size: 2, maxLength: 2, readOnly: readOnly, max: 59, ref: minuteInputRef }, 'minute'));
    const SecondInput = (_jsx(PartInput, { "data-testid": testIds.controlSecond, placeholder: t('second_placeholder'), "aria-label": displayNames.of('second'), value: date?.getUTCSeconds(), onChange: onInputChange, size: 2, maxLength: 2, readOnly: readOnly, max: 59, ref: secondInputRef }, 'second'));
    const Period = (_jsxs(Select, { "data-testid": testIds.controlPeriod, ref: meridiemSelectRef, "aria-label": displayNames.of('dayPeriod'), required: required, disabled: disabled, onChange: () => {
            if (Object.values(pickParts()).every(Boolean))
                onInputChange();
        }, readOnly: readOnly, children: [_jsx(Option, { value: 'AM', children: t('meridiem_value_am') }), _jsx(Option, { value: 'PM', children: t('meridiem_value_pm') })] }, 'period'));
    const containerRef = useConsolidatedRef(ref);
    useFocusWithin([containerRef], onFocusChange);
    const Picker = (_jsxs(_Fragment, { children: [_jsx(StyledInputButton, { "data-testid": testIds.openClosePicker, variant: 'simple', icon: true, ref: setTimePickerButtonEl, onClick: () => setOpen(cur => !cur), "aria-label": t(open ? 'close_time_button_a11y' : 'open_time_button_a11y'), readOnly: readOnly, disabled: disabled, children: _jsx(Icon, { name: 'clock' }) }), _jsx(Popover, { show: open, ref: setPopoverRef, target: containerRef.current, placement: 'bottom-end', strategy: 'fixed', modifiers: [sameWidth], children: _jsx(TimePicker, { testId: testIds.picker, selected: currentlySelectedTime(), interval: pickerInterval, onSelect: selected => {
                        hourInputRef.current.value = (is12h ? convertTo12h(selected.getUTCHours()) : selected.getUTCHours())
                            .toString()
                            .padStart(2, '0');
                        minuteInputRef.current.value = selected.getUTCMinutes().toString().padStart(2, '0');
                        if (withSeconds)
                            secondInputRef.current.value = selected.getUTCSeconds().toString().padStart(2, '0');
                        if (meridiemSelectRef.current) {
                            meridiemSelectRef.current.value = getMeridiem(selected.getUTCHours());
                        }
                        setOpen(false);
                        setTimeout(() => timePickerButtonEl?.focus());
                        onInputChange();
                    }, clockFormat: clockFormat }) })] }));
    const Comp = (_jsxs(Flex, { "data-testid": label ? undefined : testIds.root, as: StyledTimeInput, 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)
                hourInputRef.current?.focus();
        }, ...restProps, className: createClassName('time-input', className), children: [_jsx(Flex, { ref: inputContainerRef, as: StyledInputContainer, container: { alignItems: 'center', wrap: 'wrap' }, children: getDateTimeParts(locale, getTimeOptions(withSeconds, is12h)).map(part => {
                    switch (part) {
                        case 'hour':
                            return HourInput;
                        case 'minute':
                            return MinuteInput;
                        case 'second':
                            return SecondInput;
                        case 'dayPeriod':
                            return Period;
                        default:
                            return part;
                    }
                }) }), !readOnly && (_jsxs(Flex, { container: true, children: [hasValue && (_jsx(StyledInputButton, { "data-testid": testIds.clearCurrentTime, "aria-label": t('clear_current_time'), icon: true, onClick: () => {
                            hourInputRef.current.value = '';
                            minuteInputRef.current.value = '';
                            if (withSeconds)
                                secondInputRef.current.value = '';
                            if (is12h)
                                meridiemSelectRef.current.value = t('meridiem_value_am');
                            setTimeout(() => timePickerButtonEl?.focus());
                            onInputChange();
                        }, variant: 'simple', compact: true, label: t('clear'), children: _jsx(Icon, { name: 'times' }) })), Picker] }))] }));
    return label ? (_jsxs(_Fragment, { children: [_jsx(FormField, { testId: testIds, as: 'fieldset', 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(TimeInput, getTimeInputTestIds);
//# sourceMappingURL=TimeInput.js.map