"use client";

import { useEffect, useState, type ReactNode } from "react";
import { usePathname, useSearchParams } from "next/navigation";
import NavigationLoader from "./NavigationLoader";
import {
  isInternalNavigationClick,
  startNavigation,
  stopNavigation,
  subscribeNavigationLoading,
} from "@/app/lib/navigation-loading";

const LOADING_TIMEOUT_MS = 12000;

function shouldStartForHistoryUrl(nextUrl: string | URL | null | undefined) {
  if (!nextUrl) return false;
  try {
    const url = new URL(String(nextUrl), window.location.href);
    return (
      url.pathname !== window.location.pathname ||
      url.search !== window.location.search
    );
  } catch {
    return true;
  }
}

export default function NavigationLoadingProvider({
  children,
}: {
  children: ReactNode;
}) {
  const pathname = usePathname();
  const searchParams = useSearchParams();
  const [visible, setVisible] = useState(false);

  useEffect(() => subscribeNavigationLoading(setVisible), []);

  useEffect(() => {
    stopNavigation();
  }, [pathname, searchParams]);

  useEffect(() => {
    if (!visible) return;
    const timeout = window.setTimeout(() => stopNavigation(), LOADING_TIMEOUT_MS);
    return () => window.clearTimeout(timeout);
  }, [visible]);

  useEffect(() => {
    const onDocumentClick = (event: MouseEvent) => {
      const target = event.target;
      if (!(target instanceof Element)) return;
      const anchor = target.closest("a");
      if (!(anchor instanceof HTMLAnchorElement)) return;
      if (isInternalNavigationClick(event, anchor)) {
        startNavigation();
      }
    };

    const onPopState = () => startNavigation();

    const originalPushState = history.pushState.bind(history);
    const originalReplaceState = history.replaceState.bind(history);

    history.pushState = (...args) => {
      if (shouldStartForHistoryUrl(args[2])) {
        startNavigation();
      }
      return originalPushState(...args);
    };
    history.replaceState = (...args) => {
      if (shouldStartForHistoryUrl(args[2])) {
        startNavigation();
      }
      return originalReplaceState(...args);
    };

    document.addEventListener("click", onDocumentClick, true);
    window.addEventListener("popstate", onPopState);

    return () => {
      document.removeEventListener("click", onDocumentClick, true);
      window.removeEventListener("popstate", onPopState);
      history.pushState = originalPushState;
      history.replaceState = originalReplaceState;
    };
  }, []);

  return (
    <>
      {children}
      {visible ? <NavigationLoader /> : null}
    </>
  );
}
