import React, {FC, MutableRefObject, useMemo, useRef, useState} from 'react';
import {
  NativeSyntheticEvent,
  StyleSheet,
  Text,
  TextInput,
  TextInputSelectionChangeEventData,
  TouchableOpacity,
  View,
} from 'react-native';
import {useDispatch, useSelector} from 'react-redux';
import {TAGG_LIGHT_BLUE} from '../../constants';
import {
  MentionInputProps,
  MentionPartType,
  Suggestion,
} from 'react-native-controlled-mentions/dist/types';
import {
  defaultMentionTextStyle,
  generateValueFromPartsAndChangedText,
  generateValueWithAddedSuggestion,
  getMentionPartSuggestionKeywords,
  isMentionPartType,
  parseValue,
} from 'react-native-controlled-mentions/dist/utils';
import {Avatar} from '../common';
import {normalize} from 'react-native-elements';

import UpArrowIcon from '../../assets/icons/up_arrow.svg';
import {SCREEN_WIDTH, SCREEN_HEIGHT} from '../../utils';

const MentionInputControlled: FC<MentionInputProps> = ({
  value,
  onChange,

  partTypes = [],

  inputRef: propInputRef,

  containerStyle,

  onSelectionChange,

  addComment,

  ...textInputProps
}) => {
  const textInput = useRef<TextInput | null>(null);

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

  const [keyboardText, setKeyboardText] = useState<string>('');

  const {avatar} = useSelector((state: RootState) => state.user);

  const validRegex = () => {
    if (partTypes.length === 0) {
      return /.*@[^ ]*$/;
    } else {
      return new RegExp(`.*@${keywordByTrigger[partTypes[0].trigger]}.*$`);
    }
  };

  const {plainText, parts} = useMemo(
    () => parseValue(value, partTypes),
    [value, partTypes],
  );

  const handleSelectionChange = (
    event: NativeSyntheticEvent<TextInputSelectionChangeEventData>,
  ) => {
    setSelection(event.nativeEvent.selection);

    onSelectionChange && onSelectionChange(event);
  };

  /**
   * Callback that trigger on TextInput text change
   *
   * @param changedText
   */
  const onChangeInput = (changedText: string) => {
    setKeyboardText(changedText);
    onChange(
      generateValueFromPartsAndChangedText(parts, plainText, changedText),
    );
  };

  /**
   * We memoize the keyword to know should we show mention suggestions or not
   */
  const keywordByTrigger = useMemo(() => {
    return getMentionPartSuggestionKeywords(
      parts,
      plainText,
      selection,
      partTypes,
    );
  }, [parts, plainText, selection, partTypes]);

  /**
   * Callback on mention suggestion press. We should:
   * - Get updated value
   * - Trigger onChange callback with new value
   */
  const onSuggestionPress =
    (mentionType: MentionPartType) => (suggestion: Suggestion) => {
      const newValue = generateValueWithAddedSuggestion(
        parts,
        mentionType,
        plainText,
        selection,
        suggestion,
      );

      if (!newValue) {
        return;
      }

      onChange(newValue);

      /**
       * Move cursor to the end of just added mention starting from trigger string and including:
       * - Length of trigger string
       * - Length of mention name
       * - Length of space after mention (1)
       *
       * Not working now due to the RN bug
       */
      // const newCursorPosition = currentPart.position.start + triggerPartIndex + trigger.length +
      // suggestion.name.length + 1;

      // textInput.current?.setNativeProps({selection: {start: newCursorPosition, end: newCursorPosition}});
    };

  const handleTextInputRef = (ref: TextInput) => {
    textInput.current = ref as TextInput;

    if (propInputRef) {
      if (typeof propInputRef === 'function') {
        propInputRef(ref);
      } else {
        (propInputRef as MutableRefObject<TextInput>).current =
          ref as TextInput;
      }
    }
  };

  const renderMentionSuggestions = (mentionType: MentionPartType) => (
    <React.Fragment key={mentionType.trigger}>
      {mentionType.renderSuggestions &&
        mentionType.renderSuggestions({
          keyword: keywordByTrigger[mentionType.trigger],
          onSuggestionPress: onSuggestionPress(mentionType),
        })}
    </React.Fragment>
  );

  const validateInput = (testString: string) => {
    return validRegex().test(testString);
  };

  return (
    <View style={containerStyle}>
      {validateInput(keyboardText)
        ? (
            partTypes.filter(
              (one) =>
                isMentionPartType(one) &&
                one.renderSuggestions != null &&
                !one.isBottomMentionSuggestionsRender,
            ) as MentionPartType[]
          ).map(renderMentionSuggestions)
        : null}

      <View style={styles.containerStyle}>
        <Avatar style={styles.avatar} uri={avatar} />
        <TextInput
          multiline
          {...textInputProps}
          ref={handleTextInputRef}
          onChangeText={onChangeInput}
          onSelectionChange={handleSelectionChange}
          style={styles.text}>
          <Text>
            {parts.map(({text, partType, data}, index) =>
              partType ? (
                <Text
                  key={`${index}-${data?.trigger ?? 'pattern'}`}
                  style={partType.textStyle ?? defaultMentionTextStyle}>
                  {text}
                </Text>
              ) : (
                <Text key={index}>{text}</Text>
              ),
            )}
          </Text>
        </TextInput>
        <View style={styles.submitButton}>
          <TouchableOpacity style={styles.submitButton} onPress={addComment}>
            <UpArrowIcon width={35} height={35} color={'white'} />
          </TouchableOpacity>
        </View>
      </View>

      {validateInput(keyboardText)
        ? (
            partTypes.filter(
              (one) =>
                isMentionPartType(one) &&
                one.renderSuggestions != null &&
                one.isBottomMentionSuggestionsRender,
            ) as MentionPartType[]
          ).map(renderMentionSuggestions)
        : null}
    </View>
  );
};

const styles = StyleSheet.create({
  avatar: {
    height: 35,
    width: 35,
    borderRadius: 30,
    marginRight: 10,
    marginLeft: '3%',
    marginVertical: '2%',
    // alignSelf: 'flex-end',
  },
  containerStyle: {
    flexDirection: 'row',
    alignSelf: 'center',
    alignItems: 'center',
    justifyContent: 'center',
    // borderWidth: 1,
    height: normalize(40),
  },
  submitButton: {
    height: 35,
    width: 35,
    backgroundColor: TAGG_LIGHT_BLUE,
    borderRadius: 999,
    justifyContent: 'center',
    alignItems: 'center',
    marginRight: '3%',
    marginVertical: '2%',
    alignSelf: 'flex-end',
  },
  text: {flex: 1},
  overlay: {
    width: SCREEN_WIDTH,
    height: SCREEN_HEIGHT,
    backgroundColor: 'blue',
    position: 'absolute',
    left: 0,
    bottom: 0,
    zIndex: -1,
  },
});

export {MentionInputControlled};
