import React, {memo, useCallback, useEffect, useMemo, useRef} from 'react';
import {
  View,
  SectionList,
  SectionListRenderItem,
  FlatList,
  ScrollViewProps,
} from 'react-native';
import {useTranslation} from 'react-i18next';
import {IconUsersGroup, IconZoomExclamation} from '@tabler/icons-react-native';
import {useNavigation} from '@react-navigation/native';
import {StackNavigationProp} from '@react-navigation/stack';
import {Divider, ListItem, ListSkeleton, Skeleton, Title} from '@components';
import {useDebounce} from '@hooks/useDebounce';
import {SetState} from '@interfaces/generic';
import {
  ChatSearchUser,
  useOpenConversation,
  useSearchUsers,
} from '@modules/chats/hooks';
import {ChatUser} from '@modules/chats/interfaces';
import {ChatEmptyState, UserListItem} from '@modules/chats/components';
import {getChatItemLayout} from '@modules/chats/utils';
import {CONVERSATION_ITEM_HEIGHT} from '@modules/chats/constants';
import {RootStackParamList} from '@navigation/interfaces';
import {showSnackbar} from '@redux/dispatchers';
import {SPACING, useTheme} from '@shared/theme';
import {Screens} from '@shared/constants';
import {deaccentString, sentryLogs} from '@shared/utils';

import HorizontalUsersDisplayer from '../HorizontalUsersDisplayer';
import {styles} from './styles';

const keyExtractor = (item: ChatSearchUser) => `${item.id}`;

type ChatSearchUsersSection = {
  title?: string;
  data: ChatSearchUser[];
  type?: TopButton;
};

type TopButton = 'group';
interface Props {
  searchText: string;
  topButtons?: TopButton[];
  selectEnabled?: boolean;
  selectedUsers: ChatUser[];
  setSelectedUsers: SetState<ChatUser[]>;
  /**
   * Check each user if is in the channel (will show a description with this info)
   */
  isInChannel?: boolean;
  keyboardShouldPersistTaps?: ScrollViewProps['keyboardShouldPersistTaps'];
  keyboardDismissMode?: ScrollViewProps['keyboardDismissMode'];
  backgroundColor?: string;
}

const ItemSeparatorComponent = () => <Divider style={styles.divider} />;

