import {memo, useCallback, useEffect, useMemo, useRef} from 'react';
import {StyleSheet} from 'react-native';
import {useTranslation} from 'react-i18next';
import {IconMessages} from '@tabler/icons-react-native';
import {AnimatedLegendList} from '@legendapp/list/reanimated';
import {useNavigation} from '@react-navigation/native';
import {useAnimatedScrollHandler} from 'react-native-reanimated';
import {Divider, ListSkeleton} from '@components/index';
import {closeAllSwipeables} from '@components/RNSwipeable';
import {useEvent} from '@hooks/useEvent';
import {
  useConversations,
  useIsFetchingAllConversations,
} from '@modules/chats/store';
import {ChatEmptyState, ChatListItem} from '@modules/chats/components';
import {Conversation} from '@modules/chats/interfaces';
import {
  CONVERSATION_ITEM_AVATAR_SIZE,
  CONVERSATION_ITEM_HEIGHT,
  CONVERSATION_SEPARATOR_HEIGHT,
} from '@modules/chats/constants';
import {windowDimensions} from '@shared/constants';
import {SPACING, useTheme} from '@shared/theme';

import type {LegendListRef} from '@legendapp/list/react-native';

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

const Separator = () => {
  return <Divider direction="horizontal" style={styles.separator} />;
};

const getFixedItemSize = () => {
  return CONVERSATION_ITEM_HEIGHT; // item_height + separator_height
};

interface Props {
  onMorePress: (target: Conversation) => void;
  onPinPress: (target: Conversation) => void;
  onMarkAsUnreadPress: (target: Conversation, unreadCount: number) => void;
  onScroll?: ReturnType<typeof useAnimatedScrollHandler>;
}

const ConversationList = ({
  onMorePress,
  onPinPress,
  onMarkAsUnreadPress,
  onScroll,
}: Props) => {
  const {t} = useTranslation();
  const {addListener} = useNavigation();
  const conversations = useConversations();
  const isFetchingAllConversations = useIsFetchingAllConversations();
  const listRef = useRef<Nullable<LegendListRef>>(null);
  const targetId = useRef<Nullable<string>>(null);
  const {theme} = useTheme();
  const isScrollToTopEnabled = !!conversations.at(0)?.id;
  const pinnedConversationIds = useMemo(() => {
    return conversations.reduce((acc, conversation) => {
      if (conversation.properties?.pinned_at) {
        acc.push(conversation.id);
      }
      return acc;
    }, [] as string[]);
  }, [conversations]);
  // Workaround: Fixes the issue where rapidly opening the chat list causes it to render nothing
  const listKey = String(conversations.length > 0);

  const onPinPressInternal = useCallback(
    (target: Conversation) => {
      targetId.current = target.id;
      onPinPress(target);
    },
    [onPinPress],
  );

  const renderItem = useEvent(({item}: {item: Conversation}) => (
    <ChatListItem
      chat={item}
      onMorePress={onMorePress}
      onPinPress={onPinPressInternal}
      onMarkAsUnreadPress={onMarkAsUnreadPress}
    />
  ));

  const listContainerStyle = useMemo(() => {
    return [styles.list, {backgroundColor: theme.background.layout.tertiary}];
  }, [theme]);

  /**
   * Scroll to the new pinned conversation. It has a delay to wait list to be reordered.
   */
  useEffect(() => {
    if (targetId.current && pinnedConversationIds.includes(targetId.current)) {
      setTimeout(() => {
        listRef.current?.scrollToIndex({index: 0});
      }, 0);
      targetId.current = null;
    }
  }, [pinnedConversationIds]);

  /**
   * Scroll to top on tab press
   */
  useEffect(() => {
    if (!isScrollToTopEnabled) {
      return;
    }

    // @ts-expect-error: This type definitely exists
    const listener = addListener('tabPress', () => {
      listRef.current?.scrollToIndex({index: 0});
    });
    return () => listener();
  }, [addListener, isScrollToTopEnabled]);

  return (
    <AnimatedLegendList
      key={listKey}
      ref={listRef}
      data={conversations}
      renderItem={renderItem}
      keyExtractor={keyExtractor}
      getFixedItemSize={getFixedItemSize}
      keyboardDismissMode={'on-drag'}
      maintainVisibleContentPosition={false}
      style={listContainerStyle}
      recycleItems={true}
      drawDistance={500}
      onScroll={onScroll}
      scrollEventThrottle={16}
      ItemSeparatorComponent={Separator}
      onScrollBeginDrag={closeAllSwipeables}
      ListEmptyComponent={
        <ChatEmptyState
          icon={IconMessages}
          title={t('chat.no_messages_yet')}
          description={t('chat.no_messages_yet_description')}
          style={styles.emptyState}
        />
      }
      ListFooterComponent={
        isFetchingAllConversations ? (
          <>
            <Separator />
            <ListSkeleton
              presentation="flat"
              itemLength={1}
              style={styles.footerSkeleton}
            />
          </>
        ) : null
      }
    />
  );
};

const styles = StyleSheet.create({
  list: {paddingHorizontal: 0},
  emptyState: {height: (windowDimensions.height * 2) / 3},
  separator: {
    height: CONVERSATION_SEPARATOR_HEIGHT,
    justifyContent: 'center',
    width: '100%',
    paddingLeft: SPACING.x2 + CONVERSATION_ITEM_AVATAR_SIZE + SPACING.x1, // padding_h + avatar_size + avatar_title_gap
  },
  footerSkeleton: {
    paddingHorizontal: SPACING['x1.5'],
    marginTop: -SPACING['x0.5'],
  },
});

export default memo(ConversationList);
