import React, { Component } from "react";
import PropTypes from "prop-types";
import { Input } from "../Input/Input.jsx";
import { Option } from "./Option.jsx";
import "./Select.css";

const ESC_KEY_CODE = 27;

const OptionShape = PropTypes.shape({
  name: PropTypes.string,
  value: PropTypes.string
});

class Select extends Component {
  selectDomElement = null;

  static propTypes = {
    placeholder: PropTypes.string,
    default: OptionShape,
    options: PropTypes.arrayOf(OptionShape),
    selectHandler: PropTypes.func,
    includeNone: PropTypes.bool
  };

  static defaultProps = {
    placeholder: "Select",
    default: {},
    options: [],
    selectHandler: () => {},
    includeNone: false
  };

  state = {
    open: false,
    selected: {}
  };

  static getDerivedStateFromProps = (nextProps, prevState) => {
    if (prevState.selected.value) {
      return null;
    }

    return {
      selected: nextProps.default
    };
  };

  openDropdown = () => this.setState({ open: true });

  closeOnEsc = ({ keyCode }) =>
    ESC_KEY_CODE === keyCode && this.setState({ open: false });

  closeOnClick = ({ target }) =>
    this.setState({ open: this.selectDomElement.contains(target) });

  componentDidMount() {
    window.addEventListener("click", this.closeOnClick);
    window.addEventListener("keyup", this.closeOnEsc);
  }

  componentWillUnmount() {
    window.removeEventListener("click", this.closeOnClick);
    window.removeEventListener("keyup", this.closeOnEsc);
  }

  onOptionClick = value => {
    const { options, selectHandler } = this.props;

    if (value === "none") {
      return this.selectNone();
    }

    const selected = options.reduce(
      (selectedOption, option) =>
        option.value === value ? option : selectedOption,
      {}
    );

    this.setState({ selected });
    return selectHandler(selected);
  };

  selectNone = () => {
    const { selectHandler } = this.props;

    this.setState({
      selected: {
        name: "None",
        value: "none"
      }
    });

    return selectHandler({ name: "None", value: null });
  };

  render() {
    const { options, placeholder, includeNone } = this.props;

    return (
      <div className="es-selector">
        <div
          className="es-selector-input"
          ref={elem => (this.selectDomElement = elem)}
          onClick={this.openDropdown}
        >
          <Input
            type="text"
            name={placeholder}
            className="es-select-icon"
            value={this.state.selected.name}
            disabled
          />
        </div>
        {this.state.open && (
          <div className="es-selector-options">
            {includeNone && (
              <Option
                onClickHandler={this.selectNone}
                value="none"
                name="None"
              />
            )}
            {options.map(({ name, value }) => (
              <Option
                onClickHandler={this.onOptionClick}
                name={name}
                key={value}
                value={value}
              />
            ))}
          </div>
        )}
      </div>
    );
  }
}

export { Select };
