import { RefObject, useEffect, useRef, useState } from 'react';
import { CollectionReachBottom } from '../state/CollectionReachBottom';
import { ScrollableWindow } from '../reach-bottom-listener';
import { CollectionState, FiltersMap } from '@wix/bex-core';
import { useWixPatternsContainer } from '@wix/bex-core/react';
import { addEventListener } from '@wix/bex-core/util';

export interface UseCollectionReachBottomParams<
  T,
  F extends FiltersMap = FiltersMap,
> {
  collection: CollectionState<T, F>;
  containerRef?: RefObject<ScrollableWindow | null | undefined>;
  scrollMoreAlways?: boolean;
}

export function useCollectionReachBottom<T, F extends FiltersMap = FiltersMap>({
  collection,
  containerRef,
  scrollMoreAlways,
}: UseCollectionReachBottomParams<T, F>) {
  const targetRef = useRef<HTMLElement>(null);

  const { lodash } = useWixPatternsContainer();

  const {
    result: { keyedItems },
  } = collection;

  const [collectionReachBottom] = useState(
    () =>
      new CollectionReachBottom({
        collection,
        lodash,
      }),
  );

  useEffect(() => {
    if (containerRef?.current == null) {
      return;
    }

    collectionReachBottom.reachBottom.container = containerRef?.current;
    collectionReachBottom.reachBottom.target = targetRef?.current;

    const disposers = [
      addEventListener(collection.emitter, 'triggerReachBottomListener', () => {
        collectionReachBottom.triggerListenerIfReached();
      }),
    ];

    collectionReachBottom.subscribe();

    return () => {
      collectionReachBottom.reachBottom.target = null;
      disposers.forEach((d) => d());
      collectionReachBottom.unsubscribe();
    };
  }, []);

  // Check if should load more items (scrollable container is not filled yet) after new data has been rendered
  useEffect(() => {
    // In jsdom element dimensions are always 0, so calculations inside `CollectionReachBottom` are not relevant.
    if (process.env.NODE_ENV === 'test') {
      return;
    }
    if (scrollMoreAlways || containerRef?.current?.scrollHeight) {
      collectionReachBottom.triggerListenerIfReached();
    }
  }, [keyedItems.length]);

  return { containerRef, targetRef };
}
