import React, { useEffect } from 'react';
import { Keyboard, Text, TextInput, View } from 'react-native';
import Animated, { useAnimatedProps, useAnimatedRef, useDerivedValue } from 'react-native-reanimated';

import { styles } from '../../../styles';
import { isWeb } from '../../../utils';

import type { InputProps } from '../../../types';
import type { BlurEvent, StyleProp, TextInputEndEditingEvent, TextStyle } from 'react-native';
import type { SharedValue } from 'react-native-reanimated';

interface WidgetTextInputProps {
  textValue: SharedValue<string>;
  textKeyboard?: boolean;
  decimal?: boolean;
  title: string;
  label: string;
  inputStyle: StyleProp<TextStyle>;
  textStyle: StyleProp<TextStyle>;
  inputProps: InputProps;
  onEndEditing: (text: string) => void;
}

Animated.addWhitelistedNativeProps({ text: true });
const AnimatedTextInput = Animated.createAnimatedComponent(TextInput);

export default function WidgetTextInput(props: WidgetTextInputProps) {
  const {
    textValue,
    decimal = false,
    textKeyboard = false,
    title,
    label,
    inputStyle,
    textStyle,
    inputProps,
    onEndEditing,
  } = props;

  const inputRef = useAnimatedRef<TextInput>();

  const animatedProps = useAnimatedProps(() => ({ text: textValue.value, defaultValue: textValue.value }) as never, [textValue]);

  const submit = (e: TextInputEndEditingEvent | BlurEvent) => {
    // @ts-expect-error `text` doesn't exist on BlurEvent (It does)
    const text = e.nativeEvent.text;

    // number input mode
    if (decimal || !textKeyboard) {
      const number = parseFloat(text);
      if (typeof number !== 'number' || isNaN(number) || !isFinite(number)) {
        textValue.value = '';
        return;
      }
    }

    onEndEditing(text);
  };

  useEffect(() => {
    const hideSubscription = Keyboard.addListener('keyboardDidHide', () => {
      if (inputRef.current) {
        inputRef.current.blur();
      }
    });

    return () => {
      hideSubscription.remove();
    };
  }, []);

  // For web platform only
  useDerivedValue(() => {
    if (!isWeb || !inputRef.current) return;

    // @ts-expect-error value doesn't exist
    inputRef.current.value = textValue.value;
  }, [textValue]);

  return (
    <View style={styles.inputsContainer}>
      <AnimatedTextInput
        ref={inputRef}
        style={[styles.input, inputStyle]}
        maxLength={decimal ? 4 : textKeyboard ? 9 : 3} // length example: Alpha (1.55), RGB (255), Hue (360), Brightness (100), hex (#00000000)
        onEndEditing={submit}
        onBlur={isWeb ? submit : undefined}
        enterKeyHint='enter'
        returnKeyType='done'
        keyboardType={decimal ? 'decimal-pad' : textKeyboard ? 'default' : 'number-pad'}
        inputMode={decimal ? 'decimal' : textKeyboard ? 'text' : 'numeric'}
        autoComplete='off'
        autoCorrect={false}
        autoFocus={false}
        accessibilityLabel={label}
        {...inputProps}
        selectTextOnFocus={!textKeyboard}
        animatedProps={animatedProps}
      />

      <Text style={[styles.inputTitle, textStyle]} accessibilityLabel={label}>
        {title}
      </Text>
    </View>
  );
}
