import { __spreadArray, __assign } from '../../node_modules/tslib/tslib.es6.js';
import React, { forwardRef, useState, useEffect, useCallback } from 'react';
import Fuse from 'fuse.js';
import { SearchField } from '../input/SearchField.js';
import Flex from '../flex/index.js';
import { SearchableListItem } from './SearchableListItem.js';
import List from './index.js';

var fuseOptions = {
    keys: ['label', 'children.label'],
    includeMatches: true,
    threshold: 0,
    ignoreLocation: true,
    minMatchCharLength: 1,
    shouldSort: false,
};
var mapItemsFromSearchResult = function (searchResults) {
    return searchResults.map(function (_a) {
        var _b = _a.matches, matches = _b === void 0 ? [] : _b, item = _a.item;
        var parentMatch = matches.find(function (match) { return match.key === 'label'; });
        var parentHighlightIndices = parentMatch ? parentMatch.indices : [];
        var childMatches = item.children
            ? matches.filter(function (match) { return match.key === 'children.label'; })
            : [];
        if (!item.children ||
            item.children.length === 0 ||
            childMatches.length === 0) {
            return __assign(__assign({}, item), { highlightIndices: parentHighlightIndices });
        }
        var itemChildren = item.children || [];
        var children = childMatches.reduce(function (accumulator, childMatch) {
            if (childMatch.refIndex === undefined) {
                return accumulator;
            }
            var child = itemChildren[childMatch.refIndex];
            accumulator.push(__assign(__assign({}, child), { highlightIndices: childMatch.indices }));
            return accumulator;
        }, []);
        return __assign(__assign(__assign({}, item), (children ? { children: children } : {})), { highlightIndices: parentMatch ? parentMatch.indices : [] });
    });
};
var empty = function () { return null; };
var search = function (_a) {
    var query = _a.query, fuse = _a.fuse;
    fuse.options.minMatchCharLength = query.length || 1;
    return fuse.search(query);
};
var getFuseInstance = function (listItems) {
    // Not casting the instance will result in the options not being typed
    return new Fuse(listItems, fuseOptions);
};
var SearchableList = forwardRef(function (_a, ref) {
    var listItems = _a.listItems, _b = _a.NoResults, NoResults = _b === void 0 ? empty : _b, _c = _a.EmptyQueryPlaceholder, EmptyQueryPlaceholder = _c === void 0 ? empty : _c, _d = _a.listAriaLabel, listAriaLabel = _d === void 0 ? 'searchable list' : _d, _e = _a.searchFieldOptions, searchFieldOptions = _e === void 0 ? {} : _e, _f = _a.listOptions, listOptions = _f === void 0 ? { columns: 1, childrenSpacing: 'md' } : _f, listRef = _a.listRef;
    var _g = useState({
        query: '',
        listItems: listItems,
        fullListItems: __spreadArray([], listItems, true),
        fuse: getFuseInstance(listItems),
    }), searchState = _g[0], setSearchState = _g[1];
    var _h = searchFieldOptions.placeholder, placeholder = _h === void 0 ? '' : _h, _j = searchFieldOptions.autofocusOnDesktop, autofocusOnDesktop = _j === void 0 ? true : _j, autoComplete = searchFieldOptions.autoComplete;
    var _k = listOptions.columns, columns = _k === void 0 ? 1 : _k, _l = listOptions.childrenSpacing, childrenSpacing = _l === void 0 ? 'md' : _l;
    var areaId = 'searchableList';
    var query = searchState.query;
    useEffect(function () {
        setSearchState(function (currentState) {
            var fuse = getFuseInstance(listItems);
            if (currentState.query === '') {
                return {
                    listItems: listItems,
                    fullListItems: __spreadArray([], listItems, true),
                    fuse: fuse,
                    query: currentState.query,
                };
            }
            var searchResults = search({ fuse: fuse, query: currentState.query });
            var filteredListItems = mapItemsFromSearchResult(searchResults);
            return {
                listItems: filteredListItems,
                fuse: fuse,
                query: currentState.query,
                fullListItems: __spreadArray([], listItems, true),
            };
        });
    }, [listItems]);
    var setSearchQuery = useCallback(function (newQuery) {
        setSearchState(function (currentState) {
            var trimmedQuery = newQuery.trim();
            if (!trimmedQuery) {
                return __assign(__assign({}, currentState), { listItems: currentState.fullListItems, query: trimmedQuery });
            }
            var searchResults = search({
                fuse: currentState.fuse,
                query: trimmedQuery,
            });
            var filteredListItems = mapItemsFromSearchResult(searchResults);
            return __assign(__assign({}, currentState), { listItems: filteredListItems, query: trimmedQuery });
        });
    }, []);
    return (React.createElement(Flex, { gridGap: "md", direction: "column", width: "full" },
        React.createElement(SearchField, { name: "searchableListSearchFiled", searchQuery: query, setSearchQuery: setSearchQuery, ariaControls: areaId, placeholder: placeholder, autofocusOnDesktop: autofocusOnDesktop, autoComplete: autoComplete, ref: ref }),
        searchState.query.length === 0 ? React.createElement(EmptyQueryPlaceholder, null) : null,
        searchState.listItems.length > 0 ? (React.createElement(List, { ref: listRef, width: "full", height: "full", id: areaId, "aria-live": "polite", sx: {
                columns: { base: 1, md: columns },
                columnGap: 'var(--chakra-space-4xl)',
                columnRule: '1px solid var(--chakra-colors-gray-100)',
            }, "aria-label": listAriaLabel }, searchState.listItems.map(function (item, itemIndex) {
            var parentKey = "".concat(itemIndex, "-").concat(item.value);
            var children = item.children || [];
            return (React.createElement(SearchableListItem, __assign({}, item, { key: parentKey }), children.length > 0 ? (React.createElement(List, { width: "full", paddingLeft: childrenSpacing }, children.map(function (child, childIndex) {
                var childKey = "".concat(childIndex, "-").concat(child.value);
                return React.createElement(SearchableListItem, __assign({}, child, { key: childKey }));
            }))) : null));
        }))) : (React.createElement(NoResults, null))));
});

export { SearchableList };
//# sourceMappingURL=SearchableList.js.map
