import React, { Component } from 'react';
import PropTypes from 'prop-types';
import classnames from 'classnames';

import Dropdown from '../Dropdown/index';
import SearchGroup from './SearchGroup/index';
import './autocomplete.scss';

const { Content, Item } = Dropdown;

const propTypes = {
  onSelection: PropTypes.func,
  indexes: PropTypes.array,
  noMatchLabel: PropTypes.string,
  placeholder: PropTypes.string,
  hideDropdown: PropTypes.bool,
  className: PropTypes.string,
  style: PropTypes.object,
  ignoreCase: PropTypes.bool,
  input: PropTypes.object,
  onChange: PropTypes.func,
  matches: PropTypes.array,
  value: PropTypes.string,
  handleChange: PropTypes.func,
  label: PropTypes.string,
  html: PropTypes.bool
};

const defaultProps = {
  onSelection: () => { },
  indexes: [],
  noMatchLabel: undefined,
  placeholder: undefined,
  hideDropdown: false,
  className: '',
  style: null,
  ignoreCase: false,
  input: {},
  onChange: null,
  matches: null,
  value: null,
  handleChange: null,
  label: '',
  html: false
};


/**
 * Autocomplete input
 *
 */
class Autocomplete extends Component {
  state = {
    value: '',
    matchedIndexes: [],
    currentSelected: -1
  }


  componentWillReceiveProps(nextProps) {
    if (nextProps.matches && nextProps.matches.length > 0) {
      this.dropdown.openPanel();
    } else if (nextProps.matches &&
      (nextProps.matches.length !== this.props.matches.length) &&
      nextProps.matches.length === 0) {
      this.dropdown.closePanel();
    }
  }

  setDropdownRef = node => { this.dropdown = node; }

  handleChange = e => {
    this.filterResults(e.target.value);
  }

  handleFocus = () => {
    const { value } = this.state;

    if (this.props.matches && (this.props.matches.length > 0 || value.length >= 3)) {
      this.dropdown.openPanel();
    }
  }

  filterResults = value => {
    const { indexes, noMatchLabel, ignoreCase } = this.props;
    let matchedIndexes = [];
    if (value.length >= 3) {
      matchedIndexes = ignoreCase ?
        indexes.filter(index => index.toLowerCase().indexOf(value.toLowerCase()) === 0)
        : indexes.filter(index => index.indexOf(value) === 0);
      if (matchedIndexes.length) {
        this.dropdown.openPanel();
      } else if (noMatchLabel) {
        this.dropdown.openPanel();
      } else {
        this.dropdown.closePanel();
      }
    } else {
      this.dropdown.closePanel();
    }
    this.props.onChange(matchedIndexes);
    this.setState({ value, matchedIndexes, currentSelected: -1 });
  }

  handleSelection = (value, index) => () => {
    const { onSelection } = this.props;
    if (!this.props.matches) this.filterResults(value);
    this.dropdown.closePanel();
    onSelection(value, index);
  }

  handleSubmit = e => {
    const { value: stateValue, matchedIndexes, currentSelected } = this.state;
    const { matches, value: propsValue } = this.props;
    const realMatches = matches || matchedIndexes;
    const value = propsValue || stateValue;
    e.preventDefault();

    if (currentSelected > -1) {
      this.handleSelection(realMatches[currentSelected], currentSelected)();
    } else {
      this.handleSelection(value)();
    }
    this.setState({ value: '' });
  }

  handleNavigation = e => {
    const { matches } = this.props;
    const { matchedIndexes, currentSelected } = this.state;
    const realMatches = matches || matchedIndexes;
    if (e.key === 'ArrowDown') {
      e.preventDefault();
      if (currentSelected < realMatches.length - 1) {
        this.setState({ currentSelected: currentSelected + 1 });
      }
    } else if (e.key === 'ArrowUp') {
      e.preventDefault();
      if (currentSelected >= 0) {
        this.setState({ currentSelected: currentSelected - 1 });
      }
    }
  }

  render() {
    const { noMatchLabel, placeholder, hideDropdown, className, style, input, matches,
      handleChange, value: propsValue, label, html } = this.props;
    const { value: stateValue, matchedIndexes, currentSelected } = this.state;
    const realMatches = matches || matchedIndexes;
    const value = propsValue || stateValue;
    return (
      <Dropdown
        variant="full-width"
        styleName="results"
        ref={this.setDropdownRef}
        className={className}
        style={style}
      >
        {({ openPanel, closePanel, togglePanel, variant, isActive, reverse }) => {
          const resultRender = [
            <SearchGroup
              value={value}
              key="trigger"
              placeholder={placeholder}
              onFocus={this.handleFocus}
              onSubmit={this.handleSubmit}
              onChange={matches ? handleChange : this.handleChange}
              onKeyDown={this.handleNavigation}
              input={input}
              onClick={togglePanel}
              openPanel={openPanel}
              closePanel={closePanel}
              label={label}
            />
          ];
          if (!hideDropdown) {
            resultRender.push(
              <Content
                key="content"
                variant={variant}
                active={isActive}
                reverse={reverse}
              >
                {
                  realMatches.length === 0
                    ? <div styleName="no-match">{noMatchLabel}</div>
                    : realMatches.map((v, k) => (
                      typeof v === 'object' ?
                        <Item
                          styleName={classnames('item', { selected: currentSelected === k })}
                          onClick={this.handleSelection(v, k)}
                          key={`autocomplete${v.value}`}
                        >
                          {html ? <div dangerouslySetInnerHTML={{ __html: v.value }} /> : v.value}
                        </Item>
                        :
                        <Item
                          styleName={classnames('item', { selected: currentSelected === k })}
                          onClick={this.handleSelection(v, k)}
                          key={`autocomplete${v}`}
                        >
                          {html ? <div dangerouslySetInnerHTML={{ __html: v }} /> : v}
                        </Item>
                    ))
                }
              </Content>
            );
          }
          return resultRender;
        }}
      </Dropdown>
    );
  }
}


Autocomplete.propTypes = propTypes;
Autocomplete.defaultProps = defaultProps;

export default Autocomplete;
