import { createExtensionApiByAlias } from '../../../extension-registry/index.js';
import { debounce, UmbPaginationManager } from '../../../utils/index.js';
import { UmbArrayState, UmbBooleanState, UmbNumberState, UmbObjectState } from '../../../../../libs/observable-api/index.js';
import { UmbControllerBase } from '../../../../../libs/class-api/index.js';
/**
 * A manager for searching items in a picker.
 * @exports
 * @class UmbPickerSearchManager
 * @augments {UmbControllerBase}
 * @template ResultItemType
 * @template SearchRequestArgsType
 */
export class UmbPickerSearchManager extends UmbControllerBase {
    #searchable;
    #query;
    #executedQuery;
    #searching;
    #resultItems;
    #resultTotalItems;
    #pagination;
    #config;
    #searchProvider;
    constructor(host) {
        super(host);
        this.#searchable = new UmbBooleanState(false);
        this.searchable = this.#searchable.asObservable();
        this.#query = new UmbObjectState(undefined);
        this.query = this.#query.asObservable();
        this.#executedQuery = new UmbObjectState(undefined);
        this.executedQuery = this.#executedQuery.asObservable();
        this.#searching = new UmbBooleanState(false);
        this.searching = this.#searching.asObservable();
        this.#resultItems = new UmbArrayState([], (x) => x.unique);
        this.resultItems = this.#resultItems.asObservable();
        this.#resultTotalItems = new UmbNumberState(0);
        this.resultTotalItems = this.#resultTotalItems.asObservable();
        this.#pagination = new UmbPaginationManager();
        this.pagination = this.#pagination;
        this.#debouncedSearch = debounce(this.#search, 300);
        this.#pagination.setPageSize(100);
    }
    /**
     * Set the configuration for the search manager.
     * @param {UmbPickerSearchManagerConfig} config The configuration for the search manager.
     * @memberof UmbPickerSearchManager
     */
    setConfig(config) {
        this.#config = config;
        this.#initSearch();
    }
    /**
     * Get the current configuration for the search manager.
     * @returns {UmbPickerSearchManagerConfig | undefined} The current configuration for the search manager.
     * @memberof UmbPickerSearchManager
     */
    getConfig() {
        return this.#config;
    }
    /**
     * Update the current configuration for the search manager.
     * @param {Partial<UmbPickerSearchManagerConfig>} partialConfig
     * @memberof UmbPickerSearchManager
     */
    updateConfig(partialConfig) {
        const mergedConfig = { ...this.#config, ...partialConfig };
        this.setConfig(mergedConfig);
    }
    /**
     * Returns whether items can be searched.
     * @returns {boolean} Whether items can be searched.
     * @memberof UmbPickerSearchManager
     */
    getSearchable() {
        return this.#searchable.getValue();
    }
    /**
     * Sets whether items can be searched.
     * @param {boolean} value Whether items can be searched.
     * @memberof UmbPickerSearchManager
     */
    setSearchable(value) {
        this.#searchable.setValue(value);
    }
    /**
     * Search for items based on the current query.
     * @memberof UmbPickerSearchManager
     */
    search() {
        if (this.getSearchable() === false)
            throw new Error('Search is not enabled');
        const query = this.#query.getValue();
        if (!query?.query) {
            this.clear();
            return;
        }
        this.#searching.setValue(true);
        this.#debouncedSearch();
    }
    /**
     * Clear the current search query and result items.
     * @memberof UmbPickerSearchManager
     */
    clear() {
        this.#query.setValue(undefined);
        this.#executedQuery.setValue(undefined);
        this.#resultItems.setValue([]);
        this.#searching.setValue(false);
        this.#resultTotalItems.setValue(0);
        this.#pagination.clear();
    }
    /**
     * Set the search query.
     * @param {SearchRequestArgsType} query The search query.
     * @memberof UmbPickerSearchManager
     */
    setQuery(query) {
        if (!this.query) {
            this.clear();
            return;
        }
        this.#query.setValue(query);
    }
    /**
     * Get the current search query.
     * @memberof UmbPickerSearchManager
     * @returns {SearchRequestArgsType | undefined} The current search query.
     */
    getQuery() {
        return this.#query.getValue();
    }
    /**
     * Update the current search query.
     * @param {Partial<SearchRequestArgsType>} query
     * @memberof UmbPickerSearchManager
     */
    updateQuery(query) {
        this.#pagination.setCurrentPageNumber(1);
        const mergedQuery = { ...this.getQuery(), ...query };
        this.#query.setValue(mergedQuery);
    }
    async #initSearch() {
        const providerAlias = this.#config?.providerAlias;
        if (!providerAlias) {
            this.setSearchable(false);
            throw new Error('No search provider alias provided');
        }
        this.#searchProvider = await createExtensionApiByAlias(this, providerAlias);
        if (!this.#searchProvider) {
            this.setSearchable(false);
            throw new Error(`Search Provider with alias ${providerAlias} is not available`);
        }
        this.setSearchable(true);
    }
    #debouncedSearch;
    async #search() {
        if (this.getSearchable() === false)
            throw new Error('Search is not enabled');
        if (!this.#searchProvider)
            throw new Error('Search provider is not available');
        const query = this.#query.getValue();
        if (!query?.query) {
            this.clear();
            return;
        }
        const args = {
            ...query,
            // ensure that config params are always included
            ...this.#config?.queryParams,
            searchFrom: this.#config?.searchFrom,
            // TODO: Move this implementation to another place. The generic picker search manager shouldn't be aware of data types.
            dataTypeUnique: this.#config?.dataTypeUnique,
            paging: {
                skip: this.#pagination.getSkip(),
                take: this.#pagination.getPageSize(),
            },
        };
        const { data } = await this.#searchProvider.search(args);
        const items = data?.items ?? [];
        this.#resultItems.setValue(items);
        const total = data?.total ?? 0;
        this.#resultTotalItems.setValue(total);
        this.#pagination.setTotalItems(total);
        this.#executedQuery.setValue(query);
        this.#searching.setValue(false);
    }
}
