import React, {
  forwardRef,
  useCallback,
  useLayoutEffect,
  useRef,
  useState,
} from 'react';
import {BlurEvent, FocusEvent, LayoutAnimation, View} from 'react-native';
import {spyIfWritingTaggedUser, tagNewUser} from 'tag-users';
import {TextInputType} from '@components/_core/TextInput';
import {InputTags, InputTagsProps} from '@components/_HuGo/Inputs';
import {TaggableUser} from '@interfaces/taggedUsers';
import {User} from '@interfaces/user';
import {isGroupTaggableUser} from '@shared/utils';

import {styles} from './styles';

export interface TagUsersMentionSuggestions {
  userSearch: string;
  tagUser: boolean;
  isComposerFocused: boolean;
  onPickTaggableUser: (user: TaggableUser) => void;
}

export interface TagUsersTextInputProps extends InputTagsProps {
  messageBodyWithoutLastTag?: string;
  setMessageBodyWithoutLastTag?: (x: string) => void;
  changeTaggedUserStartPosition?: (
    userId: number,
    newStartPosition: number,
  ) => void;
  addTaggedUser?: (user: User) => void;
  deleteTaggedUser?: (userId: number) => void;
  groupId?: number;
  onMentionSuggestionsChange?: (
    suggestions: TagUsersMentionSuggestions,
  ) => void;
}

export const TagUsersTextInput = forwardRef<
  TextInputType,
  TagUsersTextInputProps
>(function TagUsersTextInput(
  {
    value,
    messageBodyWithoutLastTag,
    setMessageBodyWithoutLastTag,
    onChangeText: onChangeTextProp,
    taggedUsers,
    changeTaggedUserStartPosition,
    addTaggedUser,
    deleteTaggedUser,
    groupId: _groupId,
    onFocus: onFocusProp,
    onBlur: onBlurProp,
    onMentionSuggestionsChange,
    ...inputProps
  },
  ref,
) {
  const [userSearch, setUserSearch] = useState('');
  const [tagUser, setTagUser] = useState(false);
  const [tagUserStartPosition, setTagUserStartPosition] = useState(0);
  const [isComposerFocused, setIsComposerFocused] = useState(false);
  const tagUserStartPositionRef = useRef(tagUserStartPosition);
  tagUserStartPositionRef.current = tagUserStartPosition;

  const onMentionSuggestionsChangeRef = useRef(onMentionSuggestionsChange);
  onMentionSuggestionsChangeRef.current = onMentionSuggestionsChange;

  const tagNewUserDepsRef = useRef({
    taggedUsers,
    onChangeTextProp,
    messageBodyWithoutLastTag,
    setMessageBodyWithoutLastTag,
    addTaggedUser,
    changeTaggedUserStartPosition,
  });
  tagNewUserDepsRef.current = {
    taggedUsers,
    onChangeTextProp,
    messageBodyWithoutLastTag,
    setMessageBodyWithoutLastTag,
    addTaggedUser,
    changeTaggedUserStartPosition,
  };

  const onPickTaggableUser = useCallback((match: TaggableUser) => {
    const user = isGroupTaggableUser(match) ? match.user : match;
    const d = tagNewUserDepsRef.current;
    tagNewUser({
      user,
      setTagUser,
      setUserSearch,
      taggedUsers: d.taggedUsers,
      onChangeText: d.onChangeTextProp,
      messageBodyWithoutLastTag: d.messageBodyWithoutLastTag,
      setMessageBodyWithoutLastTag: d.setMessageBodyWithoutLastTag,
      tagUserStartPosition: tagUserStartPositionRef.current,
      addTaggedUser: d.addTaggedUser,
      changeTaggedUserStartPosition: d.changeTaggedUserStartPosition,
    });
  }, []);

  const onChangeText = useCallback(
    (text: string) => {
      spyIfWritingTaggedUser({
        text,
        tagUser,
        setTagUser,
        value,
        userSearch,
        setUserSearch,
        taggedUsers,
        onChangeText: onChangeTextProp,
        messageBodyWithoutLastTag,
        setMessageBodyWithoutLastTag,
        setTagUserStartPosition,
        changeTaggedUserStartPosition,
        deleteTaggedUser,
      });
    },
    [
      tagUser,
      value,
      userSearch,
      setUserSearch,
      taggedUsers,
      messageBodyWithoutLastTag,
      setMessageBodyWithoutLastTag,
      setTagUserStartPosition,
      changeTaggedUserStartPosition,
      deleteTaggedUser,
      onChangeTextProp,
    ],
  );

  const onFocus = useCallback(
    (e: FocusEvent) => {
      LayoutAnimation.configureNext(LayoutAnimation.Presets.easeInEaseOut);
      setIsComposerFocused(true);
      onFocusProp?.(e);
    },
    [onFocusProp],
  );

  const onBlur = useCallback(
    (e: BlurEvent) => {
      LayoutAnimation.configureNext(LayoutAnimation.Presets.easeInEaseOut);
      setIsComposerFocused(false);
      onBlurProp?.(e);
    },
    [onBlurProp],
  );

  useLayoutEffect(() => {
    onMentionSuggestionsChangeRef.current?.({
      userSearch,
      tagUser,
      isComposerFocused,
      onPickTaggableUser,
    });
  }, [userSearch, tagUser, isComposerFocused, onPickTaggableUser]);

  return (
    <View style={styles.inputWrapper}>
      <InputTags
        {...inputProps}
        ref={ref}
        value={value}
        autoComplete="off"
        autoCorrect
        taggedUsers={taggedUsers}
        onChangeText={onChangeText}
        onFocus={onFocus}
        onBlur={onBlur}
        multiline
        returnKeyType="default"
        scrollEnabled
        withClearButton={false}
        style={styles.input}
      />
    </View>
  );
});
