import { GeneratedAnswerAPIClient } from '../../api/generated-answer/generated-answer-client.js';
import { NoopPreprocessRequest } from '../../api/preprocess-request.js';
import { SearchAPIClient } from '../../api/search/search-api-client.js';
import { NoopPostprocessFacetSearchResponseMiddleware, NoopPostprocessQuerySuggestResponseMiddleware, NoopPostprocessSearchResponseMiddleware, } from '../../api/search/search-api-client-middleware.js';
import { interfaceLoad, logInterfaceLoad, logOmniboxFromLink, logSearchFromLink, omniboxFromLink, searchFromLink, } from '../../features/analytics/analytics-actions.js';
import { updateSearchConfiguration, } from '../../features/configuration/configuration-actions.js';
import { debugReducer as debug } from '../../features/debug/debug-slice.js';
import { pipelineReducer as pipeline } from '../../features/pipeline/pipeline-slice.js';
import { executeSearch } from '../../features/search/search-actions.js';
import { firstSearchExecutedSelector } from '../../features/search/search-selectors.js';
import { searchReducer as search } from '../../features/search/search-slice.js';
import { searchHubReducer as searchHub } from '../../features/search-hub/search-hub-slice.js';
import { buildEngine, } from '../engine.js';
import { buildLogger } from '../logger.js';
import { buildThunkExtraArguments } from '../thunk-extra-arguments.js';
import { jwtReducer } from './jwt-reducer.js';
import { getSampleSearchEngineConfiguration, searchEngineConfigurationSchema, } from './search-engine-configuration.js';
export { getSampleSearchEngineConfiguration };
const searchEngineReducers = { debug, pipeline, searchHub, search };
function getUpdateSearchConfigurationPayload(configuration) {
    const { search } = configuration;
    const { proxyBaseUrl, pipeline, searchHub, timezone, locale, authenticationProviders, } = search ?? {};
    return {
        proxyBaseUrl,
        pipeline,
        searchHub,
        timezone,
        locale,
        authenticationProviders,
    };
}
/**
 * Creates a search engine instance.
 *
 * @param options - The search engine options.
 * @returns A search engine instance.
 *
 * @group Engine
 */
export function buildSearchEngine(options) {
    const logger = buildLogger(options.loggerOptions);
    const { configuration } = options;
    validateConfiguration(configuration, logger);
    const searchAPIClient = createSearchAPIClient(configuration, logger);
    const generatedAnswerClient = createGeneratedAnswerAPIClient(logger);
    const thunkArguments = {
        ...buildThunkExtraArguments(configuration, logger),
        apiClient: searchAPIClient,
        streamingClient: generatedAnswerClient,
    };
    const augmentedOptions = {
        ...options,
        reducers: searchEngineReducers,
        crossReducer: jwtReducer(logger),
    };
    const engine = buildEngine(augmentedOptions, thunkArguments);
    const search = getUpdateSearchConfigurationPayload(configuration);
    if (search) {
        engine.dispatch(updateSearchConfiguration(search));
    }
    return {
        ...engine,
        get state() {
            return engine.state;
        },
        executeFirstSearch(analyticsEvent = logInterfaceLoad()) {
            if (firstSearchExecutedSelector(engine.state)) {
                return;
            }
            const action = executeSearch({
                legacy: analyticsEvent,
                next: interfaceLoad(),
            });
            engine.dispatch(action);
        },
        executeFirstSearchAfterStandaloneSearchBoxRedirect(analytics) {
            const { cause, metadata } = analytics;
            if (firstSearchExecutedSelector(engine.state)) {
                return;
            }
            const isOmniboxFromLink = metadata && cause === 'omniboxFromLink';
            const action = executeSearch({
                legacy: isOmniboxFromLink
                    ? logOmniboxFromLink(metadata)
                    : logSearchFromLink(),
                next: isOmniboxFromLink ? omniboxFromLink() : searchFromLink(),
            });
            engine.dispatch(action);
        },
    };
}
function validateConfiguration(configuration, logger) {
    try {
        searchEngineConfigurationSchema.validate(configuration);
    }
    catch (error) {
        logger.error(error, 'Search engine configuration error');
        throw error;
    }
}
function createSearchAPIClient(configuration, logger) {
    const { search } = configuration;
    return new SearchAPIClient({
        logger,
        preprocessRequest: configuration.preprocessRequest || NoopPreprocessRequest,
        postprocessSearchResponseMiddleware: search?.preprocessSearchResponseMiddleware ||
            NoopPostprocessSearchResponseMiddleware,
        postprocessFacetSearchResponseMiddleware: search?.preprocessFacetSearchResponseMiddleware ||
            NoopPostprocessFacetSearchResponseMiddleware,
        postprocessQuerySuggestResponseMiddleware: search?.preprocessQuerySuggestResponseMiddleware ||
            NoopPostprocessQuerySuggestResponseMiddleware,
    });
}
function createGeneratedAnswerAPIClient(logger) {
    return new GeneratedAnswerAPIClient({
        logger,
    });
}
