import { __assign, __extends } from "tslib";
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
import cx from 'classnames';
import { Component, createRef } from 'react';
import Popover from '../popover';
import { I18nReceiver as Receiver } from '../i18n';
import MenuContent from './components/MenuContent';
import { union, difference, getPathValue, getPathLabel, getPathToNode, } from './path-fns';
import { getNodeKey } from './node-fns';
import { CascaderChangeAction, CascaderLoadAction, } from './types';
import SearchContent from './components/SearchContent';
import debounce from '../utils/debounce';
import TextMark from '../text-mark';
import { DisabledContext } from '../disabled';
import shallowEqual from '../utils/shallowEqual';
import { TagsTrigger } from './trigger/TagsTrigger';
import { SingleTrigger } from './trigger/SingleTrigger';
import { Forest } from './forest';
import noop from '../utils/noop';
import memorizeOne from '../utils/memorize-one';
import { simplify } from './simplify';
function isMultiple(props) {
    return props.multiple;
}
function isSingle(props) {
    return !props.multiple;
}
var FILTER_DEBOUNCE_TIME = 200;
var defaultFilter = function (keyword, path) {
    return path.some(function (node) {
        return node.label.toLowerCase().includes(keyword.toLowerCase());
    });
};
var defaultHighlight = function (keyword, path) {
    return path.map(function (node, index) {
        return (_jsxs("span", __assign({ "data-zv": 'v10.0.12' }, { children: [_jsx(TextMark, { searchWords: [keyword], textToHighlight: node.label, highlightClassName: "zent-cascader-v2--highlight", autoEscape: true }, void 0), index !== path.length - 1 && ' / '] }), getPathValue(path.slice(0, index + 1))));
    });
};
function getActiveValue(props) {
    var activeValue = [];
    if (isMultiple(props) && props.value.length > 0) {
        activeValue = props.value[0];
    }
    if (isSingle(props)) {
        activeValue = props.value;
    }
    return activeValue;
}
function getSelectedPaths(props, options) {
    var selectedPaths = isMultiple(props)
        ? props.value.map(function (x) { return options.getPathByValue(x); })
        : [options.getPathByValue(props.value)];
    return selectedPaths.filter(function (p) { return p.length !== 0; });
}
function toggleLoading(loading, val, isLoading) {
    var contains = loading.indexOf(val) !== -1;
    if (isLoading && !contains) {
        return loading.concat(val);
    }
    if (!isLoading && contains) {
        return loading.filter(function (v) { return v !== val; });
    }
    return loading;
}
function isControlled(props) {
    return ('visible' in props &&
        'onVisibleChange' in props &&
        typeof props.onVisibleChange === 'function');
}
function getVisible(props, state) {
    if (isControlled(props)) {
        return !!props.visible;
    }
    return state.visible;
}
var MenuCascader = (function (_super) {
    __extends(MenuCascader, _super);
    function MenuCascader(props) {
        var _this = _super.call(this, props) || this;
        _this.tagsTriggerRef = createRef();
        _this.getSelectionMap = memorizeOne(function (selectedPaths) {
            return _this.getSelectionMapImpl(selectedPaths);
        });
        _this.getSimplifySelectionMap = memorizeOne(function (selectedPaths, mode) {
            if (mode === void 0) { mode = 'excludeDisabled'; }
            return _this.getSelectionMapImpl(selectedPaths, mode);
        });
        _this.simplify = function (options, mode) {
            if (mode === void 0) { mode = 'excludeDisabled'; }
            return simplify(options, _this.getSelectionMapImpl(options, mode));
        };
        _this.getSearchResultList = memorizeOne(function (options, resultList) {
            return resultList.map(function (path) {
                var values = path.map(function (x) { return x.value; });
                return options.getPathByValue(values);
            });
        });
        _this.onVisibleChange = function (visible) {
            var keyword = _this.state.keyword;
            if (_this.disabled) {
                return;
            }
            _this.setVisible(visible);
            _this.setState({
                keyword: visible === false ? '' : keyword,
            });
        };
        _this.onKeywordChange = function (keyword) {
            _this.setState({ keyword: keyword }, _this.filterOptions);
        };
        _this.filterOptions = debounce(function () {
            var _a = _this.state, keyword = _a.keyword, options = _a.options;
            if (!keyword) {
                return;
            }
            var _b = _this.props, async = _b.async, asyncFilter = _b.asyncFilter, filter = _b.filter, limit = _b.limit;
            if (async) {
                _this.setState({ isSearching: true });
                asyncFilter(keyword, limit)
                    .then(function (searchList) {
                    _this.setSearchState(searchList);
                })
                    .finally(function () {
                    _this.setState({ isSearching: false });
                });
            }
            else {
                var searchList = options
                    .reducePath(function (acc, path) {
                    acc.push(path);
                    return acc;
                }, [])
                    .filter(function (path) { return filter(keyword, path); });
                _this.setSearchState(searchList);
            }
        }, FILTER_DEBOUNCE_TIME);
        _this.setSearchState = function (searchList) {
            var limit = _this.props.limit;
            var size = searchList.length;
            _this.setState({
                searchResultList: limit <= size ? searchList : searchList.slice(0, limit),
            });
        };
        _this.onMenuOptionHover = function (node) {
            _this.onMenuOptionSelect(node, noop, 'hover');
        };
        _this.onMenuOptionClick = function (node, closePopup) {
            _this.onMenuOptionSelect(node, closePopup, 'click');
        };
        _this.onMenuOptionSelect = function (node, closePopup, source) {
            var _a = _this.props, loadOptions = _a.loadOptions, multiple = _a.multiple;
            var loading = _this.state.loading;
            var needLoading = node.loadChildrenOnExpand && loadOptions;
            var selectedOptions = getPathToNode(node);
            var newValue = selectedOptions.map(function (n) { return n.value; });
            var newState = {
                activeValue: newValue,
                keyword: '',
            };
            var hasChildren = node.children && node.children.length > 0;
            var needClose = !node.loadChildrenOnExpand &&
                !hasChildren &&
                !multiple &&
                source === 'click';
            var nodeKey = getNodeKey(node);
            if (needLoading) {
                newState.loading = toggleLoading(loading, nodeKey, true);
            }
            _this.setState(newState, function () {
                if (needLoading) {
                    loadOptions(selectedOptions, {
                        action: CascaderLoadAction.LoadChildren,
                    }).finally(function () {
                        _this.setState(function (state) {
                            return {
                                loading: toggleLoading(state.loading, nodeKey, false),
                            };
                        });
                    });
                }
                if (isSingle(_this.props)) {
                    var _a = _this.props.changeOnSelect, changeOnSelect = _a === void 0 ? false : _a;
                    var needTriggerChange = needClose || (changeOnSelect && source === 'click');
                    if (needTriggerChange) {
                        _this.props.onChange(selectedOptions.map(function (it) { return it.value; }), selectedOptions, { action: CascaderChangeAction.Change });
                    }
                }
                if (needClose) {
                    closePopup();
                }
            });
        };
        _this.toggleMenuOption = function (node, checked) {
            if (isMultiple(_this.props)) {
                var onChange_1 = _this.props.onChange;
                var _a = _this.state, options = _a.options, oldSelectedPaths = _a.selectedPaths;
                var affectedPaths = options.getPaths(node, function (path) {
                    return path.every(function (node) { return !node.disabled; });
                });
                var selectedPaths_1 = checked
                    ? union(oldSelectedPaths, affectedPaths)
                    : difference(oldSelectedPaths, affectedPaths);
                selectedPaths_1 = options.sort(selectedPaths_1);
                var value_1 = selectedPaths_1.map(function (list) { return list.map(function (n) { return n.value; }); });
                _this.setState({ selectedPaths: selectedPaths_1 }, function () {
                    var _a;
                    onChange_1(value_1, selectedPaths_1, {
                        action: CascaderChangeAction.Change,
                        simplify: _this.simplify,
                    });
                    if (_this.props.searchable) {
                        (_a = _this.tagsTriggerRef.current) === null || _a === void 0 ? void 0 : _a.focus();
                    }
                });
            }
        };
        _this.onSearchOptionClick = function (path, closePopup) {
            var activeValue = path.map(function (n) { return n.value; });
            _this.setState({ activeValue: activeValue }, function () {
                _this.onMenuOptionClick(path[path.length - 1], closePopup);
            });
        };
        _this.toggleSearchOption = function (path, checked) {
            _this.toggleMenuOption(path[path.length - 1], checked);
        };
        _this.onClear = function () {
            _this.setVisible(false);
            _this.setState({
                activeValue: [],
                selectedPaths: [],
            }, function () {
                if (isSingle(_this.props)) {
                    _this.props.onChange([], [], { action: CascaderChangeAction.Clear });
                }
                else {
                    _this.props.onChange([], [], {
                        action: CascaderChangeAction.Clear,
                        simplify: _this.simplify,
                    });
                }
            });
        };
        _this.scrollLoad = function (parent) {
            var loadOptions = _this.props.loadOptions;
            var currentHasMore = parent
                ? parent.loadChildrenOnScroll
                : _this.props.loadChildrenOnScroll;
            if (currentHasMore === false) {
                return Promise.resolve();
            }
            var selectedOptions = getPathToNode(parent);
            return loadOptions(selectedOptions, {
                action: CascaderLoadAction.Scroll,
            });
        };
        _this.onRemove = function (node) {
            if (_this.disabled) {
                return;
            }
            _this.toggleMenuOption(node, false);
        };
        _this.renderPopoverContent = function (i18n) {
            var _a = _this.props, expandTrigger = _a.expandTrigger, scrollable = _a.scrollable, multiple = _a.multiple, searchable = _a.searchable, highlight = _a.highlight, loadChildrenOnScroll = _a.loadChildrenOnScroll, renderItemContent = _a.renderItemContent, getItemTooltip = _a.getItemTooltip, renderList = _a.renderList, multipleType = _a.multipleType;
            var _b = _this.state, options = _b.options, activeValue = _b.activeValue, keyword = _b.keyword, isSearching = _b.isSearching, searchResultList = _b.searchResultList, loading = _b.loading, selectedPaths = _b.selectedPaths;
            var visible = _this.getVisible();
            var selectionMap = _this.getSelectionMap(selectedPaths);
            if (searchable && visible && keyword) {
                return (_jsx(SearchContent, { i18n: i18n, multiple: multiple, isSearching: isSearching, searchList: _this.getSearchResultList(options, searchResultList), keyword: keyword, highlight: highlight, onOptionToggle: _this.toggleSearchOption, onOptionClick: _this.onSearchOptionClick, selectionMap: selectionMap }, void 0));
            }
            return (_jsx(MenuContent, { value: activeValue, options: options.getTrees(), expandTrigger: expandTrigger, i18n: i18n, scrollable: scrollable, loadChildrenOnScroll: loadChildrenOnScroll, multiple: multiple, multipleType: multipleType, onOptionClick: _this.onMenuOptionClick, onOptionHover: _this.onMenuOptionHover, scrollLoad: _this.scrollLoad, onOptionToggle: _this.toggleMenuOption, loading: loading, selectionMap: selectionMap, renderItemContent: renderItemContent, getItemTooltip: getItemTooltip, renderList: renderList }, void 0));
        };
        var options = new Forest(props.options);
        _this.state = {
            options: options,
            activeValue: getActiveValue(props),
            visible: false,
            prevProps: props,
            selectedPaths: getSelectedPaths(props, options),
            keyword: '',
            isSearching: false,
            searchResultList: [],
            loading: [],
        };
        return _this;
    }
    MenuCascader.getDerivedStateFromProps = function (props, state) {
        var prevProps = state.prevProps, options = state.options;
        var newState = {
            prevProps: props,
        };
        var newOptions = options;
        var optionsChanged = false;
        if (prevProps.options !== props.options) {
            newOptions = new Forest(props.options);
            newState.options = newOptions;
            optionsChanged = true;
        }
        if (optionsChanged ||
            prevProps.multiple !== props.multiple ||
            !shallowEqual(prevProps.value, props.value)) {
            newState.selectedPaths = getSelectedPaths(props, newOptions);
        }
        var visible = getVisible(props, state);
        if (!visible) {
            newState.activeValue = getActiveValue(props);
        }
        return newState;
    };
    Object.defineProperty(MenuCascader.prototype, "disabled", {
        get: function () {
            var _a = this.props.disabled, disabled = _a === void 0 ? this.context.value : _a;
            return disabled;
        },
        enumerable: false,
        configurable: true
    });
    MenuCascader.prototype.isControlled = function () {
        return isControlled(this.props);
    };
    MenuCascader.prototype.getVisible = function () {
        return getVisible(this.props, this.state);
    };
    MenuCascader.prototype.setVisible = function (visible) {
        if (this.isControlled()) {
            this.props.onVisibleChange(visible);
        }
        else {
            this.setState({
                visible: visible,
            });
        }
    };
    MenuCascader.prototype.getSelectionMapImpl = function (selectedPaths, mode) {
        if (mode === void 0) { mode = 'excludeDisabled'; }
        return this.state.options.reduceNodeDfs(function (map, node) {
            var key = getNodeKey(node);
            var value = node.value;
            if (node.children.length === 0) {
                var selected = selectedPaths.some(function (path) { return path[path.length - 1].value === value; });
                map.set(key, selected ? 'on' : 'off');
            }
            else {
                var children = mode === 'excludeDisabled'
                    ? node.children.filter(function (n) { return !n.disabled; })
                    : node.children;
                var childrenState = children.reduce(function (acc, n) {
                    var k = getNodeKey(n);
                    var v = map.get(k);
                    if (v === 'on') {
                        acc.on += 1;
                    }
                    else if (v === 'off') {
                        acc.off += 1;
                    }
                    return acc;
                }, { on: 0, off: 0 });
                var childrenCount = children.length;
                if (childrenState.on === childrenCount && childrenCount > 0) {
                    map.set(key, 'on');
                }
                else if (childrenState.off === childrenCount) {
                    map.set(key, 'off');
                }
                else {
                    map.set(key, 'partial');
                }
            }
            return map;
        }, new Map());
    };
    MenuCascader.prototype.render = function () {
        var _this = this;
        var _a = this.props, className = _a.className, popupClassName = _a.popupClassName, placeholder = _a.placeholder, searchable = _a.searchable, clearable = _a.clearable, renderValue = _a.renderValue, maxLine = _a.maxLine, lineHeight = _a.lineHeight;
        var _b = this.state, selectedPaths = _b.selectedPaths, keyword = _b.keyword;
        var visible = this.getVisible();
        var hasValue = selectedPaths.length > 0;
        return (_jsx(Receiver, __assign({ componentName: "Cascader" }, { children: function (i18n) {
                var _a;
                var triggerCommonProps = {
                    placeholder: placeholder,
                    disabled: _this.disabled,
                    className: className,
                    clearable: clearable,
                    visible: visible,
                    keyword: keyword,
                    searchable: searchable,
                    i18n: i18n,
                    renderValue: renderValue,
                    maxLine: maxLine,
                    lineHeight: lineHeight,
                    onClear: _this.onClear,
                    onKeywordChange: _this.onKeywordChange,
                };
                return (_jsxs(Popover, __assign({ className: cx('zent-cascader-v2__popup', popupClassName), position: Popover.Position.CascaderAutoBottomLeft, visible: visible, onVisibleChange: _this.onVisibleChange, cushion: 4 }, { children: [_jsx(Popover.Trigger.Click, __assign({ toggle: !searchable }, { children: isMultiple(_this.props) ? (_jsx(TagsTrigger, __assign({}, triggerCommonProps, { simplifyPaths: (_a = _this.props.simplifySelection) !== null && _a !== void 0 ? _a : false, selectedPaths: selectedPaths, selectionMap: _this.getSimplifySelectionMap(selectedPaths, _this.props.simplifySelectionMode), onRemove: _this.onRemove, renderTags: _this.props.renderTags, ref: _this.tagsTriggerRef }), void 0)) : (_jsx(SingleTrigger, __assign({}, triggerCommonProps, { selectedPath: hasValue ? selectedPaths[0] : [] }), void 0)) }), void 0), _jsx(Popover.Content, { children: _this.renderPopoverContent(i18n) }, void 0)] }), void 0));
            } }), void 0));
    };
    MenuCascader.defaultProps = {
        value: [],
        options: [],
        clearable: false,
        multiple: false,
        multipleType: 'checkbox',
        maxLine: null,
        lineHeight: 22,
        expandTrigger: 'click',
        scrollable: false,
        loadChildrenOnScroll: false,
        searchable: false,
        async: false,
        limit: 50,
        renderValue: getPathLabel,
        filter: defaultFilter,
        highlight: defaultHighlight,
        simplifySelectionMode: 'excludeDisabled',
    };
    MenuCascader.contextType = DisabledContext;
    return MenuCascader;
}(Component));
export { MenuCascader };
export default MenuCascader;
