import { configuration } from '../../../app/common-reducers.js';
import { logSearchboxSubmit } from '../../../features/query/query-analytics-actions.js';
import { queryReducer as query } from '../../../features/query/query-slice.js';
import { registerQuerySetQuery, updateQuerySetQuery, } from '../../../features/query-set/query-set-actions.js';
import { querySetReducer as querySet } from '../../../features/query-set/query-set-slice.js';
import { clearQuerySuggest, registerQuerySuggest, selectQuerySuggestion, } from '../../../features/query-suggest/query-suggest-actions.js';
import { logQuerySuggestionClick, omniboxAnalytics, } from '../../../features/query-suggest/query-suggest-analytics-actions.js';
import { querySuggestReducer as querySuggest } from '../../../features/query-suggest/query-suggest-slice.js';
import { prepareForSearchWithQuery, } from '../../../features/search/search-actions.js';
import { searchReducer as search } from '../../../features/search/search-slice.js';
import { loadReducerError } from '../../../utils/errors.js';
import { getHighlightedSuggestion, } from '../../../utils/highlight.js';
import { randomID } from '../../../utils/utils.js';
import { validateOptions } from '../../../utils/validate-payload.js';
import { buildController, } from '../../controller/headless-controller.js';
import { defaultSearchBoxOptions, searchBoxOptionsSchema, } from './headless-core-search-box-options.js';
/**
 * @internal
 * Creates a `SearchBox` controller instance.
 *
 * @param engine - The headless engine instance.
 * @returns A `SearchBox` controller instance.
 */
export function buildCoreSearchBox(engine, props) {
    if (!loadSearchBoxReducers(engine)) {
        throw loadReducerError;
    }
    const controller = buildController(engine);
    const { dispatch } = engine;
    const getState = () => engine.state;
    const id = props.options?.id || randomID('search_box');
    const options = {
        id,
        highlightOptions: { ...props.options?.highlightOptions },
        ...defaultSearchBoxOptions,
        ...props.options,
    };
    validateOptions(engine, searchBoxOptionsSchema, options, 'buildSearchBox');
    dispatch(registerQuerySetQuery({ id, query: engine.state.query.q }));
    if (options.numberOfSuggestions) {
        dispatch(registerQuerySuggest({
            id,
            count: options.numberOfSuggestions,
        }));
    }
    const getValue = () => engine.state.querySet[options.id];
    const performSearch = async (analytics) => {
        const { enableQuerySyntax, clearFilters } = options;
        dispatch(prepareForSearchWithQuery({
            q: getValue(),
            enableQuerySyntax,
            clearFilters,
        }));
        if (props.isNextAnalyticsReady) {
            dispatch(props.executeSearchActionCreator(analytics));
        }
        else {
            dispatch(props.executeSearchActionCreator(analytics.legacy));
        }
    };
    return {
        ...controller,
        updateText(value) {
            dispatch(updateQuerySetQuery({ id, query: value }));
            this.showSuggestions();
        },
        clear() {
            dispatch(updateQuerySetQuery({ id, query: '' }));
            dispatch(clearQuerySuggest({ id }));
        },
        showSuggestions() {
            if (options.numberOfSuggestions) {
                dispatch(props.fetchQuerySuggestionsActionCreator({ id }));
            }
        },
        selectSuggestion(value) {
            dispatch(selectQuerySuggestion({ id, expression: value }));
            performSearch({
                legacy: logQuerySuggestionClick({ id, suggestion: value }),
                next: omniboxAnalytics(),
            }).then(() => {
                dispatch(clearQuerySuggest({ id }));
            });
        },
        submit(legacyAnalytics = logSearchboxSubmit(), nextAnalytics) {
            performSearch({ legacy: legacyAnalytics, next: nextAnalytics });
            dispatch(clearQuerySuggest({ id }));
        },
        get state() {
            const state = getState();
            const querySuggest = state.querySuggest[options.id];
            const suggestions = getSuggestions(querySuggest, options.highlightOptions);
            const isLoadingSuggestions = querySuggest
                ? querySuggest.isLoading
                : false;
            return {
                searchBoxId: id,
                value: getValue(),
                suggestions,
                isLoading: state.search.isLoading,
                isLoadingSuggestions,
            };
        },
    };
}
export function getSuggestions(state, highlightOptions) {
    if (!state) {
        return [];
    }
    return state.completions.map((completion) => ({
        highlightedValue: getHighlightedSuggestion(completion.highlighted, highlightOptions),
        rawValue: completion.expression,
    }));
}
function loadSearchBoxReducers(engine) {
    engine.addReducers({ query, querySuggest, configuration, querySet, search });
    return true;
}
