/**
 * Copyright (c) Meta Platforms, Inc. and affiliates.
 *
 * This source code is licensed under the MIT license found in the
 * LICENSE file in the root directory of this source tree.
 *
 * @flow
 */

export function defaultOnDefaultTransitionIndicator(): void | (() => void) {
  if (typeof navigation !== 'object') {
    // If the Navigation API is not available, then this is a noop.
    return;
  }

  let isCancelled = false;
  let pendingResolve: null | (() => void) = null;

  function handleNavigate(event: NavigateEvent) {
    if (event.canIntercept && event.info === 'react-transition') {
      event.intercept({
        handler() {
          return new Promise(resolve => (pendingResolve = resolve));
        },
        focusReset: 'manual',
        scroll: 'manual',
      });
    }
  }

  function handleNavigateComplete() {
    if (pendingResolve !== null) {
      // If this was not our navigation completing, we were probably cancelled.
      // We'll start a new one below.
      pendingResolve();
      pendingResolve = null;
    }
    if (!isCancelled) {
      // Some other navigation completed but we should still be running.
      // Start another fake one to keep the loading indicator going.
      // There needs to be an async gap to work around https://issues.chromium.org/u/1/issues/419746417.
      setTimeout(startFakeNavigation, 20);
    }
  }

  // $FlowFixMe
  navigation.addEventListener('navigate', handleNavigate);
  // $FlowFixMe
  navigation.addEventListener('navigatesuccess', handleNavigateComplete);
  // $FlowFixMe
  navigation.addEventListener('navigateerror', handleNavigateComplete);

  function startFakeNavigation() {
    if (isCancelled) {
      // We already stopped this Transition.
      return;
    }
    if (navigation.transition) {
      // There is an on-going Navigation already happening. Let's wait for it to
      // finish before starting our fake one.
      return;
    }
    // Trigger a fake navigation to the same page
    const currentEntry = navigation.currentEntry;
    if (currentEntry && currentEntry.url != null) {
      navigation.navigate(currentEntry.url, {
        state: currentEntry.getState(),
        info: 'react-transition', // indicator to routers to ignore this navigation
        history: 'replace',
      });
    }
  }

  // Delay the start a bit in case this is a fast Transition.
  setTimeout(startFakeNavigation, 100);

  return function () {
    isCancelled = true;
    // $FlowFixMe
    navigation.removeEventListener('navigate', handleNavigate);
    // $FlowFixMe
    navigation.removeEventListener('navigatesuccess', handleNavigateComplete);
    // $FlowFixMe
    navigation.removeEventListener('navigateerror', handleNavigateComplete);
    if (pendingResolve !== null) {
      pendingResolve();
      pendingResolve = null;
    }
  };
}
