/* eslint-disable react-hooks/exhaustive-deps */
import React, {
  FC,
  forwardRef,
  ForwardRefRenderFunction,
  useContext,
  useEffect,
  useImperativeHandle,
  useRef,
  useState,
} from 'react';
import {
  NativeSyntheticEvent,
  TextInput,
  TextInputFocusEventData,
  TouchableOpacity,
  View,
} from 'react-native';
import { useComponentId } from '../Application';
import {
  ApplicationContext,
  ComponentContext,
  MiniAppContext,
} from '../Context';
import { Icon } from '../Icon';
import { Text, useScaleSize } from '../Text';
import { InputRef, InputSearchProps } from './index';
import styles from './styles';
import { Styles } from '../Consts';
import SystemTextInput from './SystemTextInput';

const TextTyping: FC<any> = ({
  data = [],
  timeDelayEnd = 2000,
  timeDelayNextChar = 20,
}) => {
  const textRef = useRef<TextInput>(null);

  const currentIndex = useRef<number>(0);
  const currentCharIndex = useRef<number>(0);
  const currentText = useRef('');

  useEffect(() => {
    setTimeout(() => {
      playAnimation();
    }, 1000);
  }, []);

  const playAnimation = () => {
    const handleResetList = () => {
      currentIndex.current = 0;
      handleAnimation();
    };

    const handleAnimation = () => {
      const listChar = data?.[currentIndex.current]?.split('') || [];
      listChar.length !== 0 && showChar(listChar?.[currentCharIndex.current]);
    };

    currentIndex.current >= data?.length
      ? handleResetList()
      : handleAnimation();
  };

  const showChar = (char?: string) => {
    const handleResetString = () => {
      setTimeout(() => {
        reset();
      }, timeDelayEnd);
    };

    const handleShowChar = () => {
      setTimeout(() => {
        textRef.current?.setNativeProps?.({
          text: currentText.current + char,
        });
        currentText.current += char;
        currentCharIndex.current++;
        playAnimation();
      }, timeDelayNextChar);
    };

    currentCharIndex.current >= (data?.[currentIndex.current]?.length || 0)
      ? handleResetString()
      : handleShowChar();
  };

  const reset = () => {
    const handleNextString = () => {
      currentIndex.current++;
      playAnimation();
    };

    const handleReset = () => {
      setTimeout(() => {
        textRef.current?.setNativeProps?.({
          text: currentText.current.slice(0, -1),
        });
        currentText.current = currentText.current.slice(0, -1);
        currentCharIndex.current--;
        reset();
      }, timeDelayNextChar);
    };

    currentCharIndex.current <= 0 ? handleNextString() : handleReset();
  };

  return (
    <TextInput
      style={styles.inputStyle}
      ref={textRef}
      editable={false}
      autoCorrect={false}
      pointerEvents={'none'}
      numberOfLines={1}
      allowFontScaling={false}
    />
  );
};

