import React, {
  createElement,
  useState,
  useMemo,
  useRef,
  useCallback,
} from 'react';
import {
  LayoutAnimation,
  ScrollView,
  StyleProp,
  ViewStyle,
  TextInput,
  Pressable,
  View,
} from 'react-native';
import {useTranslation} from 'react-i18next';
import {spyIfWritingTaggedUser, tagNewUser} from 'tag-users';
import CustomizedTextInput, {
  TextInputComponentProps,
} from '@components/CustomizedTextInput';
import {AvatarWithName} from '@components/Image';
import {ListEmpty, Spinner} from '@components/_HuGo';
import {useDebounce} from '@hooks/useDebounce';
import {useGetUsersPublic} from '@hooks/useGetUsersPublic';
import {TaggableUser} from '@interfaces/taggedUsers';
import {User} from '@interfaces/user';
import {useGetMembers} from '@modules/group/screens/GroupDetail/hooks/useGetMembers';
import {GroupUser} from '@modules/group/interfaces';
import {getTaggableUserId, isGroupTaggableUser} from '@shared/utils';

import {styles} from './styles';
import {TIME_DELAY} from './constants';

export interface UseTagUsersTextInputProps extends TextInputComponentProps {
  messageBodyWithoutLastTag?: string;
  setMessageBodyWithoutLastTag?: (x: string) => void;
  changeTaggedUserStartPosition?: (
    userId: number,
    newStartPosition: number,
  ) => void;
  addTaggedUser?: (user: User) => void;
  deleteTaggedUser?: (userId: number) => void;
  groupId?: number;
  tagListContainer?: StyleProp<ViewStyle>;
}

function useTagUsersTextInput({
  value,
  messageBodyWithoutLastTag,
  setMessageBodyWithoutLastTag,
  onChangeText,
  taggedUsers,
  changeTaggedUserStartPosition,
  addTaggedUser,
  deleteTaggedUser,
  groupId,
  tagListContainer,
  onFocus,
  onBlur,
  ...inputProps
}: UseTagUsersTextInputProps) {
  const {t} = useTranslation();
  const [userSearch, setUserSearch] = useState('');
  const [tagUser, setTagUser] = useState(false);
  const [tagUserStartPosition, setTagUserStartPosition] = useState(0);
  const [focused, setFocused] = useState(false);
  const textInputRef = useRef<Nullable<TextInput>>(null);
  const debouncedValue = useDebounce(userSearch, TIME_DELAY);
  const isGroupSearch = !!groupId;
  const {data: usersPublic = [], isLoading: isLoadingUsers} = useGetUsersPublic(
    {
      search: debouncedValue,
      enabled: !isGroupSearch,
      status: 'ACTIVE,UNCLAIMED',
    },
  );
  const {data: groupMembers, isLoading: isLoadingMembers} = useGetMembers({
    groupId: groupId!,
    search: debouncedValue,
    enabled: isGroupSearch,
  });
  const usersCanBeTagged = useMemo(() => {
    const users = groupId ? groupMembers : usersPublic;
    return taggedUsers?.length
      ? // eslint-disable-next-line @typescript-eslint/ban-ts-comment
        // @ts-ignore Avoid strange TS error with mismatched types
        users.filter(
          (user: TaggableUser) =>
            !taggedUsers.some(u => u.type.user.id === getTaggableUserId(user)),
        )
      : users;
  }, [groupId, groupMembers, taggedUsers, usersPublic]);

  const TextInputComponent = useMemo(
    () =>
      createElement(CustomizedTextInput, {
        ...inputProps,
        ref: textInputRef,
        value,
        showMaxLength: false,
        autoComplete: 'off',
        autoCorrect: false,
        taggedUsers,
        onChangeText: (text: string) => {
          spyIfWritingTaggedUser({
            text,
            tagUser,
            setTagUser,
            value,
            userSearch,
            setUserSearch,
            taggedUsers,
            onChangeText,
            messageBodyWithoutLastTag,
            setMessageBodyWithoutLastTag,
            setTagUserStartPosition,
            changeTaggedUserStartPosition,
            deleteTaggedUser,
          });
        },
        onFocus: e => {
          LayoutAnimation.configureNext(LayoutAnimation.Presets.easeInEaseOut);
          setFocused(true);
          onFocus?.(e);
        },
        onBlur: e => {
          LayoutAnimation.configureNext(LayoutAnimation.Presets.easeInEaseOut);
          setFocused(false);
          onBlur?.(e);
        },
      }),
    [
      changeTaggedUserStartPosition,
      deleteTaggedUser,
      inputProps,
      messageBodyWithoutLastTag,
      onBlur,
      onChangeText,
      onFocus,
      setMessageBodyWithoutLastTag,
      tagUser,
      taggedUsers,
      userSearch,
      value,
    ],
  );

  const onPressUserToTag = useCallback(
    (user: User | GroupUser['user']) => () => {
      tagNewUser({
        user,
        setTagUser,
        setUserSearch,
        taggedUsers,
        onChangeText,
        messageBodyWithoutLastTag,
        setMessageBodyWithoutLastTag,
        tagUserStartPosition,
        addTaggedUser,
        changeTaggedUserStartPosition,
      });
    },
    [
      addTaggedUser,
      changeTaggedUserStartPosition,
      messageBodyWithoutLastTag,
      onChangeText,
      setMessageBodyWithoutLastTag,
      tagUserStartPosition,
      taggedUsers,
    ],
  );

  const renderUserToTag = useCallback(
    (item: TaggableUser) => {
      const typedUser = isGroupTaggableUser(item) ? item.user : item;
      const onPress = onPressUserToTag(typedUser);
      return (
        <Pressable
          key={`${typedUser.id}`}
          style={styles.profileContainer}
          onPress={onPress}>
          <AvatarWithName
            size="md"
            adjustsFontSizeToFit={false}
            url={typedUser.profilePicture}
            name={typedUser}
          />
        </Pressable>
      );
    },
    [onPressUserToTag],
  );

  // TODO: SQXS-1274 Add FlatList + pagination to UserToTag list
  const UsersList = useMemo(
    () =>
      focused && tagUser ? (
        <ScrollView
          bounces={false}
          style={[styles.usersContainer, tagListContainer]}
          nestedScrollEnabled
          persistentScrollbar
          keyboardShouldPersistTaps="always">
          {isLoadingUsers || isLoadingMembers ? (
            <View style={styles.loadingContainer}>
              <Spinner />
            </View>
          ) : !usersCanBeTagged.length ? (
            <ListEmpty
              title={t('general.no_users_result')}
              style={styles.emptyList}
            />
          ) : (
            usersCanBeTagged.map(renderUserToTag)
          )}
        </ScrollView>
      ) : null,
    [
      focused,
      isLoadingMembers,
      isLoadingUsers,
      renderUserToTag,
      t,
      tagListContainer,
      tagUser,
      usersCanBeTagged,
    ],
  );

  return [TextInputComponent, UsersList, textInputRef];
}

export default useTagUsersTextInput;
