var __assign = (this && this.__assign) || function () {
    __assign = Object.assign || function(t) {
        for (var s, i = 1, n = arguments.length; i < n; i++) {
            s = arguments[i];
            for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p))
                t[p] = s[p];
        }
        return t;
    };
    return __assign.apply(this, arguments);
};
var __rest = (this && this.__rest) || function (s, e) {
    var t = {};
    for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0)
        t[p] = s[p];
    if (s != null && typeof Object.getOwnPropertySymbols === "function")
        for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) {
            if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i]))
                t[p[i]] = s[p[i]];
        }
    return t;
};
var __spreadArray = (this && this.__spreadArray) || function (to, from, pack) {
    if (pack || arguments.length === 2) for (var i = 0, l = from.length, ar; i < l; i++) {
        if (ar || !(i in from)) {
            if (!ar) ar = Array.prototype.slice.call(from, 0, i);
            ar[i] = from[i];
        }
    }
    return to.concat(ar || Array.prototype.slice.call(from));
};
import React from 'react';
import { MenuImperative } from '../MenuImperative';
import { MultiSelect } from '../MultiSelect';
import { StyledGroupSelectOption } from './GroupSelect.styles';
var emptyArray = [];
var noop = function () { };
var defaultGetId = function (item) { return item.id; };
var defaultGetLabel = function (item) { return item.label; };
var defaultGetGroup = function (item) { return item.options; };
var defaultGetOptGroup = function (item) {
    return item.groupId;
};
function defaultOptionRenderer(item, _a) {
    var getId = _a.getId, getLabel = _a.getLabel, _b = _a.disabled, disabled = _b === void 0 ? false : _b, value = _a.value, props = __rest(_a, ["getId", "getLabel", "disabled", "value"]);
    return (React.createElement(StyledGroupSelectOption, __assign({}, props, { key: "group-select-menu-item-".concat(getId(item)), value: value || item, disabled: disabled }), getLabel(item)));
}
function defaultOptGroupRenderer(_a) {
    var id = _a.id, label = _a.label;
    return (React.createElement(MenuImperative.Group, { key: "group_".concat(id), clickable: false }, label));
}
function useGroupSelect(_a) {
    var value = _a.value, options = _a.options, groups = _a.groups, getId = _a.getId, getLabel = _a.getLabel, getGroup = _a.getGroup, onChange = _a.onChange, _onSearch = _a.onSearch;
    var _b = React.useState(''), searchValue = _b[0], setSearchValue = _b[1];
    var groupOptionsDictionary = React.useMemo(function () {
        return groups.reduce(function (acc, curr) {
            var _a;
            return (__assign(__assign({}, acc), (_a = {}, _a[getId(curr)] = getGroup(curr), _a)));
        }, {});
    }, [getGroup, getId, groups]);
    var collectOptionIds = React.useCallback(function (value) {
        return value.reduce(function (acc, cur) { return acc.add(getId(cur)); }, new Set());
    }, [getId]);
    var groupIds = React.useMemo(function () { return collectOptionIds(groups); }, [collectOptionIds, groups]);
    var isGroup = function (groupdId) { return groupIds.has(groupdId); };
    var externalOnSearch = React.useCallback(function (e) {
        if (_onSearch) {
            _onSearch(e);
        }
    }, [_onSearch]);
    var internalOnSearch = React.useCallback(function (e) {
        setSearchValue(e.target.value);
    }, []);
    var onSearch = _onSearch ? externalOnSearch : internalOnSearch;
    var selectedOptions = React.useMemo(function () { return value.filter(function (option) { return !groupIds.has(getId(option)); }); }, [getId, groupIds, value]);
    var selectedOptionIds = React.useMemo(function () { return collectOptionIds(selectedOptions); }, [collectOptionIds, selectedOptions]);
    var selectedGroups = React.useMemo(function () {
        return groups.filter(function (group) {
            return getGroup(group).length &&
                getGroup(group).every(function (option) {
                    return selectedOptionIds.has(getId(option));
                });
        });
    }, [getGroup, getId, groups, selectedOptionIds]);
    var selectedGroupIds = React.useMemo(function () { return collectOptionIds(selectedGroups); }, [collectOptionIds, selectedGroups]);
    var getGroupOptions = function (groupOptiodId) {
        var groupOptions = groupOptionsDictionary[groupOptiodId] || [];
        return groupOptions.filter(function (groupOption) { return !selectedOptionIds.has(getId(groupOption)); });
    };
    var onSelect = function (selection) {
        var newSelected = selection.reduce(function (acc, option) {
            var optionId = getId(option);
            if (isGroup(optionId)) {
                return !selectedGroupIds.has(optionId)
                    ? __spreadArray(__spreadArray([], acc, true), getGroupOptions(optionId), true) : acc;
            }
            return __spreadArray(__spreadArray([], acc, true), [option], false);
        }, []);
        setSearchValue('');
        onChange(newSelected);
    };
    var searchFilterCallback = React.useCallback(function (option) {
        return getLabel(option).toLowerCase().includes(searchValue.toLowerCase());
    }, [getLabel, searchValue]);
    var computedOptions = _onSearch
        ? options
        : options.filter(searchFilterCallback);
    var filteredGroups = _onSearch
        ? groups
        : groups.filter(searchFilterCallback);
    var computedGroups = React.useMemo(function () { return filteredGroups.filter(function (group) { return getGroup(group).length; }); }, [filteredGroups, getGroup]);
    return {
        selectedOptions: selectedOptions,
        computedOptions: __spreadArray(__spreadArray([], computedGroups, true), computedOptions, true),
        selectedOptionIds: selectedOptionIds,
        selectedGroupIds: selectedGroupIds,
        isGroup: isGroup,
        onSearch: onSearch,
        onSelect: onSelect,
    };
}
/**

 Group select allows users to select multiple options from a single item in a
 menu. Other select components are multi select, and select, tiered select.

 @since 10.19.0

 @see [Storybook](https://procore.github.io/core/latest/?path=/story/demos-groupselect--custom-search)

 @see [Design Guidelines](https://design.procore.com/group-select)

 */
