/**
 * Utility functions to be used for Commerce Server Side Rendering.
 */
import { defineCart } from '../controllers/cart/headless-cart.ssr.js';
import { defineContext } from '../controllers/context/headless-context.ssr.js';
import { defineParameterManager } from '../controllers/parameter-manager/headless-core-parameter-manager.ssr.js';
import { hydratedStaticStateFactory } from '../factories/hydrated-state-factory.js';
import { hydratedRecommendationStaticStateFactory } from '../factories/recommendation-hydrated-state-factory.js';
import { fetchRecommendationStaticStateFactory } from '../factories/recommendation-static-state-factory.js';
import { fetchStaticStateFactory } from '../factories/static-state-factory.js';
import { SolutionType } from '../types/controller-constants.js';
import { validateControllerNames } from '../validation/controller-validation.js';
/**
 * Initializes a Commerce engine definition in SSR with given controllers definitions and commerce engine config.
 * @param options - The commerce engine definition
 * @returns Three utility functions to fetch the initial state of the engine in SSR, hydrate the state in CSR,
 *  and a build function that can be used for edge cases requiring more control.
 *
 * @remarks
 * You can use the {@link InferStaticState} and {@link InferHydratedState} utility types with the returned engine definitions
 * to infer the types of static and hydrated state for your controllers.
 *
 * @example
 * ```ts
 * const engineDefinition = defineCommerceEngine(engineConfig);
 * type SearchStaticState = InferStaticState<typeof engineDefinition>;
 * type SearchHydratedState = InferHydratedState<typeof engineDefinition>;
 * ```
 *
 * @group Engine
 */
export function defineCommerceEngine(options) {
    const { controllers: controllerDefinitions, ...engineOptions } = options;
    const getOptions = () => engineOptions;
    const setNavigatorContextProvider = (navigatorContextProvider) => {
        engineOptions.navigatorContextProvider = navigatorContextProvider;
    };
    const getAccessToken = () => engineOptions.configuration.accessToken;
    const setAccessToken = (accessToken) => {
        engineOptions.configuration.accessToken = accessToken;
    };
    controllerDefinitions && validateControllerNames(controllerDefinitions);
    const augmentedControllerDefinition = {
        ...controllerDefinitions,
        parameterManager: defineParameterManager(),
        context: defineContext(),
        cart: defineCart(),
    };
    const fetchStaticState = fetchStaticStateFactory(augmentedControllerDefinition, getOptions());
    const hydrateStaticState = hydratedStaticStateFactory(augmentedControllerDefinition, getOptions());
    const fetchRecommendationStaticState = fetchRecommendationStaticStateFactory(augmentedControllerDefinition, getOptions());
    const hydrateRecommendationStaticState = hydratedRecommendationStaticStateFactory(augmentedControllerDefinition, getOptions());
    const commonMethods = {
        setNavigatorContextProvider,
        getAccessToken,
        setAccessToken,
    };
    return {
        listingEngineDefinition: {
            fetchStaticState: fetchStaticState(SolutionType.listing),
            hydrateStaticState: hydrateStaticState(SolutionType.listing),
            ...commonMethods,
        },
        searchEngineDefinition: {
            fetchStaticState: fetchStaticState(SolutionType.search),
            hydrateStaticState: hydrateStaticState(SolutionType.search),
            ...commonMethods,
        },
        recommendationEngineDefinition: {
            fetchStaticState: fetchRecommendationStaticState,
            hydrateStaticState: hydrateRecommendationStaticState,
            ...commonMethods,
        },
        // TODO KIT-3738 :  The standaloneEngineDefinition should not be async since no request is sent to the API
        standaloneEngineDefinition: {
            fetchStaticState: fetchStaticState(SolutionType.standalone),
            hydrateStaticState: hydrateStaticState(SolutionType.standalone),
            ...commonMethods,
        },
    };
}
