import {
    useImperativeHandle,
    forwardRef,
    useState,
    useRef
} from "react";
import {
    TextInput as NativeTextInput,
    TouchableOpacity,
    Keyboard,
    Platform,
    View
} from "react-native";
import type ITextInputProps from "./type";
import {
    type NumericInputInstance,
    type INumericInputRef,
    type NumericInputType
} from "./type";
import stylesheet, {
    getNumericInputType,
    useStyles
} from "./stylesheet";
import {
    NCoreUIKitLocalize,
    NCoreUIKitTheme
} from "../../core/hooks";
import {
    type RefForwardingComponent
} from "../../types";
import type ITextProps from "../text/type";
import {
    BadgeQuestionMark as BadgeQuestionMarkIcon,
    BadgeAlert as BadgeAlertIcon,
    BadgeCheck as BadgeCheckIcon,
    BadgeInfo as BadgeInfoIcon,
    EyeClosed as EyeClosedIcon,
    CircleX as CircleXIcon,
    BadgeX as BadgeXIcon,
    type LucideIcon,
    Eye as EyeIcon
} from "lucide-react-native";
import Text from "../text";

const NumericInputTypeIcon: Record<Exclude<NumericInputType, "default">, LucideIcon> = {
    "question": BadgeQuestionMarkIcon,
    "success": BadgeCheckIcon,
    "warning": BadgeAlertIcon,
    "info": BadgeInfoIcon,
    "danger": BadgeXIcon
};

