import { configuration } from '../../../app/common-reducers.js';
import { stateKey } from '../../../app/state-key.js';
import { queryReducer as commerceQuery } from '../../../features/commerce/query/query-slice.js';
import { registerQuerySetQuery, updateQuerySetQuery, } from '../../../features/commerce/query-set/query-set-actions.js';
import { clearQuerySuggest, fetchQuerySuggestions, registerQuerySuggest, selectQuerySuggestion, } from '../../../features/commerce/query-suggest/query-suggest-actions.js';
import { executeSearch, prepareForSearchWithQuery, } from '../../../features/commerce/search/search-actions.js';
import { commerceSearchReducer as commerceSearch } from '../../../features/commerce/search/search-slice.js';
import { querySetReducer as querySet } from '../../../features/query-set/query-set-slice.js';
import { querySuggestReducer as querySuggest } from '../../../features/query-suggest/query-suggest-slice.js';
import { loadReducerError } from '../../../utils/errors.js';
import { randomID } from '../../../utils/utils.js';
import { validateOptions } from '../../../utils/validate-payload.js';
import { buildController } from '../../controller/headless-controller.js';
import { getSuggestions, } from '../../core/search-box/headless-core-search-box.js';
import { defaultSearchBoxOptions, searchBoxOptionsSchema, } from './headless-search-box-options.js';
/**
 * Creates a `SearchBox` controller instance.
 *
 * @param engine - The commerce headless engine.
 * @param props - The configurable `SearchBox` properties.
 * @returns A `SearchBox` controller instance.
 *
 * @group Buildable controllers
 * @category SearchBox
 */
export function buildSearchBox(engine, props = {}) {
    if (!loadSearchBoxReducers(engine)) {
        throw loadReducerError;
    }
    const controller = buildController(engine);
    const { dispatch } = engine;
    const getState = () => engine[stateKey];
    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: getState().commerceQuery.query ?? '' }));
    dispatch(registerQuerySuggest({ id }));
    const getValue = () => getState().querySet[options.id];
    const performSearch = async () => {
        const queryOptions = {
            query: getValue(),
            clearFilters: options.clearFilters,
        };
        dispatch(prepareForSearchWithQuery(queryOptions));
        dispatch(executeSearch());
    };
    return {
        ...controller,
        updateText(value) {
            dispatch(updateQuerySetQuery({ id, query: value }));
            this.showSuggestions();
        },
        clear() {
            dispatch(updateQuerySetQuery({ id, query: '' }));
            dispatch(clearQuerySuggest({ id }));
        },
        showSuggestions() {
            dispatch(fetchQuerySuggestions({ id }));
        },
        selectSuggestion(value) {
            dispatch(selectQuerySuggestion({ id, expression: value }));
            performSearch().then(() => {
                dispatch(clearQuerySuggest({ id }));
            });
        },
        submit() {
            performSearch();
            dispatch(clearQuerySuggest({ id }));
        },
        get state() {
            const querySuggest = getState().querySuggest[options.id];
            const suggestions = getSuggestions(querySuggest, options.highlightOptions);
            const isLoadingSuggestions = querySuggest
                ? querySuggest.isLoading
                : false;
            return {
                searchBoxId: id,
                value: getValue(),
                suggestions,
                isLoading: getState().commerceSearch.isLoading,
                isLoadingSuggestions,
            };
        },
    };
}
function loadSearchBoxReducers(engine) {
    engine.addReducers({
        commerceQuery,
        querySuggest,
        configuration,
        querySet,
        commerceSearch,
    });
    return true;
}
