"use strict";
'use client';
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);
};
var __importDefault = (this && this.__importDefault) || function (mod) {
    return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
var jsx_runtime_1 = require("react/jsx-runtime");
var react_1 = require("react");
var date_utils_1 = require("@wojtekmaj/date-utils");
var Divider_js_1 = __importDefault(require("./Divider.js"));
var Hour12Input_js_1 = __importDefault(require("./TimeInput/Hour12Input.js"));
var Hour24Input_js_1 = __importDefault(require("./TimeInput/Hour24Input.js"));
var MinuteInput_js_1 = __importDefault(require("./TimeInput/MinuteInput.js"));
var SecondInput_js_1 = __importDefault(require("./TimeInput/SecondInput.js"));
var NativeInput_js_1 = __importDefault(require("./TimeInput/NativeInput.js"));
var AmPm_js_1 = __importDefault(require("./TimeInput/AmPm.js"));
var dateFormatter_js_1 = require("./shared/dateFormatter.js");
var dates_js_1 = require("./shared/dates.js");
var utils_js_1 = require("./shared/utils.js");
var getFormatterOptionsCache = {};
var allViews = ['hour', 'minute', 'second'];
function isInternalInput(element) {
    return element.dataset.input === 'true';
}
function findInput(element, property) {
    var nextElement = element;
    do {
        nextElement = nextElement[property];
    } while (nextElement && !isInternalInput(nextElement));
    return nextElement;
}
function focus(element) {
    if (element) {
        element.focus();
    }
}
function renderCustomInputs(placeholder, elementFunctions, allowMultipleInstances) {
    var usedFunctions = [];
    var pattern = new RegExp(Object.keys(elementFunctions)
        .map(function (el) { return "".concat(el, "+"); })
        .join('|'), 'g');
    var matches = placeholder.match(pattern);
    return placeholder.split(pattern).reduce(function (arr, element, index) {
        var divider = element && (
        // eslint-disable-next-line react/no-array-index-key
        (0, jsx_runtime_1.jsx)(Divider_js_1.default, { children: element }, "separator_".concat(index)));
        arr.push(divider);
        var currentMatch = matches && matches[index];
        if (currentMatch) {
            var renderFunction = elementFunctions[currentMatch] ||
                elementFunctions[Object.keys(elementFunctions).find(function (elementFunction) {
                    return currentMatch.match(elementFunction);
                })];
            if (!renderFunction) {
                return arr;
            }
            if (!allowMultipleInstances && usedFunctions.includes(renderFunction)) {
                arr.push(currentMatch);
            }
            else {
                arr.push(renderFunction(currentMatch, index));
                usedFunctions.push(renderFunction);
            }
        }
        return arr;
    }, []);
}
var formatNumber = (0, dateFormatter_js_1.getNumberFormatter)({ useGrouping: false });
function TimeInput(_a) {
    var amPmAriaLabel = _a.amPmAriaLabel, autoFocus = _a.autoFocus, className = _a.className, disabled = _a.disabled, format = _a.format, hourAriaLabel = _a.hourAriaLabel, hourPlaceholder = _a.hourPlaceholder, _b = _a.isClockOpen, isClockOpenProps = _b === void 0 ? null : _b, locale = _a.locale, _c = _a.maxDetail, maxDetail = _c === void 0 ? 'minute' : _c, maxTime = _a.maxTime, minTime = _a.minTime, minuteAriaLabel = _a.minuteAriaLabel, minutePlaceholder = _a.minutePlaceholder, _d = _a.name, name = _d === void 0 ? 'time' : _d, nativeInputAriaLabel = _a.nativeInputAriaLabel, onChangeProps = _a.onChange, onInvalidChange = _a.onInvalidChange, required = _a.required, secondAriaLabel = _a.secondAriaLabel, secondPlaceholder = _a.secondPlaceholder, valueProps = _a.value;
    var _e = (0, react_1.useState)(null), amPm = _e[0], setAmPm = _e[1];
    var _f = (0, react_1.useState)(null), hour = _f[0], setHour = _f[1];
    var _g = (0, react_1.useState)(null), minute = _g[0], setMinute = _g[1];
    var _h = (0, react_1.useState)(null), second = _h[0], setSecond = _h[1];
    var _j = (0, react_1.useState)(null), value = _j[0], setValue = _j[1];
    var amPmInput = (0, react_1.useRef)(null);
    var hour12Input = (0, react_1.useRef)(null);
    var hour24Input = (0, react_1.useRef)(null);
    var minuteInput = (0, react_1.useRef)(null);
    var secondInput = (0, react_1.useRef)(null);
    var _k = (0, react_1.useState)(isClockOpenProps), isClockOpen = _k[0], setIsClockOpen = _k[1];
    var lastPressedKey = (0, react_1.useRef)(undefined);
    (0, react_1.useEffect)(function () {
        setIsClockOpen(isClockOpenProps);
    }, [isClockOpenProps]);
    (0, react_1.useEffect)(function () {
        var nextValue = valueProps;
        if (nextValue) {
            setAmPm((0, dates_js_1.convert24to12)((0, date_utils_1.getHours)(nextValue))[1]);
            setHour((0, date_utils_1.getHours)(nextValue).toString());
            setMinute((0, date_utils_1.getMinutes)(nextValue).toString());
            setSecond((0, date_utils_1.getSeconds)(nextValue).toString());
            setValue(nextValue);
        }
        else {
            setAmPm(null);
            setHour(null);
            setMinute(null);
            setSecond(null);
            setValue(null);
        }
    }, [
        valueProps,
        minTime,
        maxTime,
        maxDetail,
        // Toggling clock visibility resets values
        isClockOpen,
    ]);
    var valueType = maxDetail;
    var formatTime = (function () {
        var level = allViews.indexOf(maxDetail);
        var formatterOptions = getFormatterOptionsCache[level] ||
            (function () {
                var options = { hour: 'numeric' };
                if (level >= 1) {
                    options.minute = 'numeric';
                }
                if (level >= 2) {
                    options.second = 'numeric';
                }
                getFormatterOptionsCache[level] = options;
                return options;
            })();
        return (0, dateFormatter_js_1.getFormatter)(formatterOptions);
    })();
    /**
     * Gets current value in a desired format.
     */
    function getProcessedValue(value) {
        var processFunction = (function () {
            switch (valueType) {
                case 'hour':
                case 'minute':
                    return date_utils_1.getHoursMinutes;
                case 'second':
                    return date_utils_1.getHoursMinutesSeconds;
                default:
                    throw new Error('Invalid valueType');
            }
        })();
        return processFunction(value);
    }
    var placeholder = format ||
        (function () {
            var hour24 = 21;
            var hour12 = 9;
            var minute = 13;
            var second = 14;
            var date = new Date(2017, 0, 1, hour24, minute, second);
            return formatTime(locale, date)
                .replace(formatNumber(locale, hour12), 'h')
                .replace(formatNumber(locale, hour24), 'H')
                .replace(formatNumber(locale, minute), 'mm')
                .replace(formatNumber(locale, second), 'ss')
                .replace(new RegExp((0, utils_js_1.getAmPmLabels)(locale).join('|')), 'a');
        })();
    var divider = (function () {
        var dividers = placeholder.match(/[^0-9a-z]/i);
        return dividers ? dividers[0] : null;
    })();
    function onClick(event) {
        if (event.target === event.currentTarget) {
            // Wrapper was directly clicked
            var firstInput = event.target.children[1];
            focus(firstInput);
        }
    }
    function onKeyDown(event) {
        lastPressedKey.current = event.key;
        switch (event.key) {
            case 'ArrowLeft':
            case 'ArrowRight':
            case divider: {
                event.preventDefault();
                var input = event.target;
                var property = event.key === 'ArrowLeft' ? 'previousElementSibling' : 'nextElementSibling';
                var nextInput = findInput(input, property);
                focus(nextInput);
                break;
            }
            default:
        }
    }
    function onKeyUp(event) {
        var key = event.key, input = event.target;
        var isLastPressedKey = lastPressedKey.current === key;
        if (!isLastPressedKey) {
            return;
        }
        var isNumberKey = !isNaN(Number(key));
        if (!isNumberKey) {
            return;
        }
        var max = input.getAttribute('max');
        if (!max) {
            return;
        }
        var value = input.value;
        /**
         * Given 1, the smallest possible number the user could type by adding another digit is 10.
         * 10 would be a valid value given max = 12, so we won't jump to the next input.
         * However, given 2, smallers possible number would be 20, and thus keeping the focus in
         * this field doesn't make sense.
         */
        if (Number(value) * 10 > Number(max) || value.length >= max.length) {
            var property = 'nextElementSibling';
            var nextInput = findInput(input, property);
            focus(nextInput);
        }
    }
    /**
     * Called after internal onChange. Checks input validity. If all fields are valid,
     * calls props.onChange.
     */
    function onChangeExternal() {
        if (!onChangeProps) {
            return;
        }
        function filterBoolean(value) {
            return Boolean(value);
        }
        var formElements = [
            amPmInput.current,
            hour12Input.current,
            hour24Input.current,
            minuteInput.current,
            secondInput.current,
        ].filter(filterBoolean);
        var formElementsWithoutSelect = formElements.slice(1);
        var values = {};
        formElements.forEach(function (formElement) {
            values[formElement.name] =
                formElement.type === 'number'
                    ? 'valueAsNumber' in formElement
                        ? formElement.valueAsNumber
                        : Number(formElement.value)
                    : formElement.value;
        });
        var isEveryValueEmpty = formElementsWithoutSelect.every(function (formElement) { return !formElement.value; });
        if (isEveryValueEmpty) {
            onChangeProps(null, false);
            return;
        }
        var isEveryValueFilled = formElements.every(function (formElement) { return formElement.value; });
        var isEveryValueValid = formElements.every(function (formElement) { return formElement.validity.valid; });
        if (isEveryValueFilled && isEveryValueValid) {
            var hour_1 = Number(values.hour24 ||
                (values.hour12 && values.amPm && (0, dates_js_1.convert12to24)(values.hour12, values.amPm)) ||
                0);
            var minute_1 = Number(values.minute || 0);
            var second_1 = Number(values.second || 0);
            var padStart = function (num) { return "0".concat(num).slice(-2); };
            var proposedValue = "".concat(padStart(hour_1), ":").concat(padStart(minute_1), ":").concat(padStart(second_1));
            var processedValue = getProcessedValue(proposedValue);
            onChangeProps(processedValue, false);
            return;
        }
        if (!onInvalidChange) {
            return;
        }
        onInvalidChange();
    }
    /**
     * Called when non-native date input is changed.
     */
    function onChange(event) {
        var _a = event.target, name = _a.name, value = _a.value;
        switch (name) {
            case 'amPm':
                setAmPm(value);
                break;
            case 'hour12':
                setHour(value ? (0, dates_js_1.convert12to24)(value, amPm || 'am').toString() : '');
                break;
            case 'hour24':
                setHour(value);
                break;
            case 'minute':
                setMinute(value);
                break;
            case 'second':
                setSecond(value);
                break;
        }
        onChangeExternal();
    }
    /**
     * Called when native date input is changed.
     */
    function onChangeNative(event) {
        var value = event.target.value;
        if (!onChangeProps) {
            return;
        }
        var processedValue = value || null;
        onChangeProps(processedValue, false);
    }
    var commonInputProps = {
        className: className,
        disabled: disabled,
        maxTime: maxTime,
        minTime: minTime,
        onChange: onChange,
        onKeyDown: onKeyDown,
        onKeyUp: onKeyUp,
        // This is only for showing validity when editing
        required: Boolean(required || isClockOpen),
    };
    function renderHour12(currentMatch, index) {
        if (currentMatch && currentMatch.length > 2) {
            throw new Error("Unsupported token: ".concat(currentMatch));
        }
        var showLeadingZeros = currentMatch ? currentMatch.length === 2 : false;
        return ((0, jsx_runtime_1.jsx)(Hour12Input_js_1.default, __assign({}, commonInputProps, { amPm: amPm, ariaLabel: hourAriaLabel, 
            // eslint-disable-next-line jsx-a11y/no-autofocus
            autoFocus: index === 0 && autoFocus, inputRef: hour12Input, placeholder: hourPlaceholder, showLeadingZeros: showLeadingZeros, value: hour }), "hour12"));
    }
    function renderHour24(currentMatch, index) {
        if (currentMatch && currentMatch.length > 2) {
            throw new Error("Unsupported token: ".concat(currentMatch));
        }
        var showLeadingZeros = currentMatch ? currentMatch.length === 2 : false;
        return ((0, jsx_runtime_1.jsx)(Hour24Input_js_1.default, __assign({}, commonInputProps, { ariaLabel: hourAriaLabel, 
            // eslint-disable-next-line jsx-a11y/no-autofocus
            autoFocus: index === 0 && autoFocus, inputRef: hour24Input, placeholder: hourPlaceholder, showLeadingZeros: showLeadingZeros, value: hour }), "hour24"));
    }
    function renderHour(currentMatch, index) {
        if (/h/.test(currentMatch)) {
            return renderHour12(currentMatch, index);
        }
        return renderHour24(currentMatch, index);
    }
    function renderMinute(currentMatch, index) {
        if (currentMatch && currentMatch.length > 2) {
            throw new Error("Unsupported token: ".concat(currentMatch));
        }
        var showLeadingZeros = currentMatch ? currentMatch.length === 2 : false;
        return ((0, jsx_runtime_1.jsx)(MinuteInput_js_1.default, __assign({}, commonInputProps, { ariaLabel: minuteAriaLabel, 
            // eslint-disable-next-line jsx-a11y/no-autofocus
            autoFocus: index === 0 && autoFocus, hour: hour, inputRef: minuteInput, placeholder: minutePlaceholder, showLeadingZeros: showLeadingZeros, value: minute }), "minute"));
    }
    function renderSecond(currentMatch, index) {
        if (currentMatch && currentMatch.length > 2) {
            throw new Error("Unsupported token: ".concat(currentMatch));
        }
        var showLeadingZeros = currentMatch ? currentMatch.length === 2 : true;
        return ((0, jsx_runtime_1.jsx)(SecondInput_js_1.default, __assign({}, commonInputProps, { ariaLabel: secondAriaLabel, 
            // eslint-disable-next-line jsx-a11y/no-autofocus
            autoFocus: index === 0 && autoFocus, hour: hour, inputRef: secondInput, minute: minute, placeholder: secondPlaceholder, showLeadingZeros: showLeadingZeros, value: second }), "second"));
    }
    function renderAmPm(currentMatch, index) {
        return ((0, jsx_runtime_1.jsx)(AmPm_js_1.default, __assign({}, commonInputProps, { ariaLabel: amPmAriaLabel, 
            // eslint-disable-next-line jsx-a11y/no-autofocus
            autoFocus: index === 0 && autoFocus, inputRef: amPmInput, locale: locale, onChange: onChange, value: amPm }), "ampm"));
    }
    function renderCustomInputsInternal() {
        var elementFunctions = {
            h: renderHour,
            H: renderHour,
            m: renderMinute,
            s: renderSecond,
            a: renderAmPm,
        };
        var allowMultipleInstances = typeof format !== 'undefined';
        return renderCustomInputs(placeholder, elementFunctions, allowMultipleInstances);
    }
    function renderNativeInput() {
        return ((0, jsx_runtime_1.jsx)(NativeInput_js_1.default, { ariaLabel: nativeInputAriaLabel, disabled: disabled, maxTime: maxTime, minTime: minTime, name: name, onChange: onChangeNative, required: required, value: value, valueType: valueType }, "time"));
    }
    return (
    // eslint-disable-next-line jsx-a11y/click-events-have-key-events, jsx-a11y/no-static-element-interactions
    (0, jsx_runtime_1.jsxs)("div", { className: className, onClick: onClick, children: [renderNativeInput(), renderCustomInputsInternal()] }));
}
exports.default = TimeInput;
