import { cleanValue } from "./utils/cleanValue.js";
import { fixedDecimalValue } from "./utils/fixedDecimalValue.js";
import { getSuffix } from "./utils/getSuffix.js";
import { formatValue } from "./utils/formatValue.js";
import { getLocaleConfig } from "./utils/getLocaleConfig.js";
import { isNumber } from "./utils/isNumber.js";
import { padTrimValue } from "./utils/padTrimValue.js";
import { repositionCursor } from "./utils/repositionCursor.js";
import { useEffect, useMemo, useState } from "react";
//#region src/hooks/useNumberInput/useNumberInput.tsx
function useNumberInput({ allowDecimals = true, allowNegativeValue = false, decimalsLimit, maxLength: userMaxLength, value: userValue, onChange, fixedDecimalLength, decimalScale, prefix, suffix, intlConfig, step, min, max, disableGroupSeparators = false, disableAbbreviations = false, decimalSeparator: _decimalSeparator, groupSeparator: _groupSeparator, transformRawValue, formatValueOnBlur = true, ref }) {
	if (_decimalSeparator && isNumber(_decimalSeparator)) throw new Error("decimalSeparator cannot be a number");
	if (_groupSeparator && isNumber(_groupSeparator)) throw new Error("groupSeparator cannot be a number");
	const localeConfig = useMemo(() => getLocaleConfig(intlConfig), [intlConfig]);
	const decimalSeparator = _decimalSeparator || localeConfig.decimalSeparator || "";
	const groupSeparator = _groupSeparator || localeConfig.groupSeparator || "";
	if (decimalSeparator && groupSeparator && decimalSeparator === groupSeparator && disableGroupSeparators === false) throw new Error("decimalSeparator cannot be the same as groupSeparator");
	const formatValueOptions = {
		decimalSeparator,
		groupSeparator,
		disableGroupSeparators,
		intlConfig,
		prefix: prefix || localeConfig.prefix,
		suffix
	};
	const cleanValueOptions = {
		decimalSeparator,
		groupSeparator,
		allowDecimals,
		decimalsLimit: decimalsLimit || fixedDecimalLength || 2,
		allowNegativeValue,
		disableAbbreviations,
		prefix: prefix || localeConfig.prefix,
		transformRawValue
	};
	const [stateValue, setStateValue] = useState(() => userValue != null ? formatValue({
		...formatValueOptions,
		decimalScale,
		value: String(userValue)
	}) : "");
	const [dirty, setDirty] = useState(false);
	const [cursor, setCursor] = useState(0);
	const [changeCount, setChangeCount] = useState(0);
	const [lastKeyStroke, setLastKeyStroke] = useState(null);
	/**
	* Process change in value
	*/
	const processChange = (value, selectionStart) => {
		setDirty(true);
		const { modifiedValue, cursorPosition } = repositionCursor({
			selectionStart,
			value,
			lastKeyStroke,
			stateValue,
			groupSeparator
		});
		const stringValue = cleanValue({
			value: modifiedValue,
			...cleanValueOptions
		});
		if (userMaxLength && stringValue.replace(/-/g, "").length > userMaxLength) return;
		if (stringValue === "" || stringValue === "-" || stringValue === decimalSeparator) {
			onChange && onChange("", {
				float: null,
				formatted: "",
				value: ""
			});
			setStateValue(stringValue);
			setCursor(1);
			return;
		}
		const stringValueWithoutSeparator = decimalSeparator ? stringValue.replace(decimalSeparator, ".") : stringValue;
		const numberValue = parseFloat(stringValueWithoutSeparator);
		const formattedValue = formatValue({
			value: stringValue,
			...formatValueOptions
		});
		if (cursorPosition != null) {
			let newCursor = cursorPosition + (formattedValue.length - value.length);
			newCursor = newCursor <= 0 ? prefix ? prefix.length : 0 : newCursor;
			setCursor(newCursor);
			setChangeCount(changeCount + 1);
		}
		setStateValue(formattedValue);
		if (onChange) onChange(stringValue, {
			float: numberValue,
			formatted: formattedValue,
			value: stringValue
		});
	};
	/**
	* Handle change event
	*/
	const handleOnChange = (event) => {
		const { target: { value, selectionStart } } = event;
		processChange(value, selectionStart);
	};
	/**
	* Handle focus event
	*/
	const handleOnFocus = (event) => {
		return stateValue ? stateValue.length : 0;
	};
	/**
	* Handle blur event
	*
	* Format value by padding/trimming decimals if required by
	*/
	const handleOnBlur = (event) => {
		const { target: { value } } = event;
		const valueOnly = cleanValue({
			value,
			...cleanValueOptions
		});
		if (valueOnly === "-" || valueOnly === decimalSeparator || !valueOnly) {
			setStateValue("");
			return;
		}
		const newValue = padTrimValue(fixedDecimalValue(valueOnly, decimalSeparator, fixedDecimalLength), decimalSeparator, decimalScale !== void 0 ? decimalScale : fixedDecimalLength);
		const numberValue = parseFloat(newValue.replace(decimalSeparator, "."));
		const formattedValue = formatValue({
			...formatValueOptions,
			value: newValue
		});
		if (onChange && formatValueOnBlur) onChange(newValue, {
			float: numberValue,
			formatted: formattedValue,
			value: newValue
		});
		setStateValue(formattedValue);
	};
	/**
	* Handle key down event
	*
	* Increase or decrease value by step
	*/
	const handleOnKeyDown = (event) => {
		const { key } = event;
		setLastKeyStroke(key);
		if (step && (key === "ArrowUp" || key === "ArrowDown")) {
			event.preventDefault();
			setCursor(stateValue.length);
			const currentValue = parseFloat(userValue != null ? String(userValue).replace(decimalSeparator, ".") : cleanValue({
				value: stateValue,
				...cleanValueOptions
			})) || 0;
			const newValue = key === "ArrowUp" ? currentValue + step : currentValue - step;
			if (min !== void 0 && newValue < Number(min)) return;
			if (max !== void 0 && newValue > Number(max)) return;
			const fixedLength = String(step).includes(".") ? Number(String(step).split(".")[1].length) : void 0;
			processChange(String(fixedLength ? newValue.toFixed(fixedLength) : newValue).replace(".", decimalSeparator));
		}
	};
	/**
	* Handle key up event
	*
	* Move cursor if there is a suffix to prevent user typing past suffix
	*/
	const handleOnKeyUp = (event) => {
		const { key, currentTarget: { selectionStart } } = event;
		if (key !== "ArrowUp" && key !== "ArrowDown" && stateValue !== "-") {
			const suffix = getSuffix(stateValue, {
				groupSeparator,
				decimalSeparator
			});
			if (suffix && selectionStart && selectionStart > stateValue.length - suffix.length) {
				if (ref && ref.current) {
					const newCursor = stateValue.length - suffix.length;
					ref.current.setSelectionRange(newCursor, newCursor);
				}
			}
		}
	};
	useEffect(() => {
		if (userValue == null) setStateValue("");
	}, [userValue]);
	useEffect(() => {
		if (dirty && stateValue !== "-" && ref && ref.current && document.activeElement === ref.current) ref.current.setSelectionRange(cursor, cursor);
	}, [
		stateValue,
		cursor,
		ref,
		dirty,
		changeCount
	]);
	/**
	* If user has only entered "-" or decimal separator,
	* keep the char to allow them to enter next value
	*/
	const getRenderValue = () => {
		if (userValue != null && stateValue !== "-" && (!decimalSeparator || stateValue !== decimalSeparator)) return formatValue({
			...formatValueOptions,
			decimalScale: dirty ? void 0 : decimalScale,
			value: String(userValue)
		});
		return stateValue;
	};
	return {
		getRenderValue,
		handleOnChange,
		handleOnBlur,
		handleOnFocus,
		handleOnKeyDown,
		handleOnKeyUp
	};
}
//#endregion
export { useNumberInput };
