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 __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 debounce from 'lodash.debounce';
import isEqual from 'lodash.isequal';
import { isNonNullable } from '../../lib/utils.js';
import { isKeyArrowUp, isKeyArrowVertical, isKeyEnter, isKeyEscape } from '../../lib/events/keyboard/identifiers.js';
import * as LayoutEvents from '../../lib/LayoutEvents.js';
import { DefaultState } from './CustomComboBox.js';
import { ComboBoxRequestStatus } from './CustomComboBoxTypes.js';
var DEBOUNCE_DELAY = 300;
var getValueString = function (value, valueToString) {
    return isNonNullable(value) ? valueToString(value) : '';
};
export var Effect = {
    search: function (query) { return function (dispatch, getState, getProps, getInstance) {
        getInstance().search(query);
    }; },
    debouncedSearch: debounce(function (dispatch, getState, getProps, getInstance, globalObject) {
        var searchEffect = Effect.search(getState().textValue);
        searchEffect(dispatch, getState, getProps, getInstance, globalObject);
    }, DEBOUNCE_DELAY),
    cancelRequest: function (dispatch, getState, getProps, getInstance) {
        Effect.debouncedSearch.cancel();
        getInstance().cancelSearch();
    },
    blur: function (dispatch, getState, getProps) {
        var onBlur = getProps().onBlur;
        if (onBlur) {
            onBlur();
        }
    },
    focus: function (dispatch, getState, getProps) {
        var onFocus = getProps().onFocus;
        if (onFocus) {
            onFocus();
        }
    },
    valueChange: function (value) { return function (dispatch, getState, getProps) {
        var onValueChange = getProps().onValueChange;
        if (onValueChange) {
            onValueChange(value);
        }
    }; },
    valueClear: function (dispatch) {
        dispatch({ type: 'TextChange', value: '' });
    },
    unexpectedInput: function (textValue, items) { return function (dispatch, getState, getProps) {
        var _a = getProps(), onUnexpectedInput = _a.onUnexpectedInput, valueToString = _a.valueToString;
        if (Array.isArray(items) && items.length === 1) {
            var singleItem = items[0];
            var valueContent = getValueString(singleItem, valueToString);
            if (valueContent === textValue) {
                dispatch({ type: 'ValueChange', value: singleItem, keepFocus: false });
                return;
            }
        }
        if (onUnexpectedInput) {
            var value = onUnexpectedInput(textValue);
            if (value !== undefined) {
                dispatch({ type: 'ValueChange', value: value, keepFocus: false });
            }
        }
    }; },
    inputChange: function (dispatch, getState, getProps) {
        var onInputValueChange = getProps().onInputValueChange;
        var textValue = getState().textValue;
        if (onInputValueChange) {
            var returnedValue = onInputValueChange(textValue);
            if (typeof returnedValue === 'string' && returnedValue !== textValue) {
                dispatch({ type: 'TextChange', value: returnedValue });
            }
        }
    },
    inputFocus: function (dispatch, getState, getProps, getInstance) {
        var input = getInstance().input;
        if (!input) {
            return;
        }
        input.focus();
        var inputNode = input.getNode();
        if (inputNode) {
            inputNode.scrollLeft = inputNode.scrollWidth;
            inputNode.scrollTop = inputNode.scrollHeight;
        }
    },
    highlightMenuItem: function (dispatch, getState, getProps, getInstance, globalObject) {
        var _a, _b;
        var _c = getProps(), value = _c.value, itemToId = _c.itemToId, valueToString = _c.valueToString;
        var _d = getState(), items = _d.items, focused = _d.focused, textValue = _d.textValue, requestStatus = _d.requestStatus;
        var menu = getInstance().menu;
        var valueString = getValueString(value, valueToString);
        if (!menu) {
            return;
        }
        if (!focused) {
            return;
        }
        var index = -1;
        if ((items === null || items === void 0 ? void 0 : items.length) && isNonNullable(value)) {
            index = items.findIndex(function (x) { return itemToId(x) === itemToId(value); });
            menu.highlightItem(index);
        }
        else {
            menu.reset();
        }
        if (index >= 0) {
            // @ts-expect-error: Use of private property.
            (_a = globalObject.requestAnimationFrame) === null || _a === void 0 ? void 0 : _a.call(globalObject, function () { return menu === null || menu === void 0 ? void 0 : menu.scrollToSelected(); });
            return;
        }
        var queryTextDifferenceOfSavedValue = textValue !== valueString;
        var needFocusToRefreshButton = requestStatus === ComboBoxRequestStatus.Failed;
        if (queryTextDifferenceOfSavedValue || needFocusToRefreshButton) {
            (_b = globalObject.requestAnimationFrame) === null || _b === void 0 ? void 0 : _b.call(globalObject, function () { return menu === null || menu === void 0 ? void 0 : menu.highlightItem(0); });
        }
    },
    selectMenuItem: function (event) { return function (dispatch, getState, getProps, getInstance) {
        var menu = getInstance().menu;
        if (menu) {
            menu.enter(event);
        }
    }; },
    moveMenuHighlight: function (direction) { return function (dispatch, getState, getProps, getInstance) {
        var menu = getInstance().menu;
        if (menu) {
            menu[direction]();
        }
    }; },
    resetHighlightedMenuItem: function (dispatch, getState, getProps, getInstance) {
        var combobox = getInstance();
        if (combobox.menu && combobox.menu.hasHighlightedItem()) {
            combobox.menu.reset();
        }
    },
    reflow: function () {
        LayoutEvents.emit();
    },
    selectInputText: function (dispatch, getState, getProps, getInstance) {
        var combobox = getInstance();
        combobox.selectInputText();
    },
    inputKeyDown: function (event) { return function (dispatch, getState, getProps) {
        var onInputKeyDown = getProps().onInputKeyDown;
        if (onInputKeyDown) {
            onInputKeyDown(event);
        }
    }; },
};
var never = function () { return null; };
export function reducer(state, props, action) {
    switch (action.type) {
        case 'ValueChange': {
            var value = action.value, keepFocus = action.keepFocus;
            var textValue = getValueString(value, props.valueToString);
            if (keepFocus) {
                return [
                    {
                        opened: false,
                        inputChanged: false,
                        editing: true,
                        items: null,
                        textValue: textValue,
                    },
                    [Effect.valueChange(value), Effect.cancelRequest, Effect.inputFocus],
                ];
            }
            return [
                {
                    opened: false,
                    inputChanged: false,
                    editing: false,
                    items: null,
                    textValue: textValue,
                },
                [Effect.valueChange(value), Effect.cancelRequest],
            ];
        }
        case 'TextChange': {
            var newState = {
                inputChanged: true,
                textValue: action.value,
            };
            if (!action.value && !props.searchOnFocus) {
                return [
                    __assign(__assign({}, newState), { opened: false, items: null }),
                    [Effect.inputChange],
                ];
            }
            return [newState, [Effect.debouncedSearch, Effect.inputChange]];
        }
        case 'KeyPress': {
            var e = action.event;
            var effects = [];
            var nextState = state;
            switch (true) {
                case isKeyEnter(e):
                    if (!state.opened) {
                        break;
                    }
                    e.preventDefault();
                    effects.push(Effect.selectMenuItem(e));
                    break;
                case isKeyArrowVertical(e):
                    e.preventDefault();
                    effects.push(Effect.moveMenuHighlight(isKeyArrowUp(e) ? 'up' : 'down'));
                    if (!state.opened) {
                        effects.push(Effect.search(state.textValue));
                    }
                    break;
                case isKeyEscape(e):
                    nextState = __assign(__assign({}, state), { items: null, opened: false });
                    break;
            }
            return [nextState, __spreadArray(__spreadArray([], effects, true), [Effect.inputKeyDown(e)], false)];
        }
        case 'DidUpdate': {
            if (isEqual(props.value, action.prevProps.value)) {
                return state;
            }
            var nextTextValue = getValueString(props.value, props.valueToString);
            if (!state.focused) {
                return [
                    {
                        editing: false,
                        inputChanged: false,
                        textValue: nextTextValue,
                    },
                    [Effect.cancelRequest],
                ];
            }
            if (state.focused && state.opened) {
                return [__assign(__assign({}, state), { textValue: nextTextValue }), [Effect.cancelRequest, Effect.search(nextTextValue)]];
            }
            if (state.focused) {
                return __assign(__assign({}, state), { textValue: nextTextValue });
            }
            break;
        }
        case 'Mount': {
            return {
                textValue: getValueString(props.value, props.valueToString),
            };
        }
        case 'Focus': {
            var newState = {
                focused: true,
                editing: true,
            };
            if (!action.searchOnFocus) {
                return [newState, [Effect.focus]];
            }
            if (state.editing) {
                return [newState, [Effect.search(state.textValue), Effect.focus]];
            }
            return [newState, [Effect.search(''), Effect.focus, Effect.selectInputText]];
        }
        case 'InputClick': {
            var newState = {
                inputChanged: false,
            };
            if (!state.opened && props.searchOnFocus) {
                return [newState, [Effect.search('')]];
            }
            return state;
        }
        case 'ClearCrossClick': {
            var newState = {
                editing: true,
                loading: true,
            };
            return [newState, [Effect.valueClear, Effect.focus, Effect.search('')]];
        }
        case 'Blur': {
            var inputChanged = state.inputChanged, items = state.items;
            if (!inputChanged) {
                return [
                    {
                        focused: false,
                        opened: false,
                        items: null,
                        editing: false,
                    },
                    [Effect.blur, Effect.cancelRequest],
                ];
            }
            return [
                {
                    focused: false,
                    opened: false,
                    items: null,
                },
                [Effect.blur, Effect.cancelRequest, Effect.unexpectedInput(state.textValue, items)],
            ];
        }
        case 'Reset': {
            return DefaultState;
        }
        case 'Open': {
            return { opened: true };
        }
        case 'Close': {
            return { opened: false, items: null };
        }
        case 'Search': {
            return [state, [Effect.search(action.query)]];
        }
        case 'RequestItems': {
            return {
                loading: true,
                opened: true,
                requestStatus: ComboBoxRequestStatus.Pending,
            };
        }
        case 'ReceiveItems': {
            var shouldResetMenuHighlight = state.textValue === '';
            return [
                {
                    loading: false,
                    opened: true,
                    items: action.items,
                    requestStatus: ComboBoxRequestStatus.Success,
                },
                [shouldResetMenuHighlight ? Effect.resetHighlightedMenuItem : Effect.highlightMenuItem, Effect.reflow],
            ];
        }
        case 'RequestFailure': {
            return [
                {
                    loading: false,
                    opened: true,
                    items: null,
                    requestStatus: ComboBoxRequestStatus.Failed,
                    repeatRequest: action.repeatRequest,
                },
                [Effect.highlightMenuItem],
            ];
        }
        case 'CancelRequest': {
            return {
                loading: false,
                requestStatus: ComboBoxRequestStatus.Unknown,
            };
        }
        default: {
            never();
        }
    }
    return state;
}
//# sourceMappingURL=CustomComboBoxReducer.js.map