var __rest = (this && this.__rest) || function (s, e) {
    var t = {};
    for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0)
        t[p] = s[p];
    if (s != null && typeof Object.getOwnPropertySymbols === "function")
        for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) {
            if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i]))
                t[p[i]] = s[p[i]];
        }
    return t;
};
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
import * as React from "react";
import { useState, useCallback, useEffect } from "react";
import { cn, debounce } from "@utils";
import { Input } from "./input";
import { keyboardKeys } from "@constants";
import { otpTextVariants } from "./otpVariants";
/**
 * OTP input component for one-time password entry
 */
export const OtpInput = React.forwardRef((_a, ref) => {
    var { initialValue, regexValidation, onChange, onBlur, onFocus, label, helperText, error = false, otpLength = 6, className, disabled = false } = _a, props = __rest(_a, ["initialValue", "regexValidation", "onChange", "onBlur", "onFocus", "label", "helperText", "error", "otpLength", "className", "disabled"]);
    const validOtpLength = Math.abs(otpLength);
    const [otpValue, setOtpValue] = useState(Array(validOtpLength).fill(""));
    const [focusedInput, setFocusedInput] = useState(initialValue ? initialValue.length - 1 : -1);
    const [isFocused, setIsFocused] = useState(false);
    // This useEffect is executed if the user has provided an initial value
    useEffect(() => {
        if (initialValue) {
            const temp = [];
            for (let i = 0; i < validOtpLength; i++) {
                temp[i] = (initialValue === null || initialValue === void 0 ? void 0 : initialValue[i]) || "";
            }
            setOtpValue(temp);
        }
    }, [validOtpLength, initialValue]);
    // isInputValid is used to check whether the input provided is valid or not
    const isInputValid = useCallback((val) => {
        const regularExpression = new RegExp(regexValidation !== null && regexValidation !== void 0 ? regexValidation : "");
        return regexValidation ? regularExpression.test(val) : /[0-9]/.test(val);
    }, [regexValidation]);
    const onInputChange = (idx) => (event) => {
        const values = [...otpValue];
        const { value } = event.target;
        values[idx] = value;
        if (isInputValid(value) || value === "") {
            setOtpValue([...values]);
            onChange === null || onChange === void 0 ? void 0 : onChange(values.join(""));
            if (idx < validOtpLength - 1 && value !== "") {
                setFocusedInput((index) => index + 1);
            }
            else if (idx !== 0 && value === "") {
                setFocusedInput((index) => index - 1);
            }
        }
    };
    // handleKeyDown is being used to react to the keyboard inputs that the user provides while the component is focused
    const handleKeyDown = useCallback((event) => {
        let currentFocused = focusedInput;
        const { key } = event;
        if (key === keyboardKeys.tab) {
            return;
        }
        switch (key) {
            case keyboardKeys.arrowLeft:
                if (currentFocused !== 0) {
                    currentFocused--;
                }
                break;
            case keyboardKeys.backspace:
                if (otpValue[currentFocused] === "" && currentFocused !== 0) {
                    currentFocused--;
                }
                break;
            case keyboardKeys.arrowRight:
                if (currentFocused < validOtpLength - 1) {
                    currentFocused++;
                }
                break;
            default:
                if (otpValue[currentFocused] === key &&
                    currentFocused < validOtpLength - 1) {
                    currentFocused++;
                }
        }
        setFocusedInput(currentFocused);
    }, [focusedInput, otpValue, validOtpLength]);
    //handlePaste is used to enter text into the component that has been copied by the user
    const handlePaste = useCallback((event) => {
        var _a;
        const pastedValue = (_a = event.clipboardData
            .getData("text")) === null || _a === void 0 ? void 0 : _a.substring(0, validOtpLength);
        const otp = [];
        for (let i = 0; i < validOtpLength; i++) {
            otp.push(isInputValid(pastedValue[i]) ? pastedValue[i] : "");
        }
        setOtpValue(otp);
        onChange === null || onChange === void 0 ? void 0 : onChange(otp.join(""));
        setFocusedInput(pastedValue.length <= validOtpLength - 1
            ? pastedValue.length
            : validOtpLength - 1);
    }, [isInputValid, onChange, validOtpLength]);
    const onFocusCallback = useCallback((event) => {
        if (!isFocused) {
            setIsFocused(true);
            onFocus === null || onFocus === void 0 ? void 0 : onFocus(event);
            setFocusedInput(Number(event.target.id));
        }
    }, [isFocused, onFocus]);
    const onBlurCallback = useCallback((event) => {
        if (isFocused) {
            setIsFocused(false);
            onBlur === null || onBlur === void 0 ? void 0 : onBlur(event);
            setFocusedInput(-1);
        }
    }, [isFocused, onBlur]);
    const handleEvents = useCallback((event) => event.type === "focus" ? onFocusCallback(event) : onBlurCallback(event), [onBlurCallback, onFocusCallback]);
    /* Debounce has been used because of the shifting focus of inputs in the otpInput component and we want the whole component
    to act like one focusable component and therefore we have debounced the whole onFocus and onBlur events in order to avoid
    the continuous firing of these events while the focused inputs inside are changing */
    // eslint-disable-next-line react-hooks/exhaustive-deps
    const handleFocusAndBlur = useCallback(debounce((event) => handleEvents(event), 50), [handleEvents]);
    return validOtpLength
        ? (_jsxs("fieldset", Object.assign({ className: cn("inline-flex flex-col gap-2 m-0 p-0 border-0 min-w-0", className), disabled: disabled, ref: ref }, props, { children: [label && (_jsx("legend", { className: cn("font-medium text-base text-secondary-500 dark:text-secondary-300 mb-2 p-0"), children: label })), _jsx("div", { className: cn("inline-flex gap-2"), onPaste: handlePaste, onBlur: handleFocusAndBlur, onFocus: handleFocusAndBlur, children: Array(validOtpLength)
                        .fill("")
                        .map((_, index) => (_jsx(Input, { index: index, handleChange: onInputChange(index), focused: focusedInput === index, handleKeyDown: handleKeyDown, value: otpValue === null || otpValue === void 0 ? void 0 : otpValue[index], id: `${index}`, error: error }, index))) }), helperText && (_jsx("div", { className: cn(otpTextVariants({ error })), children: helperText }))] })))
        : null;
});
OtpInput.displayName = "OtpInput";
//# sourceMappingURL=otp.js.map