import { type FC, type ReactElement, type ReactNode, useEffect } from 'react';
import { useInView } from 'react-intersection-observer';
import { type InfiniteQueryObserverBaseResult } from 'react-query';

import Box from '@material-hu/mui/Box';
import CircularProgress from '@material-hu/mui/CircularProgress';

import EndDivider from './EndDivider';
import List, { type ListProps } from './List';

export type InfiniteListProps = ListProps &
  Partial<
    Pick<
      InfiniteQueryObserverBaseResult,
      'isFetchingNextPage' | 'hasNextPage' | 'fetchNextPage'
    >
  > & {
    withEnd?: boolean;
    children: ReactNode;
    totalPages?: number;
    isEmpty?: boolean;
    renderSkeleton?: ReactElement;
    loadingSkeleton?: boolean;
  };

const InfiniteList: FC<InfiniteListProps> = props => {
  const {
    withEnd = false,
    fetchNextPage,
    hasNextPage,
    isFetchingNextPage,
    children,
    isLoading,
    totalPages = 0,
    isEmpty,
    renderSkeleton,
    loadingSkeleton = false,
    ...listProps
  } = props;

  const [ref, inView] = useInView({
    threshold: 0,
  });

  const showReachedEnd = !hasNextPage && withEnd && totalPages > 1;

  useEffect(() => {
    if (inView && hasNextPage && !isEmpty) {
      fetchNextPage?.();
    }
  }, [inView, hasNextPage, isEmpty]);

  return (
    <List
      isLoading={isLoading}
      isEmpty={isEmpty}
      loadingSkeleton={loadingSkeleton && renderSkeleton}
      {...listProps}
    >
      {children}
      {showReachedEnd && <EndDivider />}
      {!isLoading && hasNextPage && (
        <Box
          sx={{ height: '2px' }}
          className="loadingMoreRef"
          ref={ref}
        />
      )}
      {isFetchingNextPage &&
        (renderSkeleton || (
          <Box sx={{ textAlign: 'center', mt: 1 }}>
            <CircularProgress />
          </Box>
        ))}
    </List>
  );
};

export default InfiniteList;
