import { ArrayValue, BooleanValue, isBoolean, NumberValue, Schema, StringValue, } from '@coveo/bueno';
import { clearRecentQueries, registerRecentQueries, } from '../../features/recent-queries/recent-queries-actions.js';
import { logClearRecentQueries, logRecentQueryClick, } from '../../features/recent-queries/recent-queries-analytics-actions.js';
import { recentQueriesReducer as recentQueries } from '../../features/recent-queries/recent-queries-slice.js';
import { executeSearch, prepareForSearchWithQuery, } from '../../features/search/search-actions.js';
import { searchReducer as search } from '../../features/search/search-slice.js';
import { loadReducerError } from '../../utils/errors.js';
import { validateInitialState, validateOptions, } from '../../utils/validate-payload.js';
import { buildController, } from '../controller/headless-controller.js';
const defaultRecentQueriesState = {
    queries: [],
};
const defaultRecentQueriesOptions = {
    maxLength: 10,
    clearFilters: true,
};
const initialStateSchema = new Schema({
    queries: new ArrayValue({ required: true }),
});
const optionsSchema = new Schema({
    maxLength: new NumberValue({ required: true, min: 1 }),
    clearFilters: new BooleanValue(),
});
function validateRecentQueriesProps(engine, props) {
    validateOptions(engine, optionsSchema, props?.options, 'buildRecentQueriesList');
    validateInitialState(engine, initialStateSchema, props?.initialState, 'buildRecentQueriesList');
}
/**
 * Creates a `RecentQueriesList` controller instance.
 *
 * @param engine - The headless engine.
 * @param props - The configuration `RecentQueriesList` properties.
 * @returns A `RecentQueriesList` controller instance.
 *
 * @group Controllers
 * @category RecentQueriesList
 * */
export function buildRecentQueriesList(engine, props) {
    if (!loadRecentQueriesListReducer(engine)) {
        throw loadReducerError;
    }
    const controller = buildController(engine);
    const { dispatch } = engine;
    const getState = () => engine.state;
    const registrationOptions = {
        ...defaultRecentQueriesOptions,
        ...props?.options,
    };
    const registrationState = {
        ...defaultRecentQueriesState,
        ...props?.initialState,
    };
    validateRecentQueriesProps(engine, {
        options: registrationOptions,
        initialState: registrationState,
    });
    const options = {
        queries: registrationState.queries,
        maxLength: registrationOptions.maxLength,
    };
    dispatch(registerRecentQueries(options));
    return {
        ...controller,
        get state() {
            const state = getState();
            return {
                ...state.recentQueries,
                analyticsEnabled: state.configuration.analytics.enabled,
            };
        },
        clear() {
            dispatch(logClearRecentQueries());
            dispatch(clearRecentQueries());
        },
        updateRecentQueries(queries) {
            const errorMessage = new ArrayValue({
                required: true,
                each: new StringValue({ required: true }),
                min: 1,
            }).validate(queries);
            if (errorMessage) {
                throw new Error(errorMessage);
            }
            dispatch(registerRecentQueries({
                queries,
                maxLength: registrationOptions.maxLength,
            }));
        },
        executeRecentQuery(index) {
            const errorMessage = new NumberValue({
                required: true,
                min: 0,
                max: this.state.queries.length,
            }).validate(index);
            if (errorMessage) {
                throw new Error(errorMessage);
            }
            const queryOptions = {
                q: this.state.queries[index],
                clearFilters: registrationOptions.clearFilters,
            };
            if (isBoolean(engine.state.query?.enableQuerySyntax)) {
                queryOptions.enableQuerySyntax = engine.state.query.enableQuerySyntax;
            }
            dispatch(prepareForSearchWithQuery(queryOptions));
            dispatch(executeSearch({
                legacy: logRecentQueryClick(),
            }));
        },
    };
}
function loadRecentQueriesListReducer(engine) {
    engine.addReducers({ search, recentQueries });
    return true;
}
