import type { Ref } from 'vue';
import raf from '../../_util/raf';
import isFF from '../utils/isFirefox';
import useOriginScroll from './useOriginScroll';

interface FireFoxDOMMouseScrollEvent {
  detail: number;
  preventDefault: Function;
}

export default function useFrameWheel(
  inVirtual: Ref<boolean>,
  isScrollAtTop: Ref<boolean>,
  isScrollAtBottom: Ref<boolean>,
  onWheelDelta: (offset: number) => void,
): [(e: WheelEvent) => void, (e: FireFoxDOMMouseScrollEvent) => void] {
  let offsetRef = 0;
  let nextFrame: number | null | undefined = null;

  // Firefox patch
  let wheelValue = null;
  let isMouseScroll = false;

  // Scroll status sync
  const originScroll = useOriginScroll(isScrollAtTop, isScrollAtBottom);

  function onWheel(event: { preventDefault?: any; deltaY?: any }) {
    if (!inVirtual.value) return;

    raf.cancel(nextFrame!);

    const { deltaY } = event;
    offsetRef += deltaY;
    wheelValue = deltaY;

    // Do nothing when scroll at the edge, Skip check when is in scroll
    if (originScroll(deltaY)) return;

    // Proxy of scroll events
    if (!isFF) {
      event.preventDefault();
    }

    nextFrame = raf(() => {
      // Patch a multiple for Firefox to fix wheel number too small
      // ref: https://github.com/ant-design/ant-design/issues/26372#issuecomment-679460266
      const patchMultiple = isMouseScroll ? 10 : 1;
      onWheelDelta(offsetRef * patchMultiple);
      offsetRef = 0;
    });
  }

  // A patch for firefox
  function onFireFoxScroll(event: { detail: any }) {
    if (!inVirtual.value) return;

    isMouseScroll = event.detail === wheelValue;
  }

  return [onWheel, onFireFoxScroll];
}
