import { createContext, ReactElement, ReactNode, useContext, useEffect, useState } from 'react';
import { AppState, AppStateStatus } from 'react-native';

interface Props {
  children: ReactNode;
}

const AppStateContext = createContext<AppStateStatus | undefined>(undefined);

/**
 * @name AppStateProvider
 * @description
 * 토스 React Native 화면의 `AppState`를 관리하는 Provider예요. 이 Provider는 앱의 상태(활성, 백그라운드 등)를 관리하고, 이를 구독하는 자식 컴포넌트로 전달해요.
 * @link https://reactnative.dev/docs/appstate
 * @param {Props} children - `AppStateProvider`로 감쌀 자식 컴포넌트에요. 이 컴포넌트는`AppState`의 변화를 감지하고 반응할 수 있어요.
 * @returns {ReactElement} - `AppStateProvider` 로 감싼 React Provider 컴포넌트예요.
 * @example
 * ```tsx
 * export function App() {
 *   return (
 *     <AppStateProvider>
 *      <MyApp />
 *     </AppStateProvider>
 *   );
 * }
 * ```
 */
export function AppStateProvider({ children }: Props): ReactElement {
  const [appState, setAppState] = useState<AppStateStatus>(AppState.currentState);

  const handleAppStateChange = (status: AppStateStatus) => {
    setAppState(status);
  };

  useEffect(() => {
    const subscription = AppState.addEventListener('change', handleAppStateChange);

    return () => {
      subscription.remove();
    };
  }, []);

  return <AppStateContext.Provider value={appState}>{children}</AppStateContext.Provider>;
}

/**
 * @category Hooks
 * @name useIsAppForeground
 * @description
 * React Native 앱이 포그라운드(foreground) 상태인지 여부를 반환해요.
 *
 * @see https://reactnative.dev/docs/0.72/appstate#app-states
 * @returns {boolean} - 앱이 포그라운드 상태인지 여부를 반환해요.
 * @throws {Error} 관리 중인 AppState의 상태가 `null`일 때 에러를 발생시켜요.
 * @example
 * ```typescript
 *  const isForeground = useIsAppForeground();
 * ```
 */
export const useIsAppForeground = (): boolean => {
  const appState = useContext(AppStateContext);

  if (appState == null) {
    throw new Error('useIsAppForeground must be used within a AppStateProvider');
  }

  /**
   * iOS 에서는 'inactive' 상태도 포그라운드(foreground)로 간주해요.
   * 'inactive' 는 iOS 에서만 존재하는 상태로, 예를 들어 제어센터나 알림창이 떠 있는 상태예요.
   * @see https://reactnative.dev/docs/0.72/appstate#app-states
   */
  return appState === 'active' || appState === 'inactive';
};
