import {useTimeout} from 'ahooks';
import {debounce} from 'lodash-es';
import {useEffect, useMemo, useRef, useState} from 'react';
import {FixedSizeList, ListOnScrollProps} from 'react-window';

function nextTick(fn: () => void) {
  Promise.resolve().then(fn);
}

export function useInfiniteScroll(data: any[]) {
  const scrollRef = useRef<FixedSizeList>(null);
  const prevSize = useRef(0);
  const timer = useRef<NodeJS.Timer>();
  const [scroll, setScroll] = useState(false);
  const nowIdx = useRef(0);

  const listData = useMemo(
    function () {
      return scroll ? [...data, ...data] : data;
    },
    [data, scroll],
  );

  useEffect(
    function () {
      if (timer.current) {
        clearInterval(timer.current);
      }

      if (!scroll) return;

      timer.current = setInterval(function () {
        nowIdx.current++;

        scrollRef.current?.scrollToItem(nowIdx.current, 'start');
      }, 3000);

      return () => clearInterval(timer.current);
    },
    [scroll],
  );

  const [smooth, setSmooth] = useState(true);
  const [delay, setDelay] = useState(false);
  useTimeout(
    function () {
      setSmooth(true);
      setDelay(false);
    },
    delay ? 500 : void 0,
  );

  function scrollToTop() {
    nowIdx.current = 0;

    setSmooth(false);
    setDelay(true);

    scrollRef.current?.scrollTo(0);
  }

  const onScroll = debounce(
    function (e: ListOnScrollProps) {
      const {length} = data;
      e.scrollOffset >= length * 54 && scrollToTop();
    },
    50,
    {leading: false, trailing: true},
  );

  function jungleNeedScroll(height?: number) {
    const {length} = data;

    // 每次需要切换是否滚动时(e.g 数据切换) 切换到最顶部
    scrollToTop();

    // 如果超出显示区域确认需要进行滚动
    nextTick(function () {
      setScroll(length * 54 > (height ?? prevSize.current));
    });
  }

  function onElementSizeChange(height: number) {
    if (prevSize.current === height) return;
    prevSize.current = height;

    jungleNeedScroll(height);
  }

  return [
    {scrollRef, listData, smooth},
    {onElementSizeChange, onScroll},
  ] as const;
}
