/**
 * @file useSmartBlocker.ts - React Router navigation blocker hook that wraps `useBlocker` to allow programmatic navigations (via {@link safeNavigate}) to bypass the block condition.
 * This is useful when you want to warn users about unsaved changes on browser-initiated navigations but still allow code-driven redirects.
 */

import { useRef } from 'react';
import {
  type NavigateOptions,
  useBlocker,
  useNavigate,
} from 'react-router-dom';

/**
 * useBlocker wrapper hook that prevents the block condition from occurring after programmatic navigations.
 *
 * @param shouldBlock Additional condition to trigger useBlocker function
 */
export function useSmartBlocker(shouldBlock: boolean) {
  // Flag toggled by safeNavigate so the blocker callback can skip programmatic navigations
  const isProgrammaticNav = useRef(false);
  const navigate = useNavigate();

  // Uses shouldBlock and checks against isProgrammaticNav
  const blocker = useBlocker(({ currentLocation, nextLocation }) => {
    return (
      shouldBlock &&
      currentLocation.pathname !== nextLocation.pathname &&
      !isProgrammaticNav.current
    );
  });

  /**
   * navigate() wrapper that prevents blocker state from changing. Should be used where programmatic navigation is necessary without triggering blocker.
   *
   * @param to New location to navigate to
   * @param options Options for modifying the navigation
   */
  const safeNavigate = (to: string, options?: NavigateOptions) => {
    isProgrammaticNav.current = true;
    navigate(to, options);
    isProgrammaticNav.current = false;
  };

  return { blocker, safeNavigate };
}
