import React, {memo, useCallback, useMemo, useRef, useState} from 'react';
import {useTranslation} from 'react-i18next';
import {useNavigation} from '@react-navigation/native';
import {BottomModalFooterProps, Dialog, InputSearch} from '@components';
import {useEvent} from '@hooks/useEvent';
import {Navigation} from '@interfaces/navigation';
import {ChatSearch} from '@modules/chats/components';
import {useMessageActionsContext} from '@modules/chats/contexts';
import {useForwardMessage} from '@modules/chats/hooks/useForwardMessage';
import {MAX_FORWARD_ITEMS} from '@modules/chats/constants';
import {getMapsForIMChannels} from '@modules/chats/store/selectors';
import {showSnackbar} from '@redux/dispatchers';
import {persistedUserId} from '@services/localStorage';
import {sentryLogs, wait} from '@shared/utils';
import {Screens} from '@shared/constants';

import {ListItem} from './components/ListItem/ListItem';
import {styles} from './styles';
import {RenderItem, SelectedItem, SelectedItemsState} from './interfaces';
import {prepareSelectedItems} from './utils';

function DialogForwardMessageCmp() {
  const {targetMessage, reset, isForwarding} = useMessageActionsContext();
  const message = targetMessage?.data;
  const [searchText, setSearchText] = useState('');
  const {t} = useTranslation();
  const navigation =
    useNavigation<Navigation<Screens.CHAT_MESSAGES>['navigation']>();
  const [selectedItems, setSelectedItems] = useState<SelectedItemsState>(
    new Map(),
  );
  const mappers = useRef(getMapsForIMChannels()); // Saving into a ref to avoid subscribing to the store
  const {forwardMessage, isLoading} = useForwardMessage();

  const finishForwarding = useCallback(() => {
    reset();
    setSelectedItems(new Map());
  }, [reset]);

  const onSelectItem = useEvent((item: SelectedItem) => {
    const newItems = new Map(selectedItems);
    const userChannelId = item.isUser
      ? mappers.current.usersToChannels.get(+item.id)
      : undefined;
    const channelId = userChannelId || item.id;

    if (newItems.has(channelId)) {
      newItems.delete(channelId);
    } else {
      newItems.set(channelId, item);
    }
    setSelectedItems(newItems);
  });

  const openChatIfNeeded = useCallback(
    (channelId: string) => {
      if (channelId !== message?.channel) {
        if (!channelId) {
          sentryLogs.error({
            message: 'Conversation id not defined',
            module: 'CHATS',
            component: 'DialogForwardMessage',
            data: {
              channelId,
            },
          });
          showSnackbar({
            title: t('errors.api.500', {info: ''}),
            variant: 'error',
          });
          return;
        }
        navigation.replace(Screens.CHAT_MESSAGES, {
          id: channelId,
        });
      }
    },
    [message?.channel, navigation, t],
  );

  const onForward = useCallback(async () => {
    if (!message) {
      return;
    }
    const preparedData = prepareSelectedItems(selectedItems);

    await forwardMessage(message, preparedData);

    finishForwarding();

    if (preparedData.destinationChannelIds.length === 1) {
      // Wait dialog to close before opening the chat
      await wait(500);
      openChatIfNeeded(preparedData.destinationChannelIds[0]);
    }
  }, [
    finishForwarding,
    message,
    openChatIfNeeded,
    selectedItems,
    forwardMessage,
  ]);

  const renderItem: RenderItem = useCallback(
    ({item}) => {
      const channelIdFromUser = mappers.current.usersToChannels.get(
        Number(item.id),
      );
      const isSelected =
        selectedItems.has(item.id) ||
        (!!channelIdFromUser && selectedItems.has(channelIdFromUser));
      return (
        <ListItem
          item={item}
          userId={persistedUserId!}
          isSelected={isSelected}
          disabled={
            selectedItems.size >= MAX_FORWARD_ITEMS &&
            !selectedItems.has(item.id)
          }
          onSelect={onSelectItem}
        />
      );
    },
    [onSelectItem, selectedItems, mappers],
  );

  const footer = useMemo((): BottomModalFooterProps => {
    const items = Array.from(selectedItems.values());
    const hasItems = selectedItems.size;
    return {
      primaryButton: {
        text: t('chat.forward.forward'),
        onPress: onForward,
        disabled: !hasItems,
        isLoading,
      },
      infoText: hasItems ? items.map(item => item.name).join(', ') : undefined,
      withIconPrefix: false,
      infoTextNumberOfLines: 1,
    };
  }, [t, onForward, selectedItems, isLoading]);

  return (
    <Dialog
      isVisible={isForwarding}
      contentStyle={styles.dialog}
      title={t('chat.forward.send_to')}
      onClose={finishForwarding}
      footer={footer}
      enableDynamicSizing={true}
      wrapperType="none">
      <InputSearch
        placeholder={t('general.search')}
        onChangeText={setSearchText}
        style={styles.searchInput}
        variant="custom"
      />
      <ChatSearch
        searchText={searchText}
        renderItem={renderItem}
        freezeConversations={isLoading}
        useBottomSheetSectionList={true}
        withoutDeactivatedUsers={true}
      />
    </Dialog>
  );
}

export const DialogForwardMessage = memo(DialogForwardMessageCmp);
