import {
  type CSSProperties,
  type FC,
  memo,
  type Ref,
  useCallback,
  useMemo,
  useRef,
} from 'react';
import {
  type FetchPreviousPageOptions,
  type InfiniteQueryObserverResult,
} from 'react-query';
import { useParams } from 'react-router';

import {
  LegendList,
  type LegendListRef,
  type LegendListRenderItemProps,
} from '@legendapp/list/react';
import { type AxiosResponse } from 'axios';
import Box from '@material-hu/mui/Box';
import CircularProgress from '@material-hu/mui/CircularProgress';

import { useLatestRef } from 'src/hooks/useLatestRef';
import { CONVERSATIONS_MESSAGES_CONTAINER } from 'src/pages/dashboard/Conversations/constants';
import { AudioManagerProvider } from 'src/pages/dashboard/Conversations/contexts/AudioManagerContext';
import { useScrollToMessageConversation } from 'src/pages/dashboard/Conversations/contexts/ScrollToMessageConversationContext';
import {
  type ConversationMessage as ConversationMessageType,
  type ConversationsMessagesResponse,
  type Member,
} from 'src/pages/dashboard/Conversations/types';

import useManageScrollConversations from '../../hooks/useManageScrollConversations';

import ConversationMessageBlock from './ConversationMessageBlock';
import DropZoneConversations from './DropZoneConversations';

type ConversationMessagesProps = {
  messages: ConversationMessageType[];
  members: Member[];
  isGroupConversation: boolean;
  unreadCount: number;
  hasPreviousPage: boolean;
  fetchPreviousPage: (
    options?: FetchPreviousPageOptions,
  ) => Promise<
    InfiniteQueryObserverResult<
      AxiosResponse<ConversationsMessagesResponse, any>,
      unknown
    >
  >;
  isFetchingPreviousPage: boolean;
  latestRead?: string;
  isSelfConversation: boolean;
  setFooterRef: Ref<unknown>;
  listRef: React.RefObject<LegendListRef>;
};

const ConversationMessages: FC<ConversationMessagesProps> = ({
  listRef: listRefProp,
  setFooterRef,
  messages,
  members,
  isGroupConversation,
  unreadCount,
  hasPreviousPage,
  isFetchingPreviousPage,
  fetchPreviousPage,
  latestRead,
  isSelfConversation,
}) => {
  const listRef = listRefProp || useRef<LegendListRef>(null);
  useManageScrollConversations(listRef);
  const { id } = useParams();
  const { isScrollingToMessage } = useScrollToMessageConversation();

  const lastReadIndex = useMemo(
    () =>
      unreadCount > 0
        ? messages.findIndex(
            message => message?.hu_data?.message_ts === latestRead,
          )
        : -1,
    [id],
  );

  const fetchingStateRef = useLatestRef({
    hasPreviousPage,
    isFetchingPreviousPage,
    isScrollingToMessage,
  });

  const onStartReached = useCallback(() => {
    const {
      hasPreviousPage: hasPreviousPageLatest,
      isFetchingPreviousPage: isFetchingPreviousPageLatest,
      isScrollingToMessage: isScrollingToMessageLatest,
    } = fetchingStateRef.current;
    if (
      !isScrollingToMessageLatest &&
      hasPreviousPageLatest &&
      !isFetchingPreviousPageLatest
    ) {
      fetchPreviousPage();
    }
  }, [fetchPreviousPage]);

  const keyExtractor = useCallback(
    (message: ConversationMessageType, index: number) =>
      message?.hu_data?.message_ts || `${message.ts ?? index}`,
    [],
  );

  const renderMessageItem = useCallback(
    ({ item, index }: LegendListRenderItemProps<ConversationMessageType>) => {
      const messagePrev = messages[index - 1];
      const nextMessage = messages[index + 1];

      return (
        <ConversationMessageBlock
          message={item}
          messagePrev={messagePrev}
          nextMessage={nextMessage}
          members={members}
          position={index}
          unreadCount={unreadCount}
          latestRead={latestRead}
          hasPreviousPage={hasPreviousPage}
          isGroupConversation={isGroupConversation}
          isSelfConversation={isSelfConversation}
        />
      );
    },
    [
      hasPreviousPage,
      isGroupConversation,
      isSelfConversation,
      latestRead,
      members,
      messages,
      unreadCount,
    ],
  );

  const loaderComponent = isFetchingPreviousPage ? (
    <Box
      sx={{
        position: 'absolute',
        top: 0,
        left: 0,
        right: 0,
        zIndex: 1,
        display: 'flex',
        justifyContent: 'center',
        pt: 1,
        pointerEvents: 'none',
      }}
    >
      <Box
        sx={{
          width: 52,
          height: 52,
          borderRadius: '50%',
          display: 'flex',
          alignItems: 'center',
          justifyContent: 'center',
          backgroundColor: theme => theme.palette.new.background.layout.default,
          boxShadow: theme =>
            `0 2px 12px ${theme.palette.new.shadows['4dp']}, 0 0 30px ${theme.palette.new.shadows['8dp']}`,
        }}
      >
        <CircularProgress
          color="primary"
          size={22}
        />
      </Box>
    </Box>
  ) : undefined;

  const listFooterComponent = useMemo(
    () => (
      <>
        {loaderComponent}
        <Box ref={setFooterRef} />
      </>
    ),
    [setFooterRef, loaderComponent],
  );
  const extraData = useMemo(
    () => ({ latestRead, unreadCount }),
    [latestRead, unreadCount, members],
  );

  return (
    <AudioManagerProvider>
      <Box
        sx={{
          flex: 1,
          display: 'flex',
          overflowY: 'hidden',
          position: 'relative',
          backgroundColor: theme => theme.palette.new.background.layout.default,
          borderTop: theme =>
            `1px solid ${theme.palette.new.border.neutral.default}`,
          borderBottom: theme =>
            `1px solid ${theme.palette.new.border.neutral.default}`,
          [`& #${CONVERSATIONS_MESSAGES_CONTAINER}`]: {
            scrollbarWidth: 'thin',
            scrollbarColor: 'transparent transparent',
            transition: 'scrollbar-color 0.2s linear',
          },
          [`& #${CONVERSATIONS_MESSAGES_CONTAINER}:hover`]: {
            scrollbarColor: '#aaa transparent', // This color not exists in the theme, came from perfect-scrollbar
          },
        }}
      >
        <DropZoneConversations sx={{ flex: 1, outline: 'none' }}>
          <LegendList
            ref={listRef}
            id={CONVERSATIONS_MESSAGES_CONTAINER}
            key={id}
            extraData={extraData}
            style={styles.list}
            contentContainerStyle={styles.contentContainer}
            initialScrollAtEnd={lastReadIndex === -1}
            initialScrollIndex={
              lastReadIndex !== -1 ? lastReadIndex : undefined
            }
            drawDistance={1000}
            data={messages}
            renderItem={renderMessageItem}
            keyExtractor={keyExtractor}
            ListFooterComponent={listFooterComponent}
            onStartReached={onStartReached}
            onStartReachedThreshold={1}
            alignItemsAtEnd
            maintainVisibleContentPosition
            maintainScrollAtEnd
            estimatedItemSize={61}
          />
        </DropZoneConversations>
      </Box>
    </AudioManagerProvider>
  );
};

export default memo(ConversationMessages);

const styles = {
  list: {
    flex: 1,
    height: '100%',
    width: '100%',
  },
  contentContainer: {
    paddingTop: 16,
    paddingBottom: 16,
  },
} satisfies Record<string, CSSProperties>;
