import React, {Component} from 'react';
import PropTypes from 'prop-types';
import ReactSelect from 'react-select';
import isFunction from 'lodash.isfunction';
import ReactAsyncSelect from 'react-select/lib/Async';
import Icon from '../Icon';
import defaultStyles from '../../styles/reactSelect/styles';

function getSplitValues(values, availableOptions) {
    return values
        .split(',')
        .map((value) => availableOptions.find((option) => {
            return option.label.toLowerCase() === value.trim()
                .toLowerCase();
        }))
        .filter(Boolean);
}

const ClearIndicator = (props) => {
    const {
        getStyles,
        innerProps: {
            ref,
            ...restInnerProps
        },
    } = props;

    return (
        <div
            {...restInnerProps}
            ref={ref}
            style={getStyles('clearIndicator', props)}
            id={`${props.elementId}-clear`}
        >
            <Icon
                name="close"
                color="gray"
                size="small"
            />
        </div>
    );
};

ClearIndicator.propTypes = {
    getStyles: PropTypes.func.isRequired,
    innerProps: PropTypes.object.isRequired,
    elementId: PropTypes.string.isRequired,
};

class TagsInput extends Component {
    constructor(props) {
        super();

        this.customStyles = {
            ...defaultStyles,
            ...props.customStyles,
        };

        this.ref = null;
        this.onInputChange = this.onInputChange.bind(this);
    }

    onInputChange(inputValue) {
        if (!/,(?=\s|\w)/ig.test(inputValue)) {
            return;
        }

        const splitValues = getSplitValues(inputValue, this.props.options);

        if (!splitValues.length) {
            return;
        }

        const value = splitValues.reduce((acc, current) => {
            const hasValue = Boolean(acc.find((existedValue) => {
                return existedValue.label.toLowerCase() === current.label.toLowerCase();
            }));

            if (hasValue) {
                return acc;
            }

            acc.push(current);

            return acc;
        }, this.props.value);

        this.props.onChange(value);
        setTimeout(() => this.ref.blur(), 0);
    }

    handleAsyncRequest(value) {
        if (!value.length || value.length < 2) {
            return null;
        }

        return this.props.promiseOptions(value);
    }

    render() {
        this.customStyles = {
            ...this.customStyles,
            control: (base, state) => {
                return {
                    ...defaultStyles.control(base, state),
                    ...(isFunction(this.props.customStyles.control) ? this.props.customStyles.control(base, state) : {}),
                    border: this.props.errors.length ? '1px solid #ed3030' : defaultStyles.control(base, state).border,
                };
            },
        };

        const config = {
            ...this.props,
            placeholder: 'Start typing...',
            id: this.props.elementId,
            onChange: this.props.onChange,
            styles: this.customStyles,
            components: {
                ClearIndicator: (props) => (<ClearIndicator
                    {...props}
                    elementId={this.props.elementId}
                />),
            },
        };

        const asyncSelect = (<ReactAsyncSelect
            {...config}
            loadOptions={(value) => this.handleAsyncRequest(value)}
        />);

        const select = (<ReactSelect
            {...config}
            ref={(ref) => {
                this.ref = ref;
            }}
            options={this.props.options}
            onInputChange={this.onInputChange}
        />);

        return (
            this.props.isAsync ? asyncSelect : select
        );
    }
}

TagsInput.propTypes = {
    customStyles: PropTypes.object,
    isClearable: PropTypes.bool,
    isDisabled: PropTypes.bool,
    isLoading: PropTypes.bool,
    isRtl: PropTypes.bool,
    isMulti: PropTypes.bool,
    isSearchable: PropTypes.bool,
    isAsync: PropTypes.bool,
    elementId: PropTypes.string.isRequired,
    options: PropTypes.arrayOf(PropTypes.shape({
        value: PropTypes.oneOfType([PropTypes.number, PropTypes.string]).isRequired,
        label: PropTypes.string.isRequired,
    })),
    onChange: PropTypes.func.isRequired,
    promiseOptions: PropTypes.func,
    errors: PropTypes.array,
    value: PropTypes.array,
};

TagsInput.defaultProps = {
    isClearable: true,
    isDisabled: false,
    isLoading: false,
    isRtl: false,
    isMulti: true,
    isSearchable: true,
    isAsync: false,
    customStyles: {},
    options: [],
    promiseOptions: () => Promise.resolve(),
    errors: [],
    value: [],
};

export default TagsInput;