function ChatSearchUsersComponent({
  searchText,
  topButtons,
  selectEnabled,
  selectedUsers,
  setSelectedUsers,
  isInChannel,
  keyboardShouldPersistTaps,
  keyboardDismissMode,
  backgroundColor,
}: Props) {
  const scrollRef = useRef<SectionList<ChatUser, ChatSearchUsersSection>>(null);
  const horizontalUsersRef = useRef<FlatList>(null);
  const {t} = useTranslation();
  const navigation = useNavigation<StackNavigationProp<RootStackParamList>>();
  const debouncedSearchText = useDebounce(searchText, 250);
  const {openConversation} = useOpenConversation();
  const {theme} = useTheme();

  useEffect(() => {
    scrollRef.current?.getScrollResponder?.()?.scrollTo({
      y: 0,
      animated: false,
    });
  }, [searchText]);

  const onUserPress = useCallback(
    (user: ChatUser) => {
      if (selectEnabled) {
        setSelectedUsers(prevSelectedUsers => {
          const isSelected = prevSelectedUsers.some(
            selectedUser => selectedUser.id === user.id,
          );
          if (isSelected) {
            return prevSelectedUsers.filter(
              selectedUser => selectedUser.id !== user.id,
            );
          }
          setTimeout(() => {
            horizontalUsersRef.current?.scrollToEnd({animated: true});
          }, 0);
          return [...prevSelectedUsers, user];
        });
      } else {
        openConversation(
          {users: [user]},
          {
            onSuccess: response => {
              if (!response.id) {
                sentryLogs.error({
                  message: 'Conversation id not defined',
                  module: 'CHATS',
                  component: 'ChatSearchUsers',
                });
                showSnackbar({
                  title: t('errors.api.500', {info: ''}),
                  variant: 'error',
                });
                return;
              }
              navigation.replace(Screens.CHAT_MESSAGES, {
                id: response.id,
              });
            },
          },
        );
      }
    },
    [selectEnabled, setSelectedUsers, openConversation, navigation, t],
  );

  const {users, isLoading, isFetchingNextPage, getNextPage, hasNextPage} =
    useSearchUsers({
      search: debouncedSearchText,
      filterMySelf: selectEnabled,
      isInChannel,
    });

  const groupedUsers = useMemo(() => {
    const map = new Map<string, ChatUser[]>();

    users?.forEach(user => {
      const firstLetter = deaccentString(
        user.hu_data.member.first_name.charAt(0),
      ).toUpperCase();

      if (!map.has(firstLetter)) {
        map.set(firstLetter, []);
      }

      map.get(firstLetter)!.push(user);
    });

    return Array.from(map, ([title, data]) => ({title, data}));
  }, [users]);

  const sections = useMemo(() => {
    if (topButtons?.length) {
      return [
        ...topButtons.map(button => ({type: button, data: []})),
        ...groupedUsers,
      ];
    }
    return groupedUsers;
  }, [groupedUsers, topButtons]);

  const topButtonDescriptor = useMemo(
    () => ({
      group: {
        title: t('chat.groups.new_group'),
        onPress: () =>
          navigation.navigate(Screens.CHATS_NEW_GROUP, {isGroupCreation: true}),
        Icon: IconUsersGroup,
      },
    }),
    [navigation, t],
  );
  const renderItem: SectionListRenderItem<ChatSearchUser> = useCallback(
    ({item, index, section}) => {
      const isSelected =
        selectedUsers.some(user => user.id === item.id) || item.isInChannel;
      return (
        <UserListItem
          user={item}
          onItemPress={onUserPress}
          isFirstItem={index === 0}
          isLastItem={index === section.data.length - 1}
          style={index === section.data.length - 1 && styles.lastItem}
          presentation="card"
          selectEnabled={selectEnabled}
          isSelected={isSelected}
          selectorDisabled={item.isInChannel}
          description={
            item.isInChannel ? t('chat.groups.already_member') : undefined
          }
        />
      );
    },
    [onUserPress, selectEnabled, selectedUsers, t],
  );

  const renderSectionHeader = useCallback(
    ({section}: {section: ChatSearchUsersSection}) => {
      if (section?.type) {
        const descriptor = topButtonDescriptor[section.type];
        return (
          <ListItem
            title={descriptor.title}
            onItemPress={descriptor.onPress}
            avatar={{Icon: descriptor.Icon, variant: 'primary'}}
            withRightIcon
            backgroundColor={theme.background.elements.default}
            style={[styles.lastItem, {height: CONVERSATION_ITEM_HEIGHT}]}
            presentation="card"
            isFirstItem
            isLastItem
          />
        );
      }
      return (
        <Title
          style={[styles.sectionTitle, !!backgroundColor && {backgroundColor}]}
          title={section.title}
        />
      );
    },
    [theme.background.elements.default, topButtonDescriptor, backgroundColor],
  );

  const onEndReached = useCallback(() => {
    if (!isLoading && hasNextPage) {
      getNextPage();
    }
  }, [isLoading, hasNextPage, getNextPage]);

  const ListEmptyComponent = useMemo(() => {
    if (isLoading) {
      return (
        <>
          <Skeleton style={styles.skeletonContainer}>
            <Skeleton.Item width="100%" height={SPACING.x3} />
          </Skeleton>
          <ListSkeleton presentation="card" />
        </>
      );
    }
    return (
      <ChatEmptyState
        icon={IconZoomExclamation}
        title={t('chat.search.not_found_title')}
        description={t('chat.search.not_found_subtitle')}
        style={styles.emptyState}
      />
    );
  }, [t, isLoading]);

  const onDisplayerUserPress = useCallback(
    (user: ChatUser) => {
      setSelectedUsers(prevSelectedUsers => {
        return prevSelectedUsers.filter(
          selectedUser => selectedUser.id !== user.id,
        );
      });
    },
    [setSelectedUsers],
  );

  return (
    <View
      style={[styles.container, !!backgroundColor && {backgroundColor}]}
      testID="chat-search-users">
      {selectEnabled && !!selectedUsers.length && (
        <HorizontalUsersDisplayer
          ref={horizontalUsersRef}
          users={selectedUsers}
          onPress={onDisplayerUserPress}
          style={styles.horizontalUsersContainer}
        />
      )}
      <SectionList<ChatUser, ChatSearchUsersSection>
        sections={sections}
        ref={scrollRef}
        contentContainerStyle={styles.contentContainer}
        keyExtractor={keyExtractor}
        renderItem={renderItem}
        renderSectionHeader={renderSectionHeader}
        getItemLayout={getChatItemLayout}
        stickySectionHeadersEnabled={selectEnabled}
        onEndReached={onEndReached}
        ListEmptyComponent={ListEmptyComponent}
        ListFooterComponent={
          isFetchingNextPage ? <ListSkeleton presentation="card" /> : null
        }
        keyboardShouldPersistTaps={keyboardShouldPersistTaps}
        keyboardDismissMode={keyboardDismissMode}
        ItemSeparatorComponent={ItemSeparatorComponent}
      />
    </View>
  );
}

export const ChatSearchUsers = memo(ChatSearchUsersComponent);