const InputSearch: ForwardRefRenderFunction<InputRef, InputSearchProps> = (
  {
    placeholder,
    onFocus,
    onBlur,
    value,
    trailing,
    trailingColor,
    onPressTrailing,
    onChangeText,
    buttonText = 'Hủy',
    showButtonText = true,
    style,
    defaultValue,
    onPressButtonText,
    params,
    backgroundColor,
    onPress,
    typingData,
    ...props
  },
  ref,
) => {
  const { theme } = useContext(ApplicationContext);
  const context = useContext<any>(MiniAppContext);
  const scaledFontSize = useScaleSize(14);

  const showBaseLineDebug = context?.features?.showBaseLineDebug ?? false;

  const [focused, setFocused] = useState(false);
  const [internalText, setInternalText] = useState(defaultValue || '');
  const currentValue = value !== undefined ? value : internalText;
  const haveValue = !!currentValue;
  const inputRef = useRef<TextInput | null>(null);

  const componentName = 'InputSearch';

  const { componentId } = useComponentId(
    `${componentName}/${placeholder}`,
    props.accessibilityLabel,
  );

  const _onFocus = (e: NativeSyntheticEvent<TextInputFocusEventData>) => {
    setFocused(true);
    onFocus?.(e);
  };

  const _onBlur = (e: NativeSyntheticEvent<TextInputFocusEventData>) => {
    setFocused(false);
    onBlur?.(e);
  };

  const onClearText = () => {
    inputRef?.current?.clear();
    inputRef.current?.setNativeProps({ text: '' });
    _onChangeText('');
  };

  const _onChangeText = (text: string) => {
    if (value === undefined) {
      setInternalText(text);
    }
    onChangeText?.(text);
  };

  const _setText = (text: string) => {
    inputRef?.current?.setNativeProps({ text });
    _onChangeText(text);
  };

  useImperativeHandle(ref, () => {
    return {
      clear: onClearText,
      focus: () => inputRef.current?.focus(),
      blur: () => inputRef.current?.blur(),
      setText: _setText,
    };
  });

  /**
   * Render the input view
   */
  const renderInputView = () => {
    if (typingData && typingData?.length > 0) {
      return (
        <TouchableOpacity
          style={[
            styles.searchInput,
            {
              justifyContent: 'center',
            },
          ]}
          onPress={onPress}
          activeOpacity={onPress ? 0.6 : 1}
        >
          <TextTyping data={typingData} />
        </TouchableOpacity>
      );
    }

    return (
      <SystemTextInput
        {...props}
        accessibilityLabel={componentId}
        textAlignVertical="center"
        allowFontScaling={false}
        ref={inputRef}
        style={[
          styles.searchInput,
          {
            fontSize: scaledFontSize,
            color: theme.colors.text.default,
          },
        ]}
        value={value}
        onChangeText={_onChangeText}
        defaultValue={defaultValue}
        onFocus={_onFocus}
        onBlur={_onBlur}
        placeholder={placeholder}
        selectionColor={theme.colors.primary}
        placeholderTextColor={theme.colors.text.hint}
      />
    );
  };

  /**
   * Render trailing icon or text
   */
  const renderTrailing = () => {
    return (
      <View style={Styles.row}>
        {haveValue && (
          <TouchableOpacity
            style={styles.iconWrapper}
            onPress={onClearText}
            accessibilityLabel={`${componentId}|close-icon-touch`}
          >
            <Icon
              source="24_navigation_close_circle_full"
              size={16}
              color={theme.colors.text.hint}
            />
          </TouchableOpacity>
        )}
        {!!trailing && (
          <TouchableOpacity
            style={Styles.row}
            onPress={onPressTrailing}
            accessibilityLabel={`${componentId}|trailing-touch`}
          >
            <View
              style={[
                styles.divider,
                {
                  backgroundColor: theme.colors.primary,
                },
              ]}
            />
            <Icon
              color={trailingColor}
              source={trailing as string}
              style={styles.iconSearchInput}
            />
          </TouchableOpacity>
        )}
      </View>
    );
  };

  let inputState = 'empty';
  if (focused) {
    inputState = 'focus';
  }
  if (value && value?.length > 0) {
    inputState = 'filled';
  }

  return (
    <ComponentContext.Provider
      value={{
        componentName,
        componentId,
        params,
        state: inputState,
      }}
    >
      <View
        style={[
          style,
          styles.searchInputContainer,
          showBaseLineDebug && styles.debugBaseLine,
        ]}
      >
        <View
          style={[
            styles.searchInputWrapper,
            {
              backgroundColor:
                backgroundColor ?? theme.colors.background.surface,
            },
          ]}
        >
          <Icon
            source={'navigation_search'}
            size={24}
            color={theme.colors.text.hint}
          />
          {renderInputView()}
          {renderTrailing()}
        </View>
        {showButtonText && (
          <TouchableOpacity
            onPress={onPressButtonText}
            accessibilityLabel={`${componentId}|button-text-touch`}
          >
            <Text
              typography={'action_default_bold'}
              style={styles.textButton}
              accessibilityLabel={`${componentId}|button-text`}
            >
              {buttonText}
            </Text>
          </TouchableOpacity>
        )}
      </View>
    </ComponentContext.Provider>
  );
};

export default forwardRef(InputSearch);
