import React from 'react';
import ReactDOM from 'react-dom';
import PropTypes from 'prop-types';
import { Manager, Reference, Popper } from 'react-popper';
import { FormControlSelect } from '../../atoms/formControlSelect/FormControlSelect';
import { FormControlSelectThemeDefault } from '../../atoms/formControlSelect/themes/FormControlSelectThemeDefault';
import { Icon } from '../../atoms/icon/Icon';
import { keyCodes } from '../../../helpers';

const propTypes = {
  children: PropTypes.node,
  options: PropTypes.arrayOf(PropTypes.object),
  onAdd: PropTypes.func,
  onClose: PropTypes.func,
  icon: PropTypes.string,
  title: PropTypes.node,
  placeholder: PropTypes.string,
  isOpen: PropTypes.bool,
  showInline: PropTypes.bool,
  disableClickOutside: PropTypes.bool,
  noAutoFocus: PropTypes.bool,
};

const defaultProps = {
  children: null,
  options: [],
  onAdd: () => {},
  onClose: () => {},
  icon: 'plus',
  title: 'Add',
  placeholder: 'Search...',
  isOpen: false,
  showInline: false,
  disableClickOutside: false,
  noAutoFocus: false,
};

const theme = {
  control: (styles, { isDisabled, isFocused }) => ({
    ...FormControlSelectThemeDefault.control(styles, { isDisabled, isFocused }),
    margin: '0 0.8rem 0.8rem 0.8rem',
    fontSize: '0.9rem',
  }),
  dropdownIndicator: () => ({
    display: 'none',
  }),
  menu: (styles) => ({
    ...styles,
    position: 'relative',
    boxShadow: 'none',
    border: 'none',
    borderTop: '0.0625rem solid rgba(0, 0, 0, 0.05)',
    borderRadius: 0,
    marginBottom: 0,
  }),
};

export class AddBox extends React.Component {
  container = React.createRef();

  componentWillUnmount() {
    this.removeEvents();
  }

  addEvents = () => {
    ['click', 'touchstart', 'keyup'].forEach(
      (event) => document.addEventListener(event, this.handleDocumentEvent, true)
    );
  }

  removeEvents = () => {
    ['click', 'touchstart', 'keyup'].forEach(
      (event) => document.removeEventListener(event, this.handleDocumentEvent, true)
    );
  }

  handleDocumentEvent = (e) => {
    const { onClose } = this.props;

    if (e && (e.which === 3 || (e.type === 'keyup' && e.which !== keyCodes.esc))) {
      return;
    }

    if (!this.container) {
      return;
    }

    if (this.container.contains(e.target) && this.container !== e.target
      && (e.type !== 'keyup' || e.which === keyCodes.tab)
    ) {
      return;
    }

    onClose();
  }

  handleAdd = (item) => {
    const { onAdd } = this.props;
    onAdd(item);
  }

  render() {
    const {
      children,
      options,
      icon,
      title,
      placeholder,
      isOpen,
      onClose,
      showInline,
      disableClickOutside,
      noAutoFocus,
      ...otherProps
    } = this.props;

    this.removeEvents();

    if (isOpen && !disableClickOutside) {
      this.addEvents();
    }

    // autofocus in react-select and Popper doesn't work well together; it makes the first click on
    // the close button ineffective
    const autoFocus = showInline && !noAutoFocus;

    const { handleAdd } = this;
    // eslint-disable-next-line react/prop-types
    const Menu = React.forwardRef(({ scheduleUpdate, ...attrs }, ref) => (
      <div
        ref={ref}
        className="sui-m-add-box"
        {...attrs}
      >
        <button
          type="button"
          className="sui-m-add-box__close"
          onClick={() => onClose()}
        >
          <Icon name="close" size="sm" />
        </button>
        <div className="sui-m-add-box__title">
          {!!icon && (
            <Icon name={icon} size="sm" position="start" />
          )}
          {title}
        </div>
        <div className="sui-m-add-box__select">
          <FormControlSelect
            menuIsOpen
            autoFocus={autoFocus}
            placeholder={placeholder}
            onChange={(item) => handleAdd(item)}
            onInputChange={scheduleUpdate ? () => scheduleUpdate() : () => {}}
            noOptionsMessage={({ inputValue }) => {
              if (!inputValue) return 'No option';
              return `No option "${inputValue}"`;
            }}
            theme={theme}
            options={options}
            isGroupOption
            {...otherProps}
          />
        </div>
      </div>
    ));

    if (showInline) {
      return isOpen && (
        <div ref={(node) => { this.container = node; }}>
          {children}
          <Menu />
        </div>
      );
    }

    return (
      <Manager>
        <Reference>{({ ref }) => <span style={{ display: 'inline-block' }} ref={ref}>{children}</span>}</Reference>
        {isOpen && ReactDOM.createPortal(
          <Popper
            innerRef={(node) => { this.container = node; }}
            placement="bottom-start"
          >
            {({
              ref, style, placement, scheduleUpdate,
            }) => (
              <Menu
                ref={ref}
                style={style}
                data-placement={placement}
                scheduleUpdate={scheduleUpdate}
              />
            )}
          </Popper>,
          document.body
        )}
      </Manager>
    );
  }
}

AddBox.propTypes = propTypes;
AddBox.defaultProps = defaultProps;
