import { buildCommerceEngine, } from '../../../app/commerce-engine/commerce-engine.js';
import { buildLogger } from '../../../app/logger.js';
import { stateKey } from '../../../app/state-key.js';
import { createWaitForActionMiddleware, createWaitForActionMiddlewareForRecommendation, } from '../../../utils/utils.js';
import { buildControllerDefinitions } from '../controller-utils.js';
import { SolutionType } from '../types/controller-constants.js';
import { wireControllerParams } from '../utils/controller-wiring.js';
import { extendEngineConfiguration } from '../utils/engine-wiring.js';
function isListingFetchCompletedAction(action) {
    return /^commerce\/productListing\/fetch\/(fulfilled|rejected)$/.test(action.type);
}
function isSearchCompletedAction(action) {
    return /^commerce\/search\/executeSearch\/(fulfilled|rejected)$/.test(action.type);
}
function isRecommendationCompletedAction(action) {
    return /^commerce\/recommendations\/fetch\/(fulfilled|rejected)$/.test(action.type);
}
function noSearchActionRequired(_action) {
    return true;
}
function buildSSRCommerceEngine(solutionType, options, recommendationCount) {
    let actionCompletionMiddleware;
    const middlewares = [];
    const memo = new Set();
    switch (solutionType) {
        case SolutionType.listing:
            actionCompletionMiddleware = createWaitForActionMiddleware(isListingFetchCompletedAction);
            middlewares.push(actionCompletionMiddleware);
            break;
        case SolutionType.search:
            actionCompletionMiddleware = createWaitForActionMiddleware(isSearchCompletedAction);
            middlewares.push(actionCompletionMiddleware);
            break;
        case SolutionType.recommendation:
            middlewares.push(...Array.from({ length: recommendationCount }, () => createWaitForActionMiddlewareForRecommendation(isRecommendationCompletedAction, memo)));
            break;
        case SolutionType.standalone:
            actionCompletionMiddleware = createWaitForActionMiddleware(noSearchActionRequired);
            break;
        default:
            throw new Error('Unsupported solution type', solutionType);
    }
    const commerceEngine = buildCommerceEngine({
        ...options,
        middlewares: [
            ...(options.middlewares ?? []),
            ...middlewares.map(({ middleware }) => middleware),
        ],
    });
    return {
        ...commerceEngine,
        get [stateKey]() {
            return commerceEngine[stateKey];
        },
        waitForRequestCompletedAction() {
            return [...middlewares.map(({ promise }) => promise)];
        },
    };
}
function fetchActiveRecommendationControllers(controllerProps, solutionType) {
    return solutionType === SolutionType.recommendation
        ? Object.values(controllerProps).filter((controller) => controller &&
            typeof controller === 'object' &&
            'enabled' in controller &&
            controller.enabled).length
        : 0;
}
export const buildFactory = (controllerDefinitions, options) => (solutionType) => async (...[buildOptions]) => {
    const controllerProps = wireControllerParams(solutionType, controllerDefinitions, buildOptions); // TODO: KIT-4754: remove non-null assertion operator
    const logger = buildLogger(options.loggerOptions);
    if (!options.navigatorContextProvider) {
        logger.warn('[WARNING] Missing navigator context in server-side code. Make sure to set it with `setNavigatorContextProvider` before calling fetchStaticState()');
    }
    const enabledRecommendationControllers = fetchActiveRecommendationControllers(controllerProps, solutionType);
    const engineOptions = {
        ...options,
        configuration: extendEngineConfiguration(options.configuration, buildOptions), // TODO: KIT-4754: remove non-null assertion operator
    };
    const engine = buildSSRCommerceEngine(solutionType, engineOptions, enabledRecommendationControllers);
    const controllers = buildControllerDefinitions({
        definitionsMap: (controllerDefinitions ?? {}),
        engine,
        solutionType,
        propsMap: controllerProps,
    });
    return {
        engine,
        controllers,
    };
};
