import { jsx, jsxs } from 'react/jsx-runtime';
import React__default, { useState, useRef, useEffect, useCallback } from 'react';
import { FormLabel } from '../FormLabel/FormLabel.js';
import { inputTheme } from './Input.theme.js';
import { cn } from '../../../utils/cn.js';
import { LockClosedIcon, EyeSlashIcon, EyeIcon } from '@heroicons/react/24/solid';
import { MagnifyingGlassIcon, MinusIcon, PlusIcon } from '@heroicons/react/24/outline';
import { validateMaskedInput, applyInputMask, getAdjustedCursorPosition } from './inputMasks.js';

const PasswordToggleButton = ({ showPassword, onToggle, passwordToggleClasses, }) => {
    const toggleIconActive = inputTheme.typeStyles.password.toggleIconActive;
    const toggleIconInactive = inputTheme.typeStyles.password.toggleIconInactive;
    return (jsx("div", { className: passwordToggleClasses, onClick: (e) => {
            e.stopPropagation();
            onToggle();
        }, "aria-label": showPassword ? "Hide password" : "Show password", role: "button", tabIndex: 0, onKeyDown: (e) => {
            if (e.key === "Enter" || e.key === " ") {
                e.preventDefault();
                onToggle();
            }
        }, children: showPassword ? (jsx(EyeSlashIcon, { className: toggleIconActive, "aria-hidden": "true" })) : (jsx(EyeIcon, { className: toggleIconInactive, "aria-hidden": "true" })) }));
};
const NumberButtons = ({ isDisabled, isAtMax, isAtMin, onIncrement, onDecrement, numberButtonsContainerClasses, numberButtonClasses, }) => {
    const incrementIconStyle = inputTheme.typeStyles.number.incrementIconStyle;
    const decrementIconStyle = inputTheme.typeStyles.number.decrementIconStyle;
    return (jsxs("div", { className: numberButtonsContainerClasses, children: [jsx("button", { type: "button", className: `${numberButtonClasses}`, onClick: (e) => {
                    e.stopPropagation();
                    onDecrement();
                }, disabled: isDisabled || isAtMin, "aria-label": "Decrease value", tabIndex: -1, children: jsx(MinusIcon, { className: cn("size-4", decrementIconStyle), "aria-hidden": "true" }) }), jsx("button", { type: "button", className: `${numberButtonClasses}`, onClick: (e) => {
                    e.stopPropagation();
                    onIncrement();
                }, disabled: isDisabled || isAtMax, "aria-label": "Increase value", tabIndex: -1, children: jsx(PlusIcon, { className: cn("size-4", incrementIconStyle), "aria-hidden": "true" }) })] }));
};
const getActiveDots = (strength) => {
    switch (strength) {
        case "weak":
            return 1;
        case "moderate":
            return 2;
        case "strong":
            return 4;
        case "very-strong":
            return 5;
        default:
            return 0;
    }
};
const PasswordStrengthIndicator = ({ inline = false, passwordStrengthIndicator, }) => {
    const strength = passwordStrengthIndicator.strength || "strong";
    const customLabel = passwordStrengthIndicator.customLabel;
    const indicatorClassName = passwordStrengthIndicator.className || "";
    const containerStyle = `${inputTheme.passwordStrengthIndicator.containerStyle} ${inline ? "" : "mt-2"}`;
    const labelStyle = inputTheme.passwordStrengthIndicator.labelStyle;
    const dotStyle = inputTheme.passwordStrengthIndicator.dotStyle;
    const dotActiveStyle = inputTheme.passwordStrengthIndicator.dotActiveStyle;
    const dotInactiveStyle = inputTheme.passwordStrengthIndicator.dotInactiveStyle;
    const strengthConfig = inputTheme.passwordStrengthIndicator
        .strengthStyles[strength] || {
        label: "Password",
        color: "text-[var(--color-text-muted)]",
    };
    const colorClass = strengthConfig.color || "text-neutral-500";
    const label = customLabel || strengthConfig.label || "Password";
    const activeDots = getActiveDots(strength);
    return (jsxs("div", { className: `${containerStyle} ${indicatorClassName} ${colorClass}`, children: [jsx("div", { className: labelStyle, children: label }), [...Array(5)].map((_, index) => (jsx("div", { className: `${dotStyle} ${index < activeDots ? dotActiveStyle : dotInactiveStyle}` }, index)))] }));
};
// ============================================================================
// Main Input Component
// ============================================================================
const Input = React__default.forwardRef(({ size = "md", state = "default", className = "", label, labelClassName = "", helperText, helperTextClassName = "", wrapperClassName = "", inputGroupClassName = "", iconStart, iconEnd, contentStart, contentEnd, keyboardShortcut, id, required, type = "text", passwordToggle = type === "password", passwordStrengthIndicator, showNumberControls = false, min, max, step = 1, onChange, onFocus, onBlur, value, currencyDecimalPlaces, darkMode = false, ...props }, ref) => {
    const [isFocused, setIsFocused] = useState(false);
    const [showPassword, setShowPassword] = useState(false);
    const generatedId = React__default.useId();
    const inputId = id || generatedId;
    const [numberValue, setNumberValue] = useState(value !== undefined
        ? typeof value === "number"
            ? value
            : typeof value === "string"
                ? parseFloat(value) || undefined
                : undefined
        : undefined);
    const inputRef = useRef(null);
    const cursorPositionRef = useRef(null);
    // Default icons based on input type
    const defaultPasswordIcon = type === "password" && !iconStart ? (jsx(LockClosedIcon, { className: "size-5 text-[var(--color-text-muted)]" })) : null;
    const defaultSearchIcon = type === "search" && !iconStart ? (jsx(MagnifyingGlassIcon, { className: cn("size-5", inputTheme.typeStyles.search.iconStyle) })) : null;
    // Use the provided iconStart or the default icon based on input type
    const finalLeftIcon = iconStart || defaultPasswordIcon || defaultSearchIcon;
    // Derived state flags for internal use
    const hasLeftIcon = Boolean(finalLeftIcon);
    const isDisabled = state === "disabled";
    const isInvalid = state === "invalid";
    const hasRightIcon = Boolean(iconEnd);
    const hasContentStart = Boolean(contentStart);
    const hasContentEnd = Boolean(contentEnd);
    const hasKeyboardShortcut = Boolean(keyboardShortcut);
    const isPasswordField = type === "password" && passwordToggle;
    const isNumberField = type === "number";
    const displayNumberControls = isNumberField && showNumberControls;
    const isMaskedInput = [
        "creditCard",
        "expiryDate",
        "phone",
        "ssn",
        "currency",
    ].includes(type);
    // Password strength indicator flags
    const hasPasswordStrength = type === "password" && (passwordStrengthIndicator === null || passwordStrengthIndicator === void 0 ? void 0 : passwordStrengthIndicator.show);
    const strengthPosition = (passwordStrengthIndicator === null || passwordStrengthIndicator === void 0 ? void 0 : passwordStrengthIndicator.position) || "right";
    const showStrengthWithLabel = hasPasswordStrength && strengthPosition === "right";
    const showStrengthBelow = hasPasswordStrength && strengthPosition === "below";
    // State class for CSS selectors
    const stateClass = isInvalid
        ? "state-invalid"
        : isDisabled
            ? "state-disabled"
            : "state-default";
    // Set the ref from forwardRef or create one
    const setInputRef = (el) => {
        inputRef.current = el;
        if (typeof ref === "function") {
            ref(el);
        }
        else if (ref) {
            ref.current = el;
        }
    };
    // Determine the actual input type to use
    const actualInputType = isPasswordField && showPassword ? "text" : isMaskedInput ? "text" : type;
    // Validate masked inputs
    useEffect(() => {
        if (isMaskedInput && value) {
            validateMaskedInput(type, value.toString());
            // Optional: Add validation state handling here if needed
        }
    }, [value, type, isMaskedInput]);
    // Sync the internal number value with the external value prop
    useEffect(() => {
        if (isNumberField && value !== undefined) {
            const parsedValue = typeof value === "number"
                ? value
                : typeof value === "string"
                    ? parseFloat(value) || undefined
                    : undefined;
            setNumberValue(parsedValue);
        }
    }, [value, isNumberField]);
    // Toggle password visibility
    const handleTogglePassword = useCallback(() => {
        if (!isDisabled) {
            setShowPassword((prev) => !prev);
        }
    }, [isDisabled]);
    // Handle input group click for addon variations - focus the input
    // Bail out when the click target is inside an interactive element (e.g. nested Select)
    const handleInputGroupClick = (e) => {
        const target = e.target;
        if (target.closest('button, [role="button"], [role="listbox"], [role="combobox"], [aria-haspopup], select, a')) {
            return;
        }
        if (!isFocused && !isDisabled && inputRef.current) {
            inputRef.current.focus();
        }
    };
    // Increment number value
    const handleIncrement = useCallback(() => {
        if (isDisabled)
            return;
        const stepValue = typeof step === "number" ? step : 1;
        const currentValue = numberValue !== undefined ? numberValue : 0;
        let newValue = currentValue + stepValue;
        // Apply constraints
        if (max !== undefined && typeof max === "number" && newValue > max) {
            newValue = max;
        }
        setNumberValue(newValue);
        updateNumberValue(newValue);
    }, [isDisabled, step, numberValue, max]);
    // Decrement number value
    const handleDecrement = useCallback(() => {
        if (isDisabled)
            return;
        const stepValue = typeof step === "number" ? step : 1;
        const currentValue = numberValue !== undefined ? numberValue : 0;
        let newValue = currentValue - stepValue;
        // Apply constraints
        if (min !== undefined && typeof min === "number" && newValue < min) {
            newValue = min;
        }
        setNumberValue(newValue);
        updateNumberValue(newValue);
    }, [isDisabled, step, numberValue, min]);
    // Update the input value and trigger onChange
    const updateNumberValue = (newValue) => {
        if (inputRef.current) {
            inputRef.current.value = newValue.toString();
            // Create and dispatch a synthetic event
            const event = new Event("input", { bubbles: true });
            inputRef.current.dispatchEvent(event);
            // Call onChange handler if provided
            if (onChange) {
                onChange(event);
            }
        }
    };
    // Handle input change
    const handleInputChange = (e) => {
        // Store original value and cursor position
        const originalValue = e.target.value;
        cursorPositionRef.current = e.target.selectionStart;
        if (isMaskedInput) {
            // Apply masking with options
            const maskedValue = applyInputMask(originalValue, type, {
                currencyDecimalPlaces: currencyDecimalPlaces,
            });
            // Update the input value
            e.target.value = maskedValue;
            // Adjust cursor position
            if (cursorPositionRef.current !== null) {
                const newCursorPosition = getAdjustedCursorPosition(originalValue, maskedValue, cursorPositionRef.current);
                // Set the cursor position after React updates the DOM
                setTimeout(() => {
                    if (inputRef.current) {
                        inputRef.current.setSelectionRange(newCursorPosition, newCursorPosition);
                    }
                }, 0);
            }
            // For currency inputs, ensure we immediately validate
            if (type === "currency" && isInvalid && onChange) {
                const event = { ...e };
                onChange(event);
            }
        }
        else if (isNumberField) {
            const value = e.target.value;
            const parsedValue = value ? parseFloat(value) : undefined;
            setNumberValue(parsedValue);
        }
        // Call the original onChange handler
        if (onChange) {
            onChange(e);
        }
    };
    // Theme classes - using simplified approach with design tokens
    const wrapperClasses = inputTheme.wrapperStyle;
    const inputGroupClasses = inputTheme.inputGroupStyle;
    const baseClasses = inputTheme.baseStyle;
    const sizeClasses = inputTheme.sizes[size];
    const stateClasses = inputTheme.states[state];
    const helperTextClasses = inputTheme.helperText;
    // Icon classes using design tokens
    const iconStartClasses = inputTheme.iconStartStyle;
    const iconEndClasses = inputTheme.iconEndStyle;
    const iconStartPadding = inputTheme.iconPadding.left;
    const iconEndPadding = inputTheme.iconPadding.right;
    // Content classes - size-aware
    const contentStyleClasses = inputTheme.contentStyle[size];
    const contentStartStyle = inputTheme.contentStartStyle;
    const contentEndStyle = inputTheme.contentEndStyle;
    // Interactive element classes
    const passwordToggleClasses = inputTheme.passwordToggleStyle;
    const numberButtonsContainerClasses = inputTheme.numberButtonsContainerStyle;
    const numberButtonClasses = inputTheme.numberButtonStyle;
    // Compute number bounds for NumberButtons
    const isAtMax = max !== undefined &&
        numberValue !== undefined &&
        typeof max === "number" &&
        numberValue >= max;
    const isAtMin = min !== undefined &&
        numberValue !== undefined &&
        typeof min === "number" &&
        numberValue <= min;
    return (jsxs("div", { className: cn(wrapperClasses, stateClass, darkMode && "dark", wrapperClassName), children: [label && (typeof label === 'string' ? (jsxs("div", { className: "flex justify-between items-center", children: [jsx(FormLabel, { htmlFor: inputId, className: labelClassName, state: state, required: required, children: label }), showStrengthWithLabel && (jsx(PasswordStrengthIndicator, { inline: true, passwordStrengthIndicator: passwordStrengthIndicator }))] })) : (jsxs("div", { className: "flex justify-between items-center", children: [label, showStrengthWithLabel && (jsx(PasswordStrengthIndicator, { inline: true, passwordStrengthIndicator: passwordStrengthIndicator }))] }))), jsx("div", { children: jsxs("div", { className: cn(inputGroupClasses, stateClasses, isFocused && (isInvalid ? inputTheme.inputGroupFocusInvalidStyle : inputTheme.inputGroupFocusStyle), inputGroupClassName), onClick: handleInputGroupClick, role: "presentation", children: [hasContentStart && (jsx("div", { "data-slot": "content-start", className: cn(contentStyleClasses, contentStartStyle), children: contentStart })), jsxs("div", { className: "relative flex-1", children: [jsx("input", { ref: setInputRef, id: inputId, type: actualInputType, className: cn(baseClasses, sizeClasses, hasLeftIcon && iconStartPadding, (hasRightIcon || isPasswordField || displayNumberControls) &&
                                        iconEndPadding, className), disabled: isDisabled, "aria-invalid": isInvalid, "aria-describedby": helperText ? `${inputId}-helper` : undefined, required: required, min: min, max: max, step: step, value: value, onChange: handleInputChange, onFocus: (e) => {
                                        setIsFocused(true);
                                        onFocus === null || onFocus === void 0 ? void 0 : onFocus(e);
                                    }, onBlur: (e) => {
                                        setIsFocused(false);
                                        onBlur === null || onBlur === void 0 ? void 0 : onBlur(e);
                                    }, placeholder: props.placeholder, ...props }), hasLeftIcon && (jsx("div", { className: iconStartClasses, children: finalLeftIcon })), hasRightIcon && !isPasswordField && !displayNumberControls && (jsx("div", { className: iconEndClasses, children: iconEnd })), isPasswordField && (jsx(PasswordToggleButton, { showPassword: showPassword, onToggle: handleTogglePassword, passwordToggleClasses: passwordToggleClasses })), displayNumberControls && (jsx(NumberButtons, { isDisabled: isDisabled, isAtMax: isAtMax, isAtMin: isAtMin, onIncrement: handleIncrement, onDecrement: handleDecrement, numberButtonsContainerClasses: numberButtonsContainerClasses, numberButtonClasses: numberButtonClasses })), hasKeyboardShortcut && (jsx("div", { className: inputTheme.keyboardShortcutStyle, children: keyboardShortcut }))] }), hasContentEnd && (jsx("div", { "data-slot": "content-end", className: cn(contentStyleClasses, contentEndStyle), children: contentEnd }))] }) }), showStrengthBelow && jsx(PasswordStrengthIndicator, { inline: false, passwordStrengthIndicator: passwordStrengthIndicator }), helperText && (typeof helperText === 'string' ? (jsx("div", { id: `${inputId}-helper`, className: cn(helperTextClasses, helperTextClassName), children: helperText })) : (helperText))] }));
});
Input.displayName = "Input";

export { Input };
