import { __assign, __extends, __rest } from "tslib";
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
import { Component } from 'react';
import { findDOMNode } from 'react-dom';
import cx from 'classnames';
import isEqual from '../utils/isEqual';
import Input from '../input';
import Popover from '../popover';
import getCaretCoordinates from '../utils/dom/getCaretCoordinates';
import isFirefox from '../utils/isFirefox';
import SelectMenu from '../select-menu';
import { I18nReceiver as Receiver } from '../i18n';
import { findMentionAtCaretPosition } from './findMentionAtCaretPosition';
import * as SelectionChangeEventHub from './SelectionChangeEventHub';
import * as Utils from './utils';
import { getPopoverBottomPosition, getPopoverTopPosition } from './position';
import { MENTION_FOUND } from './constants';
import defer from '../utils/defer';
import { runOnceInNextFrame } from '../utils/nextFrame';
var NAV_KEYS = ['ArrowUp', 'ArrowDown', 'ArrowLeft', 'ArrowRight'];
var DEFAULT_STATE = {
    suggestionVisible: false,
    search: null,
};
var Mention = (function (_super) {
    __extends(Mention, _super);
    function Mention() {
        var _this = _super !== null && _super.apply(this, arguments) || this;
        _this.input = null;
        _this.suggestionList = null;
        _this.state = __assign(__assign({}, DEFAULT_STATE), { position: undefined, placeholder: null });
        _this.BottomPosition = getPopoverBottomPosition(_this);
        _this.TopPosition = getPopoverTopPosition(_this);
        _this.onSuggestionVisibleChange = function (visible) {
            if (!visible) {
                _this.setStateIfChange(_this.getDefaultState());
            }
        };
        _this.onCloseMenuList = function () {
            _this.onSuggestionVisibleChange(false);
        };
        _this.onSelectSuggestion = function (val) {
            _this.onCloseMenuList();
            var _a = _this.props, value = _a.value, onChange = _a.onChange;
            var placeholder = _this.state.placeholder;
            var newValue = Utils.replaceSubstring(value, placeholder.start, placeholder.end, val);
            onChange(newValue.value);
            defer(function () {
                if (_this.input) {
                    _this.input.setSelectionRange(newValue.caret, newValue.caret);
                    _this.input.blur();
                    _this.input.focus();
                }
            });
        };
        _this.onInputChange = function (evt) {
            _this.props.onChange(evt.target.value);
        };
        _this.onInputScroll = runOnceInNextFrame(function () {
            if (_this.state.suggestionVisible) {
                _this.setSuggestionVisible();
            }
        });
        _this.onInputCompositionStart = function () {
            _this._compositing = true;
        };
        _this.onInputCompositionEnd = function () {
            _this._compositing = false;
        };
        _this.onInputBlur = function (evt) {
            if (!_this.state.suggestionVisible) {
                _this.setStateIfChange(_this.getDefaultState());
            }
            _this.triggerEventCallback('onBlur', evt);
        };
        _this.onInputKeyUp = function (evt) {
            if (isFirefox &&
                (evt.altKey ||
                    evt.ctrlKey ||
                    evt.metaKey ||
                    NAV_KEYS.indexOf(evt.key) !== -1)) {
                defer(_this.setSuggestionVisible, _this.props.value);
            }
            _this.triggerEventCallback('onKeyUp', evt);
        };
        _this.onInputKeyDown = function (evt) {
            if (_this.state.suggestionVisible && _this.suggestionList) {
                var key = evt.key;
                if (key === 'ArrowUp') {
                    _this.suggestionList.moveFocusIndexUp();
                    evt.preventDefault();
                }
                else if (key === 'ArrowDown') {
                    _this.suggestionList.moveFocusIndexDown();
                    evt.preventDefault();
                }
                else if (key === 'Enter') {
                    _this.suggestionList.selectCurrentFocusIndex(evt);
                    evt.preventDefault();
                }
                else if (key === 'Escape') {
                    _this.setStateIfChange(_this.getDefaultState());
                }
            }
            _this.triggerEventCallback('onKeyDown', evt);
        };
        _this.onSelectionChange = function () {
            _this.setSuggestionVisible(_this.props.value);
        };
        _this.saveInputRef = function (instance) {
            if (_this.input) {
                SelectionChangeEventHub.uninstall({
                    node: _this.input,
                    callback: _this.onSelectionChange,
                });
            }
            if (!instance) {
                return;
            }
            var inputNode = Utils.getInputNodeForTrigger(findDOMNode(instance));
            _this.input = inputNode;
            if (_this.input) {
                SelectionChangeEventHub.install({
                    node: _this.input,
                    callback: _this.onSelectionChange,
                });
            }
        };
        _this.onSuggestionListRefChange = function (instance) {
            _this.suggestionList = instance;
        };
        _this.setSuggestionVisible = function (value) {
            if (!_this.input || _this._compositing) {
                return;
            }
            value = value !== undefined ? value : _this.props.value;
            var triggerText = _this.props.triggerText;
            var mention = findMentionAtCaretPosition({
                input: _this.input,
                value: value,
                triggerText: triggerText,
            });
            var newState = _this.getDefaultState();
            if (mention.code === MENTION_FOUND) {
                newState.suggestionVisible = true;
                newState.search = Utils.substring(value, mention.searchStart, mention.searchEnd + 1);
                newState.position = _this.getCaretCoordinates(mention.caretMeasureStart);
                newState.placeholder = {
                    start: mention.placeholderStart,
                    end: mention.placeholderEnd,
                };
            }
            _this.setStateIfChange(newState);
        };
        return _this;
    }
    Mention.prototype.render = function () {
        var _this = this;
        var _a = this.props, multiLine = _a.multiLine, position = _a.position, suggestions = _a.suggestions, onSearchChange = _a.onSearchChange, suggestionNotFoundContent = _a.suggestionNotFoundContent, loading = _a.loading, triggerText = _a.triggerText, onChange = _a.onChange, onBlur = _a.onBlur, onKeyUp = _a.onKeyUp, onKeyDown = _a.onKeyDown, type = _a.type, className = _a.className, inline = _a.inline, passThroughProps = __rest(_a, ["multiLine", "position", "suggestions", "onSearchChange", "suggestionNotFoundContent", "loading", "triggerText", "onChange", "onBlur", "onKeyUp", "onKeyDown", "type", "className", "inline"]);
        var inputType = multiLine ? 'textarea' : 'text';
        var suggestionVisible = this.state.suggestionVisible;
        return (_jsx(Receiver, __assign({ componentName: "Mention" }, { children: function (i18n) {
                return (_jsxs(Popover, __assign({ visible: suggestionVisible, onVisibleChange: _this.onSuggestionVisibleChange, position: position === 'bottom' ? _this.BottomPosition : _this.TopPosition }, { children: [_jsx(Popover.Trigger.Click, __assign({ getElement: Utils.getInputNodeForTrigger }, { children: _jsx(Input, __assign({ type: inputType, ref: _this.saveInputRef, className: cx('zent-mention', className), onChange: _this.onInputChange, onBlur: _this.onInputBlur, onKeyUp: _this.onInputKeyUp, onKeyDown: _this.onInputKeyDown, onScroll: _this.onInputScroll, onWheel: _this.onInputScroll, onCompositionStart: _this.onInputCompositionStart, onCompositionEnd: _this.onInputCompositionEnd, inline: inline }, passThroughProps), void 0) }), void 0), _jsx(Popover.Content, { children: _jsx(SelectMenu, { ref: _this.onSuggestionListRefChange, items: Utils.getMenuListItems(suggestions, i18n.noContent), onRequestClose: _this.onCloseMenuList, onSelect: _this.onSelectSuggestion }, void 0) }, void 0)] }), void 0));
            } }), void 0));
    };
    Mention.prototype.componentDidUpdate = function (prevProps) {
        if (prevProps.value !== this.props.value) {
            this.setSuggestionVisible(this.props.value);
        }
    };
    Mention.prototype.componentDidMount = function () {
        this.setSuggestionVisible(this.props.value);
    };
    Mention.prototype.triggerEventCallback = function (eventName, evt) {
        var fn = this.props[eventName];
        if (typeof fn === 'function') {
            fn(evt);
        }
    };
    Mention.prototype.setStateIfChange = function (state) {
        var isSearchChanged = state.search !== this.state.search;
        if (!isEqual(this.state, state)) {
            var onSearchChange = this.props.onSearchChange;
            if (isSearchChanged && typeof onSearchChange === 'function') {
                onSearchChange(state.search);
            }
            this.setState(state);
        }
    };
    Mention.prototype.getCaretCoordinates = function (start) {
        var position = getCaretCoordinates(this.input, start, { debug: false });
        var _a = this.input, scrollLeft = _a.scrollLeft, scrollTop = _a.scrollTop;
        if (scrollLeft) {
            position.left = position.left - scrollLeft;
        }
        if (scrollTop) {
            position.top = position.top - scrollTop;
        }
        return position;
    };
    Mention.prototype.getDefaultState = function () {
        return __assign(__assign({}, this.state), DEFAULT_STATE);
    };
    Mention.defaultProps = {
        multiLine: false,
        position: 'bottom',
        suggestionNotFoundContent: '',
        suggestions: [],
        triggerText: '@',
        inline: true,
    };
    return Mention;
}(Component));
export { Mention };
export default Mention;
