import { useRef } from "react";
import { throttle } from "lodash";

const threshold = 0.1;

const useDragScrolling = (containers: string[]) => {
  const isScrolling = useRef(false);
  const targets = containers.map(
    (id) => document.querySelector(id) as HTMLElement,
  );
  const rects = useRef<DOMRect[]>([]);

  const goDown = (target: HTMLElement) => {
    return () => {
      target.scrollTop += 5;

      const { offsetHeight, scrollTop, scrollHeight } = target;
      const isScrollEnd = offsetHeight + scrollTop >= scrollHeight;

      if (isScrolling.current && !isScrollEnd) {
        window.requestAnimationFrame(goDown(target));
      }
    };
  };

  const goUp = (target: HTMLElement) => {
    return () => {
      target.scrollTop -= 5;
      if (isScrolling.current && target.scrollTop > 0) {
        window.requestAnimationFrame(goUp(target));
      }
    };
  };

  const onDragOver = (event: MouseEvent) => {
    // detect if mouse is in any rect
    rects.current.forEach((rect, index) => {
      if (event.clientX < rect.left || event.clientX > rect.right) {
        isScrolling.current = false;
        return;
      }

      const height = rect.bottom - rect.top;
      if (
        event.clientY > rect.top &&
        event.clientY < rect.top + threshold * height
      ) {
        isScrolling.current = true;
        window.requestAnimationFrame(goUp(targets[index]));
      } else if (
        event.clientY < rect.bottom &&
        event.clientY > rect.bottom - threshold * height
      ) {
        isScrolling.current = true;
        window.requestAnimationFrame(goDown(targets[index]));
      } else {
        isScrolling.current = false;
      }
    });
  };

  const throttleOnDragOver = throttle(onDragOver, 300);

  const addEventListenerForWindow = () => {
    rects.current = targets.map((t) => t.getBoundingClientRect());
    window.addEventListener("dragover", throttleOnDragOver, false);
  };

  const removeEventListenerForWindow = () => {
    window.removeEventListener("dragover", throttleOnDragOver, false);
    isScrolling.current = false;
  };

  return {
    addEventListenerForWindow,
    removeEventListenerForWindow,
  };
};

export default useDragScrolling;
