import type { History, Blocker, Transition } from 'history';
import { useEffect } from 'react';
// see: https://gist.github.com/rmorse/426ffcc579922a82749934826fa9f743
import { Navigator as BaseNavigator } from 'react-router-dom';

interface Navigator extends BaseNavigator {
  block?: History['block'];
}

export interface FormBasedPreventNavigationProps {
  promptMessage?: string;
  preventNavigate: boolean;
  navigator: Navigator;
}
/** Only use this if the project uses `<BrowserRouter/>` or any router that does not support the new
 * [react-router Data API](https://reactrouter.com/en/main/routers/picking-a-router#using-v64-data-apis)
 *
 * Legacy function to prevent the user from navigating away from a form if there are any changes.
 */
export default function LegacyFormBasedPreventNavigation({
  promptMessage = 'Changes you made may not be saved.',
  preventNavigate,
  navigator,
}: FormBasedPreventNavigationProps) {
  useEffect(() => {
    if (!preventNavigate) {
      return;
    }
    let unblock = () => {};
    const push = navigator.push;

    // TODO: https://reactrouter.com/docs/en/v6/upgrading/v5#prompt-is-not-currently-supported
    // this is a workaround until we get native support for prompt on navigate
    if (navigator.block) {
      const blocker: Blocker = (tx) => {
        if (window.confirm(promptMessage)) {
          tx.retry();
        }
      };
      unblock = navigator.block((tx: Transition) => {
        const autoUnblockingTx = {
          ...tx,
          retry() {
            // Automatically unblock the transition so it can play all the way
            // through before retrying it. TODO: Figure out how to re-enable
            // this block if the transition is cancelled for some reason.
            unblock();
            tx.retry();
          },
        };

        blocker(autoUnblockingTx);
      });
    } else {
      //https://gist.github.com/MarksCode/64e438c82b0b2a1161e01c88ca0d0355
      navigator.push = (...args: Parameters<typeof push>) => {
        if (window.confirm(promptMessage)) {
          push(...args);
        }
      };
    }

    window.addEventListener('beforeunload', beforeUnload);
    return () => {
      unblock();
      navigator.push = push;
      window.removeEventListener('beforeunload', beforeUnload);
    };

    function beforeUnload(e: BeforeUnloadEvent) {
      e.preventDefault();
      e.returnValue = promptMessage;
    }
  }, [preventNavigate, promptMessage, navigator]);

  return null;
}
