import { getRoutePath } from './path';
import { routeMap } from '../BedrockRoute';
import { RequireContext, RouteScreen } from '../types';

/**
 * @kind function
 * @name getRouteScreens
 * @description
 * pages 폴더 내에 있는 화면들을 가져옵니다.
 *
 * @param {RequireContext} context - Router 내의 화면들에 대한 정보를 담은 객체
 * @returns {RouteScreen[]} screens - 이동할 수 있는 화면들의 목록을 반환합니다.
 *
 * @example
 * ```tsx
 * import { getRouteScreens } from 'react-native-bedrock';
 *
 * const context = require.context('../pages');
 * const screens = getRouteScreens(context);
 * ```
 */
export function getRouteScreens(context: RequireContext): RouteScreen[] {
  const screens = context.keys().map((key) => {
    const path = getRoutePath(key);

    /**
     * backward compatibility를 위해 export default 옵션도 남겨둡니다.
     * type-safe로 마이그레이션 된다면 export Route만 필요합니다.
     */
    const component = context(key)?.default ?? routeMap.get(context(key)?.Route?._path)?.component;

    if (component == null) {
      throw new Error(`${key} 의 페이지 컴포넌트가 없습니다.`);
    }

    return {
      path,
      component,
    };
  });

  return screens;
}

/**
 * @kind function
 * @name getScreenPathMapConfig
 * @description 화면들의 path 를 매핑합니다.
 *
 * @param {RouteScreen[]} routeScreens - 이동할 수 있는 화면들의 목록
 *
 * @example
 * ```tsx
 * import { registerPage, getRouteScreens, getScreenPathMapConfig, Router } from 'react-native-bedrock';
 * import { context } from '../require.context';
 *
 * function App() {
 *   return <Router context={context} prefix={'intoss://minibench'} />;
 * }
 *
 * export default registerPage(
 *   App,
 *   'minibench',
 *   getScreenPathMapConfig(getRouteScreens(context))
 * );
 * ```
 */
export function getScreenPathMapConfig(routeScreens: RouteScreen[]) {
  const screensConfig: ScreenPath = {};

  routeScreens.forEach((routeScreen) => {
    const routePath = routeScreen.path;

    if (screensConfig[routePath] != null) {
      throw new Error(`${routePath}는 이미 등록되었습니다. 중복된 path 가 있는지 확인해주세요.`);
    }

    screensConfig[routePath] = {
      path: routePath,
    };
  });

  // @see https://reactnavigation.org/docs/configuring-links/#matching-exact-paths
  // 딥링크 처리를 위한 루트 경로('/') 매핑입니다.
  // 예: intoss://{서비스명}?name=John 과 같은 URL을 처리하기 위해
  // 루트 경로를 빈 문자열로 매핑하여 쿼리 파라미터를 올바르게 추출할 수 있도록 합니다.
  screensConfig['/'] = {
    path: '',
  };

  // https://reactnavigation.org/docs/configuring-links/#handling-unmatched-routes-or-404
  screensConfig['/_404'] = {
    path: '*',
  };

  return screensConfig;
}

/**
 * @name ScreenPath
 * @description
 * 화면 경로를 나타내는 타입이에요.
 *
 * @typedef {Record<string, { path?: string }>} ScreenPath
 */
export type ScreenPath = Record<
  string,
  {
    path?: string;
  }
>;
