import { useDebugValue, useEffect, useState } from 'react';
import { useNavigationSafely } from './useNavigationSafely';

/**
 * @name useIsFocusedSafely
 * @category Hooks
 * @kind function
 * @link https://github.com/react-navigation/react-navigation/blob/%40react-navigation/native%406.1.18/packages/core/src/useIsFocused.tsx
 * @description
 * 현재 화면이 포커스된 상태인지 여부를 반환해요.
 *
 * `@react-navigation/native`에서 제공하던 `useIsFocused`를 안전하게 사용할 수 있도록 만든 Hook이에요.
 * 이 Hook은 `@react-navigation/native` 에서 제공하는 `useIsFocused`을 기반으로, `navigation` 이나 `root` 객체가 `null`이거나 `undefined`일 때에 에러를 throw 하지 않도록 만들었어요.
 * `@react-navigation/native` 를 쓰지 않는 환경에서 코드가 사용 되더라도 유저가 에러를 보지 않도록 만들었어요.
 *
 * @returns {boolean} - 현재 화면의 포커스 상태를 반환해요.
 * @example
 * ```typescript
 *  const isFocused = useIsFocusedSafely();
 *  console.log(isFocused); // true or false
 * ```
 */
export function useIsFocusedSafely(): boolean {
  const navigation = useNavigationSafely();
  const isNavigationFocused = () => navigation?.isFocused() ?? true;

  const [isFocused, setIsFocused] = useState(isNavigationFocused());

  const valueToReturn = isNavigationFocused();

  if (isFocused !== valueToReturn) {
    // If the value has changed since the last render, we need to update it.
    // This could happen if we missed an update from the event listeners during re-render.
    // React will process this update immediately, so the old subscription value won't be committed.
    // It is still nice to avoid returning a mismatched value though, so let's override the return value.
    // This is the same logic as in https://github.com/facebook/react/tree/master/packages/use-subscription
    setIsFocused(valueToReturn);
  }

  useEffect(() => {
    if (navigation == null) {
      return;
    }

    const unsubscribeFocus = navigation.addListener('focus', () => setIsFocused(true));

    const unsubscribeBlur = navigation.addListener('blur', () => setIsFocused(false));

    return () => {
      unsubscribeFocus();
      unsubscribeBlur();
    };
  }, [navigation]);

  useDebugValue(valueToReturn);

  return valueToReturn;
}