const NumericInput: RefForwardingComponent<INumericInputRef, ITextInputProps> = ({
    isAutoKeyboardDismissOnBlur = true,
    rightIcon: RightIconComponentProp,
    hintTextIcon: HintTextIconProp,
    spreadBehaviour = "baseline",
    isShowHideTextButton = true,
    isWorkWithDebouncer = false,
    isShowHintTextIcon = false,
    icon: IconComponentProp,
    hintTextContainerStyle,
    isCleanEnabled = false,
    contentContainerStyle,
    subTitle = "Optional",
    onFocus: onFocusProp,
    isRequired = false,
    isDisabled = false,
    onBlur: onBlurProp,
    hideTextIconStyle,
    variant = "text",
    type = "default",
    rightIconOnPress,
    customLocalize,
    rightIconStyle,
    isShowSubTitle,
    cleanIconStyle,
    onChangeText,
    initialValue,
    customTheme,
    placeholder,
    iconOnPress,
    isOptional,
    validation,
    inputStyle,
    iconStyle,
    hintText,
    style,
    title,
    ...props
}, ref) => {
    const {
        inlineSpaces,
        typography,
        radiuses,
        borders,
        spaces,
        colors
    } = NCoreUIKitTheme.useContext(customTheme);

    const {
        localize
    } = NCoreUIKitLocalize.useContext(customLocalize);

    const currentType = getNumericInputType({
        type
    });

    const inputDebouncer = useRef<ReturnType<typeof setTimeout>>(null);
    const inputRef = useRef<NumericInputInstance | null>(null);

    const styleType = type === "default" ? "neutral" : type === "question" ? "neutral" : type === "danger" ? "error" : type;

    const [
        value,
        setValue
    ] = useState(initialValue ? initialValue : "");

    const [
        hideValue,
        setHideValue
    ] = useState(true);

    const [
        isFocused,
        setIsFocused
    ] = useState(false);

    const [
        selection,
        setSelection
    ] = useState({
        start: 0,
        end: 0
    });

    const {
        hideTextIconContainer: hideTextIconContainerDynamicStyle,
        titleContainer: titleContainerDynamicStyle,
        hintTextIcon: hintTextIconDynamicStyle,
        cleanButton: cleanButtonDynamicStyle,
        rightIcon: rightIconDynamicStyle,
        container: containerDynamicStyle,
        hintText: hintTextDynamicStyle,
        required: requiredDynamicStyle,
        subTitle: subTitleDynamicStyle,
        content: contentDynamicStyle,
        overlay: overlayDynamicStyle,
        title: titleDynamicStyle,
        input: inputDynamicStyle,
        icon: iconDynamicStyle
    } = useStyles({
        icon: IconComponentProp ? true : false,
        spreadBehaviour,
        inlineSpaces,
        currentType,
        isDisabled,
        typography,
        isFocused,
        radiuses,
        borders,
        spaces,
        colors,
        title,
        type
    });

    useImperativeHandle(
        ref,
        () => ({
            updateValue,
            cleanText,
            focus,
            blur
        }),
        []
    );

    const titleProps: ITextProps = {
        color: currentType.titleColor,
        variant: "bodyLargeSize"
    };

    const iconProps: NCoreUIKit.IconCallbackProps = {
        size: Number(typography.labelLargeSize.fontSize) + 6,
        color: currentType.iconColor
    };

    if(isDisabled) {
        iconProps.color = "disabled";
    }

    const blur = () => {
        inputRef.current?.blur();
    };

    const focus = () => {
        inputRef.current?.focus();
    };

    const cleanText = () => {
        setValue("");

        inputRef.current?.clear();

        if(onChangeText) {
            onChangeText("");
        }
    };

    const updateValue = (text: string) => {
        setValue(text);

        inputRef.current?.setNativeProps({
            text: text
        });
    };

    const onFocus = () => {
        setIsFocused(true);

        if(onFocusProp) onFocusProp();
    };

    const onBlur = () => {
        setIsFocused(false);

        inputRef.current?.blur();

        if(isAutoKeyboardDismissOnBlur) {
            Keyboard.dismiss();
        }

        if(onBlurProp) onBlurProp();
    };

    const toggleValueVisibility = () => {
        setHideValue(prevState => !prevState);
    };

    const handleTextChange = (text: string) => {
        if (
            props.maxLength &&
            selection.start >= value.length &&
            text.length > props.maxLength &&
            text.length > value.length
        ) {
            inputRef.current?.setNativeProps({
                value: value
            });

            return;
        }

        const cleanedText = text.replace(/\n/g, "").replace(/[^0-9]/g, "");
        const newValue = props.maxLength ? cleanedText.slice(0, props.maxLength) : cleanedText;

        if(text === "") {
            setValue("");

            if(onChangeText) onChangeText("");

            return;
        }

        const isValid = validation ? validation(newValue, (text) => {
            if (onChangeText) onChangeText(newValue);
            setValue(text);
        }) : true;

        if (!isValid) {
            setSelection({
                start: selection.start,
                end: selection.end
            });

            return;
        }

        const isDeleting = text.length < value.length;
        let nextPosition = selection.start;

        if (isDeleting) {
            nextPosition = Math.max(0, selection.start - 1);
        } else {
            nextPosition = Math.min(newValue.length, selection.start + 1);
        }

        setValue(newValue);
        if (onChangeText) onChangeText(newValue);

        setSelection({
            start: nextPosition,
            end: nextPosition
        });
    };

    const renderCleanButton = () => {
        if(isDisabled) {
            return null;
        }

        if(variant !== "text") {
            return null;
        }

        if(!isCleanEnabled || !value.length) {
            return null;
        }

        return <TouchableOpacity
            style={[
                cleanIconStyle,
                stylesheet.cleanButton,
                cleanButtonDynamicStyle
            ]}
            onPress={() => {
                if(inputRef.current) inputRef.current.clear();

                if(onChangeText) {
                    onChangeText("");
                }

                setValue("");
            }}
        >
            <CircleXIcon
                color={colors.content.icon[currentType.iconColor]}
                size={20}
            />
        </TouchableOpacity>;
    };

    const renderIcon = () => {
        if (!IconComponentProp) {
            return null;
        }

        return <TouchableOpacity
            onPress={iconOnPress}
            style={[
                iconStyle,
                stylesheet.icon,
                iconDynamicStyle
            ]}
        >
            <IconComponentProp
                color={iconProps.color}
                size={iconProps.size}
            />
        </TouchableOpacity>;
    };

    const renderRightIcon = () => {
        if (!RightIconComponentProp) {
            return null;
        }

        if(isShowHideTextButton && variant === "hidden") {
            return null;
        }

        if(isCleanEnabled && value.length > 0 && variant === "text") {
            return null;
        }

        return <TouchableOpacity
            onPress={rightIconOnPress}
            style={[
                rightIconStyle,
                stylesheet.rightIcon,
                rightIconDynamicStyle
            ]}
        >
            <RightIconComponentProp
                color={iconProps.color}
                size={iconProps.size}
            />
        </TouchableOpacity>;
    };

    const renderHideTextIcon = () => {
        if(!isShowHideTextButton) {
            return null;
        }

        if (variant !== "hidden") {
            return null;
        }

        return <TouchableOpacity
            onPress={toggleValueVisibility}
            style={[
                hideTextIconStyle,
                stylesheet.hideTextIconContainer,
                hideTextIconContainerDynamicStyle
            ]}
        >
            {
                hideValue ?
                    <EyeIcon
                        color={colors.content.icon[iconProps.color]}
                        size={20}
                    />
                :
                    <EyeClosedIcon
                        color={colors.content.icon[iconProps.color]}
                        size={20}
                    />
            }
        </TouchableOpacity>;
    };

    const renderHintIcon = () => {
        if(!isShowHintTextIcon) {
            return null;
        }

        if(HintTextIconProp) {
            return <HintTextIconProp
                color={isDisabled ? "disabled" : currentType.hintTextIconColor}
                size={20}
                style={[
                    stylesheet.hintTextIcon,
                    hintTextIconDynamicStyle
                ]}
            />;
        }

        const CurrentHintIcon = NumericInputTypeIcon[type === "default" ? "question" : type];

        let hintIconColor = colors.content.icon[currentType.hintTextIconColor];

        if(isDisabled) {
            hintIconColor = colors.system.state.content.disabled[styleType];
        }

        return <CurrentHintIcon
            color={hintIconColor}
            size={20}
            style={[
                stylesheet.hintTextIcon,
                hintTextIconDynamicStyle
            ]}
        />;
    };

    const renderHintText = () => {
        if (!hintText) {
            return null;
        }

        return <View
            style={[
                hintTextContainerStyle,
                stylesheet.hintText,
                hintTextDynamicStyle
            ]}
        >
            {renderHintIcon()}
            <Text
                customColor={isDisabled ? colors.system.state.content.disabled[styleType] : undefined}
                color={currentType.hintTextColor}
                variant="labelSmallSize"
            >
                {hintText}
            </Text>
        </View>;
    };

    const renderRequired = () => {
        if(!isRequired) {
            return null;
        }

        return <Text
            color="danger"
            style={[
                stylesheet.required,
                requiredDynamicStyle
            ]}
        >
            *
        </Text>;
    };

    const renderSubtitle = () => {
        if(!isShowSubTitle && !isOptional) {
            return null;
        }

        return <Text
            variant="labelLargeSize"
            color={titleProps.color}
            style={[
                stylesheet.subTitle,
                subTitleDynamicStyle
            ]}
        >
            ( {isOptional ? localize("is-optional") : subTitle} )
        </Text>;
    };

    const renderTitle = () => {
        if (!title) {
            return null;
        }

        return <View
            style={[
                stylesheet.titleContainer,
                titleContainerDynamicStyle
            ]}
        >
            {renderRequired()}
            <Text
                {...titleProps}
                variant={titleProps.variant}
                color={titleProps.color}
                style={[
                    stylesheet.title,
                    titleDynamicStyle
                ]}
            >
                {title}
            </Text>
            {renderSubtitle()}
        </View>;
    };

    const renderInput = () => {
        return <NativeTextInput
            {...props}
            placeholderTextColor={colors.content.text[currentType.placeholderColor]}
            onSelectionChange={(e) => setSelection(e.nativeEvent.selection)}
            secureTextEntry={variant === "hidden" && hideValue}
            underlineColorAndroid="rgba(255,255,255,0)"
            onChangeText={(text) => {
                if(isWorkWithDebouncer) {
                    if(inputDebouncer.current) {
                        clearTimeout(inputDebouncer.current);
                        inputDebouncer.current = null;
                    }

                    inputDebouncer.current = setTimeout(() => {{
                        handleTextChange(text);
                    }}, 550);
                } else {
                    handleTextChange(text);
                }
            }}
            placeholder={placeholder}
            allowFontScaling={false}
            editable={!isDisabled}
            maxLength={undefined}
            selection={selection}
            multiline={false}
            onFocus={onFocus}
            onBlur={onBlur}
            value={value}
            ref={inputRef}
            style={[
                inputStyle,
                stylesheet.input,
                inputDynamicStyle
            ]}
        />;
    };

    const renderOverlay = () => {
        return <View
            style={[
                stylesheet.overlay,
                overlayDynamicStyle
            ]}
        />;
    };

    return <TouchableOpacity
        disabled={isDisabled}
        style={[
            style,
            stylesheet.container,
            containerDynamicStyle
        ]}
        onPress={() => {
            if(!isDisabled) inputRef.current?.focus();
        }}
        {...Platform.select({
            web: {
                dataSet: {
                    disablePressableDownEffect: "true"
                }
            },
            default: {}
        })}
    >
        {renderTitle()}

        <View
            style={[
                contentContainerStyle,
                stylesheet.content,
                contentDynamicStyle
            ]}
        >
            {renderIcon()}

            {renderInput()}

            {renderCleanButton()}
            {renderHideTextIcon()}
            {renderRightIcon()}

            {renderOverlay()}
        </View>

        {renderHintText()}
    </TouchableOpacity>;
};
export default forwardRef(NumericInput);
