import type {RefObject} from 'react';
import {useEffect, useState} from 'react';

const defer = (fn: () => void) => setTimeout(fn, 0);

export function useCurrentItemScroller(containerRef: RefObject<HTMLElement>) {
  const [isAutoScrollDisabled, setIsAutoScrollDisabled] = useState(false);

  useEffect(() => {
    const containerEl = containerRef.current;
    let observer: MutationObserver | undefined;

    if (containerEl) {
      const isContainerScrollable = () =>
        containerEl.scrollHeight > containerEl.offsetHeight;

      observer = new MutationObserver(mutationList => {
        for (const mutation of mutationList) {
          if (
            mutation.type === 'attributes' &&
            mutation.attributeName === 'aria-current' &&
            mutation.target.nodeType === 1 // Element nodeType
          ) {
            const element = mutation.target as HTMLElement;
            const isCurrent = element?.ariaCurrent === 'true';
            if (isCurrent && isContainerScrollable() && !isAutoScrollDisabled) {
              let offset: number;

              // If possible scroll to the middle of the container instead of to the top
              if (element.clientHeight < containerEl.clientHeight) {
                offset =
                  element.offsetTop -
                  (containerEl.clientHeight / 2 - element.clientHeight / 2);
              } else {
                // Align it to the top as per default if the element is higher than the container
                offset = element.offsetTop;
              }
              // Deferring the scroll helps prevent it from not being executed
              // in certain situations. (jumping to a time with the scrubber)
              defer(() => {
                containerEl?.scrollTo({
                  behavior: 'smooth',
                  top: offset,
                });
              });
            }
          }
        }
      });

      observer.observe(containerRef.current, {
        attributes: true,
        childList: false,
        subtree: true,
      });
    }

    const handleMouseEnter = () => {
      setIsAutoScrollDisabled(true);
    };

    const handleMouseLeave = () => {
      setIsAutoScrollDisabled(false);
    };

    containerEl?.addEventListener('mouseenter', handleMouseEnter);
    containerEl?.addEventListener('mouseleave', handleMouseLeave);

    return () => {
      observer?.disconnect();
      containerEl?.removeEventListener('mouseenter', handleMouseEnter);
      containerEl?.removeEventListener('mouseleave', handleMouseLeave);
    };
  }, [containerRef, isAutoScrollDisabled]);
}