import { TocItem, TocList } from '@ctzhian/tiptap';
import { useCallback, useEffect, useRef, useState } from 'react';

const useScroll = (headings: TocList, domId: string) => {
  const [activeHeading, setActiveHeading] = useState<TocItem | null>(null);
  const isFirstLoad = useRef(true);
  const scrollTimeoutRef = useRef<NodeJS.Timeout | null>(null);
  const isManualScroll = useRef(false);

  const debounce = <T extends (...args: any[]) => any>(
    func: T,
    delay: number,
  ) => {
    return (...args: Parameters<T>) => {
      if (scrollTimeoutRef.current) {
        clearTimeout(scrollTimeoutRef.current);
      }
      scrollTimeoutRef.current = setTimeout(() => func(...args), delay);
    };
  };

  const scrollToElement = useCallback(
    (elementId: string, offset = 80) => {
      const element = document.getElementById(elementId);
      if (element) {
        const container = document.getElementById(domId) || window;
        const targetHeading = headings.find(h => h.id === elementId);
        if (targetHeading) {
          isManualScroll.current = true;
          setActiveHeading(targetHeading);
          location.hash = encodeURIComponent(targetHeading.textContent);

          const elementPosition = element.getBoundingClientRect().top;
          const scrollTop =
            'scrollY' in container ? container.scrollY : container.scrollTop;
          const offsetPosition = elementPosition + scrollTop - offset;

          container.scrollTo({
            top: offsetPosition,
            behavior: 'smooth',
          });

          setTimeout(() => {
            isManualScroll.current = false;
          }, 1000);
        }
      }
    },
    [headings],
  );

  const findActiveHeading = useCallback(() => {
    const levels = Array.from(
      new Set(headings.map(it => it.level).sort((a, b) => a - b)),
    ).slice(0, 3);
    const visibleHeadings = headings.filter(header =>
      levels.includes(header.level),
    );

    if (visibleHeadings.length === 0) return null;

    const offset = 100;
    let activeHeader: TocItem | null = null;

    for (let i = visibleHeadings.length - 1; i >= 0; i--) {
      const header = visibleHeadings[i];
      const element = document.getElementById(header.id);
      if (element) {
        const container = document.getElementById(domId) || window;
        const scrollTop =
          'scrollY' in container ? container.scrollY : container.scrollTop;
        const elementTop = element.getBoundingClientRect().top + scrollTop;
        if (elementTop <= scrollTop + offset) {
          activeHeader = header;
          break;
        }
      }
    }

    if (!activeHeader && visibleHeadings.length > 0) {
      activeHeader = visibleHeadings[0];
    }

    return activeHeader;
  }, [headings]);

  const debouncedScrollHandler = useCallback(
    debounce(() => {
      if (isManualScroll.current) return;
      const activeHeader = findActiveHeading();
      if (activeHeader && activeHeader.id !== activeHeading?.id) {
        setActiveHeading(activeHeader);
      }
    }, 100),
    [findActiveHeading, activeHeading],
  );

  useEffect(() => {
    if (isFirstLoad.current && headings.length > 0) {
      const hash = decodeURIComponent(location.hash).slice(1);
      if (hash) {
        const targetHeading = headings.find(
          header => header.textContent === hash,
        );
        if (targetHeading) {
          setActiveHeading(targetHeading);
          setTimeout(() => {
            isManualScroll.current = true;
            const element = document.getElementById(targetHeading.id);
            if (element) {
              const container = document.getElementById(domId) || window;
              const elementPosition = element.getBoundingClientRect().top;
              const scrollTop =
                'scrollY' in container
                  ? container.scrollY
                  : container.scrollTop;
              const offsetPosition = elementPosition + scrollTop - 80;

              container.scrollTo({
                top: offsetPosition,
                behavior: 'smooth',
              });
            }
            setTimeout(() => {
              isManualScroll.current = false;
            }, 1000);
          }, 100);
        }
      } else {
        // 没有hash时，设置第一个标题为活跃状态并设置hash
        // const activeHeader = findActiveHeading()
        // if (activeHeader) {
        //   setActiveHeading(activeHeader)
        //   location.hash = encodeURIComponent(activeHeader.title)
        // }
      }
      isFirstLoad.current = false;
    }
  }, [headings, findActiveHeading]);

  useEffect(() => {
    if (headings.length === 0) return;
    const container = document.getElementById(domId) || window;
    container.addEventListener('scroll', debouncedScrollHandler);
    debouncedScrollHandler();
    return () => {
      container.removeEventListener('scroll', debouncedScrollHandler);
      if (scrollTimeoutRef.current) {
        clearTimeout(scrollTimeoutRef.current);
      }
    };
  }, [debouncedScrollHandler, headings, domId]);

  return {
    activeHeading,
    scrollToElement,
  };
};

export default useScroll;
