import { memo, useCallback, useState } from "react";

import TextBox, { type TextBoxProps } from "./TextBox";

export interface NumberInputBoxProps
	extends Omit<
		TextBoxProps,
		"inputMode" | "onChange" | "value" | "min" | "max"
	> {
	value?: number | undefined;
	onChange?: (value: number | undefined) => void;

	min?: number;
	max?: number;
	integerOnly?: boolean;

	// TODO:
	// startAdornment?: string;
	// endAdornment?: string;
}

export default memo(function NumberInputBox(props: NumberInputBoxProps) {
	const [value, setValue] = useState("");

	const onChangeParent = props.onChange;
	const { integerOnly, min, max } = props;

	const onChange = useCallback(
		(v: string) => {
			setValue(v);

			const value = v.replaceAll(/\./g, "").replaceAll(",", ".");

			const numberValue = Number(value);
			if (
				(min !== undefined && numberValue < min) ||
				(max !== undefined && numberValue > max) ||
				Number.isNaN(numberValue) ||
				!Number.isFinite(numberValue)
			) {
				onChangeParent?.(undefined);
				return;
			}

			if (integerOnly && !Number.isSafeInteger(numberValue)) {
				onChangeParent?.(undefined);
				return;
			}

			onChangeParent?.(numberValue);
		},
		[integerOnly, min, max, onChangeParent],
	);

	return (
		<TextBox
			ref={(input) => {
				if (!input) {
					return;
				}

				const handler = (e: InputEvent) => {
					const content = e.data;
					if (!content || !e.inputType.startsWith("insert")) {
						return;
					}

					if (
						(integerOnly && !/^[-0-9]*$/.test(content)) ||
						!/^[-0-9,]*$/.test(content)
					) {
						e.preventDefault();
					}
				};

				input.addEventListener("beforeinput", handler);
				return () => input.removeEventListener("beforeinput", handler);
			}}
			{...props}
			min={undefined}
			max={undefined}
			onChange={onChange}
			value={value?.toString()}
			pattern={integerOnly ? "[-0-9]*" : "[-0-9,]*"}
			inputMode="numeric"
		/>
	);
});