export var GroupSelect = React.forwardRef(function GroupSelect(_a, ref) {
    var _b = _a.value, value = _b === void 0 ? emptyArray : _b, _c = _a.options, options = _c === void 0 ? emptyArray : _c, _d = _a.groups, groups = _d === void 0 ? emptyArray : _d, _e = _a.getId, getId = _e === void 0 ? defaultGetId : _e, _f = _a.getLabel, getLabel = _f === void 0 ? defaultGetLabel : _f, _g = _a.getGroup, getGroup = _g === void 0 ? defaultGetGroup : _g, _h = _a.getOptGroup, getOptGroup = _h === void 0 ? defaultGetOptGroup : _h, _j = _a.onChange, onChange = _j === void 0 ? noop : _j, _onSearch = _a.onSearch, optionRenderer = _a.optionRenderer, groupRenderer = _a.groupRenderer, _k = _a.optGroupRenderer, optGroupRenderer = _k === void 0 ? defaultOptGroupRenderer : _k, props = __rest(_a, ["value", "options", "groups", "getId", "getLabel", "getGroup", "getOptGroup", "onChange", "onSearch", "optionRenderer", "groupRenderer", "optGroupRenderer"]);
    var _l = useGroupSelect({
        value: value,
        options: options,
        groups: groups,
        getId: getId,
        getLabel: getLabel,
        getGroup: getGroup,
        onChange: onChange,
        onSearch: _onSearch,
    }), selectedOptions = _l.selectedOptions, selectedOptionIds = _l.selectedOptionIds, selectedGroupIds = _l.selectedGroupIds, computedOptions = _l.computedOptions, isGroup = _l.isGroup, onSelect = _l.onSelect, onSearch = _l.onSearch;
    var multiselectOptionRenderer = React.useCallback(function (option) {
        var optionId = getId(option);
        var renderer = (isGroup(optionId) ? groupRenderer : optionRenderer) ||
            defaultOptionRenderer;
        var isSelected = selectedOptionIds.has(optionId);
        var isDisabled = selectedGroupIds.has(optionId);
        return renderer(option, {
            getId: getId,
            getLabel: getLabel,
            value: option,
            selected: isSelected,
            disabled: isDisabled,
        });
    }, [
        getId,
        getLabel,
        groupRenderer,
        isGroup,
        optionRenderer,
        selectedGroupIds,
        selectedOptionIds,
    ]);
    return (React.createElement(MultiSelect, __assign({ ref: ref }, props, { value: selectedOptions, options: computedOptions, getId: getId, getLabel: getLabel, onChange: onSelect, onSearch: onSearch, getGroup: getOptGroup, optionRenderer: multiselectOptionRenderer, groupHeaderRenderer: optGroupRenderer })));
});
GroupSelect.displayName = 'GroupSelect';
//# sourceMappingURL=GroupSelect.js.map