/* eslint-disable react/no-danger */
import React from 'react';
import PropTypes from 'prop-types';

import Select, { Creatable } from 'react-select';
import 'react-select/dist/react-select.css';
import omit from 'lodash/omit';
import FieldControl from '../FieldControl';

import './select.scss';

/**
 * Input Select
 *
 */
class SelectInput extends React.Component {
  static propTypes = {
    // eslint-disable-next-line react/no-unused-prop-types
    options: PropTypes.oneOfType([
      PropTypes.object,
      PropTypes.array
    ]),
    /**
     * Allow multiple choices
     */
    multi: PropTypes.bool,
    childrenClassName: PropTypes.string,
    // eslint-disable-next-line react/no-unused-prop-types
    input: PropTypes.object,
    placeholder: PropTypes.string,
    /**
     * Allow user to create new tags in multiple select input
     */
    allowCreate: PropTypes.bool
  };

  static defaultProps = {
    options: [],
    multi: false,
    childrenClassName: '',
    touched: false,
    allowCreate: false,
    placeholder: 'Select...',
    input: null
  };

  state = {
    options: []
  };

  componentWillMount() {
    this.updateOptions();
  }

  componentWillReceiveProps(nextProps) {
    this.updateOptions({ props: nextProps });
  }

  onChange = nextValue => {
    const { onChange } = this.getInputProps();
    this.updateOptions({ nextValue });
    if (typeof onChange === 'function') {
      if (Array.isArray(nextValue)) {
        onChange(nextValue.map(i => i.value));
      } else {
        onChange(nextValue ? nextValue.value : null);
      }
    }
  };

  onBlur = () => {
    const { value, onBlur } = this.getInputProps();
    if (typeof onBlur === 'function') {
      onBlur(value);
    }
  };

  getInputProps(props) {
    const { input, ...resultProps } = props || this.props;
    return { ...resultProps, ...input };
  }

  updateOptions({ props, nextValue } = {}) {
    const resultProps = props || this.props;
    const { options, allowCreate, multi } = resultProps;
    const parsedOptions = Array.isArray(options) ?
      [...options] : Object.keys(options).map(key => ({ value: key, label: options[key] }));
    if (allowCreate && multi) {
      const resultValue = nextValue || this.getInputProps(resultProps).value;
      const objectOption = Array.isArray(options) ?
        options.reduce((resultObject, { value, label }) => {
          // eslint-disable-next-line no-param-reassign
          resultObject[value] = label;
          return resultObject;
        }, {}) || {}
        : options;

      if (Array.isArray(resultValue)) {
        resultValue.forEach(itemValue => {
          if (!objectOption[itemValue]) {
            parsedOptions.push({ value: itemValue, label: itemValue });
          }
        });
      }
    }
    this.setState({ options: parsedOptions });
  }

  render() {
    const {
      childrenClassName,
      allowCreate,
      placeholder,
      ...props
    } = this.props;
    const { options } = this.state;

    const ResultSelect = allowCreate && this.props.multi ? Creatable : Select;

    return (
      <FieldControl {...props}>
        {restProps => (
          <ResultSelect
            className={childrenClassName}
            options={options}
            onChange={this.onChange}
            onBlur={this.onBlur}
            placeholder={placeholder}
            {...omit(this.getInputProps(restProps), ['options', 'onChange', 'onBlur'])}
          />
        )}
      </FieldControl >
    );
  }
}

export default SelectInput;
