import React from 'react';
import classNames from 'classnames';
import InputWithOptions from '../InputWithOptions';
import InputWithTags from './InputWithTags';
import last from 'lodash/last';
import difference from 'difference';
import { st, classes } from './MultiSelect.st.css.js';
class MultiSelect extends InputWithOptions {
    constructor(props) {
        super(props);
        this.onKeyDown = this.onKeyDown.bind(this);
        this.onPaste = this.onPaste.bind(this);
        this._onBlur = this._onBlur.bind(this);
        this.state = { ...this.state, pasteDetected: false };
    }
    hideOptions() {
        super.hideOptions();
        if (this.props.clearOnBlur) {
            this.clearInput();
        }
    }
    rootAdditionalProps() {
        const { className } = this.props;
        return {
            className: st(classes.root, className),
        };
    }
    onClickOutside() {
        if (this.state.showOptions) {
            this.hideOptions();
        }
    }
    _onBlur(event) {
        super._onBlur(event);
        this.props.acceptOnBlur && this.submitValue(this.state.inputValue);
    }
    getUnselectedOptions() {
        const optionIds = this.props.options.map(option => option.id);
        const tagIds = this.props.tags.map(tag => tag.id);
        const unselectedOptionsIds = difference(optionIds, tagIds);
        return this.props.options.filter(option => unselectedOptionsIds.includes(option.id));
    }
    dropdownAdditionalProps() {
        const { predicate, emptyStateMessage, fixedFooter } = this.props;
        const filterFunc = this.state.isEditing ? predicate : () => true;
        const filtered = this.getUnselectedOptions().filter(filterFunc);
        let options = filtered;
        if (emptyStateMessage && filtered.length === 0) {
            options = [
                {
                    id: 'empty-state-message',
                    value: emptyStateMessage,
                    disabled: true,
                },
            ];
        }
        return {
            options,
            closeOnSelect: false,
            selectedHighlight: false,
            selectedId: -1,
            fixedFooter,
        };
    }
    closeOnSelect() {
        return false;
    }
    isDropdownLayoutVisible() {
        // Don't show dropdown if there are no options available
        const options = this.props.options || [];
        const isWithOtherItems = !!this.props.fixedFooter ||
            !!this.props.emptyStateMessage ||
            !!this.props.customDropdownContent;
        return (super.isDropdownLayoutVisible() &&
            (options.length > 0 || isWithOtherItems));
    }
    inputAdditionalProps() {
        return {
            readOnly: this.props.readOnly,
            disableEditing: true,
            inputElement: (React.createElement(InputWithTags, { className: classes.inputWithTags, onReorder: this.props.onReorder, maxNumRows: this.props.maxNumRows, mode: this.props.mode, hideCustomSuffix: this.isDropdownLayoutVisible(), customSuffix: this.props.customSuffix, customPrefix: this.props.customPrefix, border: this.props.border })),
            onKeyDown: this.onKeyDown,
            delimiters: this.props.delimiters,
            onPaste: this.onPaste,
        };
    }
    onPaste() {
        this.setState({ pasteDetected: true });
    }
    _splitByDelimitersAndTrim(value) {
        const delimitersRegexp = new RegExp(this.props.delimiters.join('|'), 'g');
        return value
            .split(delimitersRegexp)
            .map(str => str.trim())
            .filter(str => str);
    }
    _onChange(event) {
        if (this.state.pasteDetected) {
            const value = event.target.value;
            this.setState({ pasteDetected: false }, () => {
                this.submitValue(value);
            });
        }
        else {
            this.setState({ inputValue: event.target.value });
            this.props.onChange && this.props.onChange(event);
        }
        // If the input value is not empty, should show the options
        if (event.target.value.trim()) {
            this.showOptions();
        }
    }
    _onSelect(option) {
        this.onSelect(option);
    }
    _onManuallyInput(inputValue, event) {
        const { value } = this.props;
        // FIXME: InputWithOptions is not updating it's inputValue state when the `value` prop changes.
        // So using `value` here, covers for that bug. (This is tested)
        // BTW: Previously, `value` was used to trigger onSelect, and `inputValue` was used to trigger onManuallyInput. Which is crazy.
        // So now both of them trigger a submit (onManuallyInput).
        const _value = (value && value.trim()) || (inputValue && inputValue.trim());
        this.submitValue(_value);
        _value && event.preventDefault();
        if (this.closeOnSelect()) {
            this.hideOptions();
        }
    }
    getManualSubmitKeys() {
        return ['Enter', 'Tab'].concat(this.props.delimiters);
    }
    onKeyDown(event) {
        const { tags, value, onRemoveTag } = this.props;
        if (tags.length > 0 &&
            (event.key === 'Delete' || event.key === 'Backspace') &&
            value &&
            value.length === 0) {
            onRemoveTag(last(tags).id);
        }
        if (event.key === 'Escape') {
            this.clearInput();
            super.hideOptions();
            event.stopPropagation();
        }
        if (this.props.onKeyDown) {
            this.props.onKeyDown(event);
        }
    }
    optionToTag({ id, value, tag, theme }) {
        return tag ? { id, ...tag } : { id, label: value, theme };
    }
    onSelect(option) {
        this.clearInput();
        const { onSelect } = this.props;
        if (onSelect) {
            onSelect(this.props.options.find(o => o.id === option.id));
        }
    }
    submitValue(inputValue) {
        if (!inputValue) {
            return;
        }
        const { onManuallyInput } = this.props;
        const values = this._splitByDelimitersAndTrim(inputValue);
        onManuallyInput && values.length && onManuallyInput(values);
        this.clearInput();
    }
    clearInput() {
        this.input.current && this.input.current.clear();
        if (this.props.onChange) {
            this.props.onChange({ target: { value: '' } });
        }
    }
}
MultiSelect.autoSizeInput = ({ className, 'data-ref': dataRef, ...rest }) => {
    const inputClassName = classNames(className, classes.autoSizeInput);
    return React.createElement("input", { ...rest, ref: dataRef, className: inputClassName });
};
MultiSelect.autoSizeInputWithRef = () => React.forwardRef((props, ref) => (({ className, ref, ...rest }) => {
    const inputClassName = classNames(className, classes.autoSizeInput);
    return React.createElement("input", { ...rest, ref: ref, className: inputClassName });
})({ ...props, ref }));
MultiSelect.displayName = 'MultiSelect';
MultiSelect.defaultProps = {
    ...InputWithOptions.defaultProps,
    predicate: () => true,
    tags: [],
    delimiters: [','],
    clearOnBlur: true,
    customInput: MultiSelect.autoSizeInputWithRef(),
};
export default MultiSelect;
//# sourceMappingURL=MultiSelect.js.map