import type { BacktopProps } from './backtop';

import { nextTick, onMounted, ref, shallowRef } from 'vue';

import {
  useEventListener,
  useResizeObserver,
  useThrottleFn,
} from '@vueuse/core';

export const useBackTop = (props: BacktopProps) => {
  const el = shallowRef<HTMLElement>();
  const container = shallowRef<Document | HTMLElement>();
  const resizeTarget = shallowRef<HTMLElement>();
  const canScrollDown = ref(false);
  const canScrollUp = ref(false);
  const scrollable = ref(false);
  const visible = ref(false);

  const handleScroll = () => {
    if (el.value) {
      const maxScrollTop = Math.max(
        el.value.scrollHeight - el.value.clientHeight,
        0,
      );
      scrollable.value = maxScrollTop > 1;
      canScrollUp.value = el.value.scrollTop > 1;
      canScrollDown.value = el.value.scrollTop < maxScrollTop - 1;
      visible.value = el.value.scrollTop >= (props?.visibilityHeight ?? 0);
    }
  };

  const handleClick = () => {
    el.value?.scrollTo({ behavior: 'smooth', top: 0 });
  };

  const handleBottomClick = () => {
    if (!el.value) {
      return;
    }
    el.value.scrollTo({
      behavior: 'smooth',
      top: Math.max(el.value.scrollHeight - el.value.clientHeight, 0),
    });
  };

  const handleScrollThrottled = useThrottleFn(handleScroll, 300, true);

  useEventListener(container, 'scroll', handleScrollThrottled);
  useResizeObserver(resizeTarget, handleScrollThrottled);
  onMounted(() => {
    container.value = document;
    el.value = document.documentElement;
    resizeTarget.value = document.body;

    if (props.target) {
      el.value = document.querySelector<HTMLElement>(props.target) ?? undefined;

      if (!el.value) {
        throw new Error(`target does not exist: ${props.target}`);
      }
      container.value = el.value;
      resizeTarget.value = el.value;
    }
    void nextTick(handleScroll);
  });

  return {
    canScrollDown,
    canScrollUp,
    handleBottomClick,
    handleClick,
    scrollable,
    visible,
  };
};
