import { useEffect, useRef } from 'react';
import { useRouter } from 'next/router';

const STORAGE_KEY = 'vystrikejto-scroll-positions';

function readPositions(): Record<string, number> {
  try {
    return JSON.parse(sessionStorage.getItem(STORAGE_KEY) || '{}');
  } catch {
    return {};
  }
}

function savePosition(url: string, y: number) {
  try {
    const positions = readPositions();
    positions[url] = y;
    sessionStorage.setItem(STORAGE_KEY, JSON.stringify(positions));
  } catch {
    // sessionStorage can be unavailable
  }
}

function readPosition(url: string): number | null {
  const value = readPositions()[url];
  return typeof value === 'number' ? value : null;
}

function prefersReducedMotion() {
  return window.matchMedia('(prefers-reduced-motion: reduce)').matches;
}

function scrollToY(y: number, smooth: boolean) {
  window.scrollTo({
    top: y,
    left: 0,
    behavior: smooth && !prefersReducedMotion() ? 'smooth' : 'auto',
  });
}

const ScrollRestoration: React.FC = () => {
  const router = useRouter();
  const pathRef = useRef(router.asPath);
  const restoreRef = useRef(false);
  const restoreTimersRef = useRef<number[]>([]);

  pathRef.current = router.asPath;

  useEffect(() => {
    if (typeof window === 'undefined') return;

    if ('scrollRestoration' in window.history) {
      window.history.scrollRestoration = 'manual';
    }

    const clearRestoreTimers = () => {
      restoreTimersRef.current.forEach((id) => window.clearTimeout(id));
      restoreTimersRef.current = [];
    };

    const restore = (url: string) => {
      const y = readPosition(url);
      if (y == null || y < 8) {
        scrollToY(0, false);
        return;
      }

      clearRestoreTimers();

      restoreTimersRef.current.push(
        window.setTimeout(() => {
          scrollToY(y, true);
        }, 80)
      );

      restoreTimersRef.current.push(
        window.setTimeout(() => {
          if (Math.abs(window.scrollY - y) > 80) {
            scrollToY(y, true);
          }
        }, 450)
      );
    };

    const onPopState = () => {
      restoreRef.current = true;
    };

    const onRouteChangeStart = () => {
      savePosition(pathRef.current, window.scrollY);
    };

    const onRouteChangeComplete = (url: string) => {
      if (restoreRef.current) {
        restoreRef.current = false;
        restore(url);
        return;
      }

      scrollToY(0, false);
    };

    const onPageHide = () => {
      savePosition(pathRef.current, window.scrollY);
    };

    window.addEventListener('popstate', onPopState);
    window.addEventListener('pagehide', onPageHide);
    router.events.on('routeChangeStart', onRouteChangeStart);
    router.events.on('routeChangeComplete', onRouteChangeComplete);

    return () => {
      clearRestoreTimers();
      window.removeEventListener('popstate', onPopState);
      window.removeEventListener('pagehide', onPageHide);
      router.events.off('routeChangeStart', onRouteChangeStart);
      router.events.off('routeChangeComplete', onRouteChangeComplete);
    };
  }, [router.events]);

  return null;
};

export default ScrollRestoration;
