function _array_like_to_array(arr, len) {
    if (len == null || len > arr.length) len = arr.length;
    for(var i = 0, arr2 = new Array(len); i < len; i++)arr2[i] = arr[i];
    return arr2;
}
function _array_without_holes(arr) {
    if (Array.isArray(arr)) return _array_like_to_array(arr);
}
function _iterable_to_array(iter) {
    if (typeof Symbol !== "undefined" && iter[Symbol.iterator] != null || iter["@@iterator"] != null) return Array.from(iter);
}
function _non_iterable_spread() {
    throw new TypeError("Invalid attempt to spread non-iterable instance.\\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.");
}
function _to_consumable_array(arr) {
    return _array_without_holes(arr) || _iterable_to_array(arr) || _unsupported_iterable_to_array(arr) || _non_iterable_spread();
}
function _unsupported_iterable_to_array(o, minLen) {
    if (!o) return;
    if (typeof o === "string") return _array_like_to_array(o, minLen);
    var n = Object.prototype.toString.call(o).slice(8, -1);
    if (n === "Object" && o.constructor) n = o.constructor.name;
    if (n === "Map" || n === "Set") return Array.from(n);
    if (n === "Arguments" || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)) return _array_like_to_array(o, minLen);
}
import { keyExists } from "../reducers/treePathReducer";
var JUMP_SIZE = 10;
export var keys = {
    Enter: 'Enter',
    Space: 'Space',
    Tab: 'Tab',
    Escape: 'Escape',
    Backspace: 'Backspace',
    ArrowLeft: 'ArrowLeft',
    ArrowRight: 'ArrowRight',
    ArrowUp: 'ArrowUp',
    ArrowDown: 'ArrowDown',
    Home: 'Home',
    End: 'End',
    PageUp: 'PageUp',
    PageDown: 'PageDown'
};
export var getItemByFocused = function getItemByFocused(focusedPath, focusedToValueMap) {
    var focusedPathAsString = focusedPath.reduce(function(acc, n) {
        return "".concat(acc, "/").concat(n);
    }, '').replace(/^(\/)/, '');
    return focusedToValueMap.get(focusedPathAsString);
};
// #TODO: подумать над идеей выноса логики фокуса непосредственно в focusedPathReducer.
export var useKeyNavigation = function useKeyNavigation(param) {
    var focusedPath = param.focusedPath, dispatchFocusedPath = param.dispatchFocusedPath, path = param.path, dispatchPath = param.dispatchPath, pathMap = param.pathMap, focusedToValueMap = param.focusedToValueMap, handleListToggle = param.handleListToggle, handlePressDown = param.handlePressDown, treePath = param.treePath, dispatchTreePath = param.dispatchTreePath, treeView = param.treeView, valueToPathMap = param.valueToPathMap, items = param.items, readOnly = param.readOnly;
    if (treeView) {
        return keyboardNavigationTree({
            focusedPath: focusedPath,
            dispatchFocusedPath: dispatchFocusedPath,
            path: path,
            dispatchPath: dispatchPath,
            pathMap: pathMap,
            focusedToValueMap: focusedToValueMap,
            handleListToggle: handleListToggle,
            handlePressDown: handlePressDown,
            treePath: treePath,
            dispatchTreePath: dispatchTreePath,
            treeView: treeView,
            valueToPathMap: valueToPathMap,
            items: items,
            readOnly: readOnly
        });
    }
    return keyboardNavigationDefault({
        focusedPath: focusedPath,
        dispatchFocusedPath: dispatchFocusedPath,
        path: path,
        dispatchPath: dispatchPath,
        pathMap: pathMap,
        focusedToValueMap: focusedToValueMap,
        handleListToggle: handleListToggle,
        handlePressDown: handlePressDown,
        treePath: treePath,
        dispatchTreePath: dispatchTreePath,
        treeView: treeView,
        valueToPathMap: valueToPathMap,
        items: items,
        readOnly: readOnly
    });
};
var keyboardNavigationDefault = function keyboardNavigationDefault(param) {
    var focusedPath = param.focusedPath, dispatchFocusedPath = param.dispatchFocusedPath, path = param.path, dispatchPath = param.dispatchPath, pathMap = param.pathMap, focusedToValueMap = param.focusedToValueMap, handleListToggle = param.handleListToggle, handlePressDown = param.handlePressDown, readOnly = param.readOnly;
    var currentIndex = (focusedPath === null || focusedPath === void 0 ? void 0 : focusedPath[focusedPath.length - 1]) || 0;
    var currentLength = pathMap.get(path === null || path === void 0 ? void 0 : path[focusedPath.length - 1]) || 0;
    var onKeyDown = function onKeyDown(event) {
        if (readOnly) {
            return;
        }
        switch(event.code){
            case keys.ArrowUp:
                {
                    if (focusedPath.length) {
                        if (currentIndex > 0) {
                            if (path.length > focusedPath.length) {
                                dispatchPath({
                                    type: 'removed_last_level'
                                });
                            }
                            dispatchFocusedPath({
                                type: 'change_last_focus',
                                value: currentIndex - 1
                            });
                        }
                    } else {
                        dispatchPath({
                            type: 'opened_first_level'
                        });
                        dispatchFocusedPath({
                            type: 'set_initial_focus'
                        });
                        handleListToggle(true);
                    }
                    break;
                }
            case keys.ArrowDown:
                {
                    if (focusedPath.length) {
                        if (currentIndex + 1 < currentLength) {
                            if (path.length > focusedPath.length) {
                                dispatchPath({
                                    type: 'removed_last_level'
                                });
                            }
                            dispatchFocusedPath({
                                type: 'change_last_focus',
                                value: currentIndex + 1
                            });
                        }
                    } else {
                        dispatchPath({
                            type: 'opened_first_level'
                        });
                        dispatchFocusedPath({
                            type: 'set_initial_focus'
                        });
                        handleListToggle(true);
                    }
                    break;
                }
            case keys.ArrowLeft:
                {
                    if (path[0]) {
                        if (focusedPath.length) {
                            if (path.length > focusedPath.length) {
                                dispatchPath({
                                    type: 'removed_last_level'
                                });
                            } else {
                                dispatchFocusedPath({
                                    type: 'return_prev_focus'
                                });
                            }
                        }
                        if (path.length === 1) {
                            handleListToggle(false);
                        }
                    }
                    break;
                }
            case keys.ArrowRight:
                {
                    if (path[0]) {
                        if (!focusedPath.length) {
                            break;
                        }
                        var currentItem = getItemByFocused(focusedPath, focusedToValueMap);
                        if ((currentItem === null || currentItem === void 0 ? void 0 : currentItem.disabled) || (currentItem === null || currentItem === void 0 ? void 0 : currentItem.isDisabled)) {
                            break;
                        }
                        if (currentItem === null || currentItem === void 0 ? void 0 : currentItem.items) {
                            if (path.length > focusedPath.length) {
                                dispatchFocusedPath({
                                    type: 'add_focus',
                                    value: 0
                                });
                            } else {
                                dispatchPath({
                                    type: 'added_next_level',
                                    value: currentItem.value.toString()
                                });
                            }
                        }
                    }
                    break;
                }
            case keys.Space:
                {
                    event.preventDefault();
                    var currentItem1 = getItemByFocused(focusedPath, focusedToValueMap);
                    if (!path[0]) {
                        dispatchPath({
                            type: 'opened_first_level'
                        });
                        dispatchFocusedPath({
                            type: 'set_initial_focus'
                        });
                        break;
                    }
                    if (!currentItem1 || (currentItem1 === null || currentItem1 === void 0 ? void 0 : currentItem1.disabled) || (currentItem1 === null || currentItem1 === void 0 ? void 0 : currentItem1.isDisabled)) {
                        break;
                    }
                    handlePressDown(currentItem1);
                    break;
                }
            case keys.Enter:
                {
                    event.preventDefault();
                    var currentItem2 = getItemByFocused(focusedPath, focusedToValueMap);
                    if ((currentItem2 === null || currentItem2 === void 0 ? void 0 : currentItem2.disabled) || (currentItem2 === null || currentItem2 === void 0 ? void 0 : currentItem2.isDisabled)) {
                        break;
                    }
                    if (!path[0]) {
                        dispatchPath({
                            type: 'opened_first_level'
                        });
                        dispatchFocusedPath({
                            type: 'set_initial_focus'
                        });
                        break;
                    }
                    if (currentItem2 === null || currentItem2 === void 0 ? void 0 : currentItem2.items) {
                        if (path.length > focusedPath.length) {
                            dispatchFocusedPath({
                                type: 'add_focus',
                                value: 0
                            });
                        } else {
                            dispatchPath({
                                type: 'added_next_level',
                                value: currentItem2.value.toString()
                            });
                        }
                        break;
                    }
                    handlePressDown(currentItem2);
                    break;
                }
            case keys.Tab:
            case keys.Escape:
                {
                    if (path[0]) {
                        handleListToggle(false);
                    }
                    break;
                }
            case keys.Home:
                {
                    if (path[0]) {
                        if (path.length > focusedPath.length) {
                            dispatchPath({
                                type: 'removed_last_level'
                            });
                        }
                        dispatchFocusedPath({
                            type: 'change_last_focus',
                            value: 0
                        });
                    } else {
                        dispatchPath({
                            type: 'opened_first_level'
                        });
                        dispatchFocusedPath({
                            type: 'set_initial_focus'
                        });
                        handleListToggle(true);
                    }
                    break;
                }
            case keys.End:
                {
                    if (path[0]) {
                        if (path.length > focusedPath.length) {
                            dispatchPath({
                                type: 'removed_last_level'
                            });
                        }
                        dispatchFocusedPath({
                            type: 'change_last_focus',
                            value: currentLength - 1
                        });
                    } else {
                        dispatchPath({
                            type: 'opened_first_level'
                        });
                        dispatchFocusedPath({
                            type: 'change_last_focus',
                            value: (pathMap.get('root') || 0) - 1
                        });
                        handleListToggle(true);
                    }
                    break;
                }
            case keys.PageUp:
                {
                    if (!path[0]) {
                        break;
                    }
                    if (path.length > focusedPath.length) {
                        dispatchPath({
                            type: 'removed_last_level'
                        });
                    }
                    if (currentIndex <= JUMP_SIZE) {
                        dispatchFocusedPath({
                            type: 'change_last_focus',
                            value: 0
                        });
                    } else {
                        dispatchFocusedPath({
                            type: 'change_last_focus',
                            value: currentIndex - JUMP_SIZE
                        });
                    }
                    break;
                }
            case keys.PageDown:
                {
                    if (!path[0]) {
                        break;
                    }
                    if (path.length > focusedPath.length) {
                        dispatchPath({
                            type: 'removed_last_level'
                        });
                    }
                    if (currentLength - currentIndex <= JUMP_SIZE) {
                        dispatchFocusedPath({
                            type: 'change_last_focus',
                            value: currentLength - 1
                        });
                    } else {
                        dispatchFocusedPath({
                            type: 'change_last_focus',
                            value: currentIndex + JUMP_SIZE
                        });
                    }
                    break;
                }
            default:
                {
                    break;
                }
        }
    };
    return {
        onKeyDown: onKeyDown
    };
};
var keyboardNavigationTree = function keyboardNavigationTree(param) {
    var focusedPath = param.focusedPath, dispatchFocusedPath = param.dispatchFocusedPath, path = param.path, dispatchPath = param.dispatchPath, pathMap = param.pathMap, focusedToValueMap = param.focusedToValueMap, handleListToggle = param.handleListToggle, handlePressDown = param.handlePressDown, treePath = param.treePath, dispatchTreePath = param.dispatchTreePath, valueToPathMap = param.valueToPathMap, items = param.items, readOnly = param.readOnly;
    var _currentItem_parent_items, _currentItem_parent;
    var currentItem = getItemByFocused(focusedPath, focusedToValueMap);
    var currentIndex = (focusedPath === null || focusedPath === void 0 ? void 0 : focusedPath[focusedPath.length - 1]) || 0;
    var currentLength = (currentItem === null || currentItem === void 0 ? void 0 : (_currentItem_parent = currentItem.parent) === null || _currentItem_parent === void 0 ? void 0 : (_currentItem_parent_items = _currentItem_parent.items) === null || _currentItem_parent_items === void 0 ? void 0 : _currentItem_parent_items.length) || pathMap.get('root') || 0;
    var isValidFocus = function isValidFocus(focusCandidate) {
        if (!Array.isArray(items) || !Array.isArray(focusCandidate)) return false;
        var currentLevel = items;
        var _iteratorNormalCompletion = true, _didIteratorError = false, _iteratorError = undefined;
        try {
            for(var _iterator = focusCandidate[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true){
                var index = _step.value;
                if (!Array.isArray(currentLevel) || index >= currentLevel.length) {
                    return false;
                }
                var node = currentLevel[index];
                currentLevel = node.items || [];
            }
        } catch (err) {
            _didIteratorError = true;
            _iteratorError = err;
        } finally{
            try {
                if (!_iteratorNormalCompletion && _iterator.return != null) {
                    _iterator.return();
                }
            } finally{
                if (_didIteratorError) {
                    throw _iteratorError;
                }
            }
        }
        return true;
    };
    var onKeyDown = function onKeyDown(event) {
        if (readOnly) {
            return;
        }
        switch(event.code){
            case keys.ArrowUp:
                {
                    /**
                 * Если список открыт и фокус уже установлен на каком-либо элементе.
                 * */ if (focusedPath.length) {
                        /**
                     * Если это не первый элемент, то нужно вначале найти элемент для фокуса.
                     * Т.к. если верхний элемент раскрыт, то и перемещаться нужно не на него,
                     * а на его самый нижний дочерний элемент.
                     * */ if (currentIndex > 0) {
                            var nextFocus = _to_consumable_array(focusedPath.slice(0, -1)).concat([
                                currentIndex - 1
                            ]);
                            while(nextFocus){
                                var focusedPathAsString = nextFocus.reduce(function(acc, n) {
                                    return "".concat(acc, "/").concat(n);
                                }, '').replace(/^(\/)/, '');
                                var item = focusedToValueMap.get(focusedPathAsString);
                                var isLevelOpened = keyExists(treePath, valueToPathMap.get(item.value.toString()) || []);
                                if (isLevelOpened) {
                                    var _item_items;
                                    nextFocus = _to_consumable_array(nextFocus).concat([
                                        ((item === null || item === void 0 ? void 0 : (_item_items = item.items) === null || _item_items === void 0 ? void 0 : _item_items.length) || 0) - 1
                                    ]);
                                } else {
                                    break;
                                }
                            }
                            dispatchFocusedPath({
                                type: 'set_focus',
                                value: nextFocus
                            });
                        } else {
                            /**
                         * Если элемент первый, то нужно лишь подняться к его родителю.
                         * */ dispatchFocusedPath({
                                type: 'return_prev_focus'
                            });
                        }
                    } else {
                        /**
                     * Если список закрыт, то нужно его открыть и установить фокус на первый элемент.
                     * */ dispatchPath({
                            type: 'opened_first_level'
                        });
                        dispatchFocusedPath({
                            type: 'set_initial_focus'
                        });
                        handleListToggle(true);
                    }
                    break;
                }
            case keys.ArrowDown:
                {
                    /**
                 * Если список открыт и фокус уже установлен на каком-либо элементе.
                 * */ if (focusedPath.length) {
                        /**
                     * Заходим сюда если у элемента есть другие вложенные элементы.
                     * */ if ((currentItem === null || currentItem === void 0 ? void 0 : currentItem.items) && (currentItem === null || currentItem === void 0 ? void 0 : currentItem.items.length)) {
                            var isCurrentLevelOpened = keyExists(treePath, valueToPathMap.get(currentItem.value.toString()) || []);
                            /**
                         * Если у этого элемента открыт его дочерний список,
                         * то устанавливаем фокус на первый элемент из этого списка
                         * и сразу же выходим из обработчика события.
                         * */ if (isCurrentLevelOpened) {
                                dispatchFocusedPath({
                                    type: 'add_focus',
                                    value: 0
                                });
                                break;
                            }
                        }
                        /**
                     * Если мы еще не достигли конца списка, то движемся к следующему элементу.
                     * */ if (currentIndex + 1 < currentLength) {
                            dispatchFocusedPath({
                                type: 'change_last_focus',
                                value: currentIndex + 1
                            });
                        } else {
                            /**
                         * Если же достигли последнего элемента на текущем уровне, то нужно определить,
                         * на какой из элементов ниже мы перейдем.
                         * Переход фокуса отсюда может быть только на уровни выше, при чем сразу на несколько.
                         * */ var focusCandidate = _to_consumable_array(focusedPath);
                            var nextFocus1 = null;
                            while(focusCandidate.length > 1){
                                focusCandidate = _to_consumable_array(focusCandidate.slice(0, -2)).concat([
                                    (focusCandidate.at(-2) || 0) + 1
                                ]);
                                if (isValidFocus(focusCandidate)) {
                                    nextFocus1 = focusCandidate;
                                    break;
                                }
                            }
                            if (nextFocus1) {
                                dispatchFocusedPath({
                                    type: 'set_focus',
                                    value: nextFocus1
                                });
                            } else {
                                break;
                            }
                        }
                    } else {
                        /**
                     * Если список закрыт, то нужно его открыть и установить фокус на первый элемент.
                     * */ dispatchPath({
                            type: 'opened_first_level'
                        });
                        dispatchFocusedPath({
                            type: 'set_initial_focus'
                        });
                        handleListToggle(true);
                    }
                    break;
                }
            case keys.ArrowLeft:
                {
                    if (path[0]) {
                        if (focusedPath.length) {
                            dispatchTreePath({
                                type: 'close_level',
                                value: valueToPathMap.get((currentItem === null || currentItem === void 0 ? void 0 : currentItem.value.toString()) || '') || []
                            });
                        }
                    }
                    break;
                }
            case keys.ArrowRight:
                {
                    if (path[0]) {
                        if (!focusedPath.length || (currentItem === null || currentItem === void 0 ? void 0 : currentItem.disabled) || (currentItem === null || currentItem === void 0 ? void 0 : currentItem.isDisabled) || !(currentItem === null || currentItem === void 0 ? void 0 : currentItem.items)) {
                            break;
                        }
                        dispatchTreePath({
                            type: 'open_level',
                            value: valueToPathMap.get(currentItem.value.toString()) || []
                        });
                    }
                    break;
                }
            case keys.Space:
            case keys.Enter:
                {
                    event.preventDefault();
                    if (!path[0]) {
                        dispatchPath({
                            type: 'opened_first_level'
                        });
                        dispatchFocusedPath({
                            type: 'set_initial_focus'
                        });
                        break;
                    }
                    if (!currentItem || (currentItem === null || currentItem === void 0 ? void 0 : currentItem.disabled) || (currentItem === null || currentItem === void 0 ? void 0 : currentItem.isDisabled)) {
                        break;
                    }
                    handlePressDown(currentItem);
                    break;
                }
            case keys.Tab:
            case keys.Escape:
                {
                    if (path[0]) {
                        handleListToggle(false);
                    }
                    break;
                }
            default:
                {
                    break;
                }
        }
    };
    return {
        onKeyDown: onKeyDown
    };
};
