import React, {
  ComponentType,
  useCallback,
  useEffect,
  useMemo,
  useRef,
} from 'react';
import {
  StyleSheet,
  FlatList,
  View,
  ViewStyle,
  ActivityIndicator,
} from 'react-native';
import {
  useStyles,
  useAutoScroll,
  useTheme,
  useChatRoomState,
  useChatMessagesEffect,
  useLoadReactionPacksEffect,
  useUserReactionsEffect,
  useReactionSpace,
  useLoadUserReactions,
  useChatRoomActions,
} from '../../hooks';
import {
  LLChatMessageItem,
  LLChatMessageItemProps,
} from '../LLChatMessageItem';
import {
  LLMessageListEmptyComponent,
  LLMessageListEmptyComponentProps,
} from './LLMessageListEmptyComponent';
import {
  IChatMessage,
  ComponentStyleProp,
  LLComponentStyleFn,
} from '../../types';
import { LLLoadActionButtonComponent } from '../LLLoadActionButton';

export type LLChatMessageListStyles = {
  rootContainer: ViewStyle;
  listLoadingIndicator: ViewStyle;
};

export type LLChatMessageListProps =
  ComponentStyleProp<LLChatMessageListStyles> & {
    roomId: string;
    MessageItemComponent?: typeof LLChatMessageItem;
    MessageItemComponentStyles?: LLChatMessageItemProps['styles'];
    MessageListComponent?: typeof FlatList;
    MessageListLoadingComponent?: ComponentType<unknown>;
    MessageListEmptyComponent?: typeof LLMessageListEmptyComponent;
    LoadPrevButtonComponent?: typeof LLLoadActionButtonComponent;
    MessageListEmptyComponentStyles?: LLMessageListEmptyComponentProps['styles'];
  };

const listItemKeyExtractor = (message: IChatMessage) => message.id;
export function LLChatMessageList({
  roomId,
  styles: stylesProp,
  MessageListComponent = FlatList,
  MessageItemComponent = LLChatMessageItem,
  MessageListEmptyComponent = LLMessageListEmptyComponent,
  LoadPrevButtonComponent = LLLoadActionButtonComponent,
  MessageItemComponentStyles,
  MessageListLoadingComponent,
  MessageListEmptyComponentStyles,
}: LLChatMessageListProps) {
  const listRef = useRef<FlatList>(null);
  const userReactionsLoadedRef = useRef(false);
  const { chatMessages, chatMessagesLoaded, messageListIterator } =
    useChatRoomState({
      roomId,
    });
  const { onContentSizeChangeHandler, onScrollEndDrag } = useAutoScroll({
    ref: listRef,
  });
  const messageListStyles = useStyles({
    componentStylesFn: getMessageListStyles,
    stylesProp,
  });
  const { theme } = useTheme();
  const { reactionSpace } = useReactionSpace({ targetGroupId: roomId });
  useChatMessagesEffect({ roomId });
  useLoadReactionPacksEffect({ reactionSpaceId: reactionSpace?.id });
  useUserReactionsEffect({ reactionSpaceId: reactionSpace?.id });
  const { loadPrevMessages } = useChatRoomActions({ roomId });

  const targetIds = useMemo(
    () => chatMessages?.map(({ id }) => id),
    [chatMessages]
  );
  const { loadUserReactions } = useLoadUserReactions({
    reactionSpaceId: reactionSpace?.id,
  });

  useEffect(() => {
    if (!targetIds?.length || userReactionsLoadedRef.current) {
      return;
    }
    loadUserReactions({ targetIds });
    userReactionsLoadedRef.current = true;
  }, [targetIds]);

  const renderLoadPrevMessagesButton = useCallback(() => {
    if (!messageListIterator) {
      return null;
    }
    return (
      <LoadPrevButtonComponent
        label="Load previous messages"
        actionInProgressLabel="Loading previous messages"
        onPress={loadPrevMessages}
      />
    );
  }, [messageListIterator, loadPrevMessages]);
  const renderListItem = useCallback(
    ({ item }) => (
      <MessageItemComponent
        message={item}
        styles={MessageItemComponentStyles}
      />
    ),
    [MessageItemComponentStyles]
  );

  const renderListLoadingComponent = MessageListLoadingComponent ? (
    <MessageListLoadingComponent />
  ) : (
    <ActivityIndicator
      size={'large'}
      color={theme.text}
      style={messageListStyles.listLoadingIndicator}
    />
  );

  return (
    <View style={messageListStyles.rootContainer}>
      {!chatMessagesLoaded ? (
        renderListLoadingComponent
      ) : (
        <MessageListComponent
          ref={listRef}
          contentContainerStyle={{ flexGrow: 1 }}
          ListEmptyComponent={
            <MessageListEmptyComponent
              styles={MessageListEmptyComponentStyles}
            />
          }
          data={chatMessages}
          renderItem={renderListItem}
          keyExtractor={listItemKeyExtractor}
          onContentSizeChange={onContentSizeChangeHandler}
          onScrollEndDrag={onScrollEndDrag}
          ListHeaderComponent={renderLoadPrevMessagesButton}
          maintainVisibleContentPosition={{
            minIndexForVisible: 0,
          }}
        />
      )}
    </View>
  );
}

const getMessageListStyles: LLComponentStyleFn<LLChatMessageListStyles> = ({
  theme,
}) =>
  StyleSheet.create({
    rootContainer: {
      display: 'flex',
      flex: 1,
      justifyContent: 'center',
      marginBottom: 10,
    },
    listLoadingIndicator: {},
  });
