import React, {useState, useCallback, useMemo, useEffect} from 'react';
import {FlatList, ListRenderItem, View} from 'react-native';
import {useTranslation} from 'react-i18next';
import {useMutation} from 'react-query';
import {useSafeAreaInsets} from 'react-native-safe-area-context';
import {IconInfoCircle} from '@tabler/icons-react-native';
import {
  Button,
  ListItem,
  InputSearch,
  Divider,
  ListEmpty,
  Avatar,
  ListSkeleton,
} from '@components';
import {useInfiniteQuery} from '@hooks/queries/useInfiniteQuery';
import {useDebounce} from '@hooks/useDebounce';
import {useGoBack} from '@hooks/useGoBack';
import {Navigation} from '@interfaces/navigation';
import {PrivacyPolicy, ReducedUser} from '@modules/group/interfaces';
import {
  addGroupMembers,
  getAssignableMembers,
  inviteGroupMembers,
} from '@modules/group/services';
import {useGetGroupById} from '@modules/group/hooks/useGetGroupById';
import {getGroupRoles} from '@modules/group/utils';
import ListHeader from '@modules/group/screens/AddGroupMembers/components/ListHeader';
import {GROUP_QUERY_KEYS} from '@modules/group/constants';
import {useUserId} from '@redux/selectors';
import {showSnackbar} from '@redux/dispatchers';
import {DEFAULT_LIMIT} from '@services/constants';
import {getCompleteName, logAmplitudeEvent} from '@shared/utils';
import {AMPLITUDE_EVENTS, Screens} from '@shared/constants';
import {useTheme} from '@shared/theme';

import {styles} from './styles';

const keyExtractor = (item: ReducedUser) => item.id.toString();

const AddGroupMembers = ({
  navigation,
  route: {
    params: {groupId},
  },
}: Navigation<Screens.ADD_GROUP_MEMBERS>) => {
  const {t} = useTranslation();
  const userId = useUserId();
  const {data: group} = useGetGroupById(groupId);
  const {iAmAdmin} = getGroupRoles(group);
  const {theme} = useTheme();
  const {goBack} = useGoBack();
  const [searchValue, setSearchValue] = useState('');
  const [selectedUsers, setSelectedUsers] = useState<ReducedUser[]>([]);
  const {bottom} = useSafeAreaInsets();
  const debouncedSearchValue = useDebounce(searchValue, 500);

  useEffect(() => {
    group?.title &&
      navigation.setOptions({
        title: t('group.add_members.invite_people_to_group', {
          groupName: group.title,
        }),
      });
  }, [navigation, group, t]);

  const {mutate: addGroupMemberMutate, isLoading: isAddingMembers} =
    useMutation(addGroupMembers, {
      onSuccess: (_, variables) => {
        goBack();
        logAmplitudeEvent(AMPLITUDE_EVENTS.GROUPS_USER_ADDED, {
          groupId,
          userId,
          action: 'ADD',
          addedUserIds: variables.userIds,
        });
        showSnackbar({
          title: t('group.add_persons'),
          variant: 'success',
        });
      },
    });
  const {mutate: inviteGroupMembersMutate, isLoading: isInvitingMembers} =
    useMutation(inviteGroupMembers, {
      onSuccess: (_, variables) => {
        goBack();
        logAmplitudeEvent(AMPLITUDE_EVENTS.GROUPS_USER_ADDED, {
          groupId,
          userId,
          action: 'INVITE',
          addedUserIds: variables.userIds,
        });
        showSnackbar({
          title: t('group.invited_persons'),
          variant: 'success',
        });
      },
    });

  const toggleCheckedUser = useCallback(
    (user: ReducedUser) => () =>
      setSelectedUsers(prevState =>
        prevState.some(u => u.id === user.id)
          ? prevState.filter(u => u.id !== user.id)
          : [...prevState, user],
      ),
    [],
  );

  const queryFn = ({page}: {page: number}) =>
    getAssignableMembers({
      page,
      q: debouncedSearchValue || undefined,
      groupId,
      limit: DEFAULT_LIMIT,
    });

  const {data, isLoading, isFetching, hasNextPage, getNextPage} =
    useInfiniteQuery(
      GROUP_QUERY_KEYS.groupAssignableMembers(groupId, debouncedSearchValue),
      queryFn,
    );

  const onEndReached = () => {
    if (hasNextPage) {
      getNextPage();
    }
  };

  const selectedUserIds = useMemo(
    () => selectedUsers.map(u => u.id),
    [selectedUsers],
  );

  const onAddMembers = () =>
    addGroupMemberMutate({groupId, userIds: selectedUserIds});

  const onInviteMembers = () =>
    inviteGroupMembersMutate({groupId, userIds: selectedUserIds});

  const renderItem: ListRenderItem<ReducedUser> = useCallback(
    ({item}) => (
      <ListItem
        style={styles.listItemContainer}
        onItemPress={toggleCheckedUser(item)}
        avatar={{
          name: getCompleteName(item),
          url: item.profilePicture,
        }}
        title={getCompleteName(item)}
        selectEnabled
        isSelected={selectedUsers.some(user => user.id === item.id)}
      />
    ),
    [selectedUsers, toggleCheckedUser],
  );

  return (
    <View
      style={[
        styles.container,
        {
          backgroundColor: theme.background.elements.default,
          paddingBottom: bottom,
        },
      ]}>
      <InputSearch
        variant="secondary"
        value={searchValue}
        onChangeText={setSearchValue}
        placeholder={t('general.search')}
      />
      <ListHeader
        isSearching={!!searchValue}
        selectedUsers={selectedUsers}
        group={group}
        toggleCheckedUser={toggleCheckedUser}
      />
      <FlatList
        data={data}
        style={styles.usersListContainer}
        renderItem={renderItem}
        keyExtractor={keyExtractor}
        showsVerticalScrollIndicator={false}
        onEndReached={onEndReached}
        ListFooterComponent={
          isFetching ? (
            <ListSkeleton itemLength={4} presentation="flat" />
          ) : null
        }
        ListEmptyComponent={
          !isFetching ? (
            <ListEmpty
              IconComponent={<Avatar Icon={IconInfoCircle} variant="primary" />}
              title={t('general.empty_search_result')}
            />
          ) : null
        }
      />
      <Divider />
      {!searchValue && (
        <View style={styles.buttonsContainer}>
          <Button
            disabled={
              isLoading ||
              isAddingMembers ||
              isInvitingMembers ||
              !selectedUsers.length
            }
            text={t('group.add_members.accept')}
            onPress={
              iAmAdmin || group?.privacyPolicy === PrivacyPolicy.Open
                ? onAddMembers
                : onInviteMembers
            }
          />
        </View>
      )}
    </View>
  );
};

export default AddGroupMembers;
