import React from 'react';
import classnames from 'classnames';
import map from 'lodash/map';
import filter from 'lodash/filter';
import SearchSingle from './SearchSingle';
import {fetchJsonp} from 'services/fetch';
import findIndex from 'lodash/findIndex';
import take from 'lodash/take';


/**
 * Implements SearchMulti to autocomplete symbol symbols.
 * Used to build a list of symbols.
 * Symbols are object with format {type: ('symbol' | 'keyword'), value: symbolSymbol}
 */
class SymbolAutocomplete extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      autocompleteQueryLimit: 5,
      autoSymbols: [],
    };
  }

  /**
   * Takes the current search term and a list of symbols returned from server autocomplete
   * and creates list for dropdown.
   * Note that the API endpoint ensures that exact matches will always display first.
  */
  calculateAutocomplete(search = '', serverSymbols = []) {
    if (search.trim().length < 1) {
      this.setState({autoSymbols: []});
      return;
    }
    let list = [];
    let symbols = serverSymbols;
    // Remove anything we want ignored.
    if (this.props.ignoreList) {
      symbols = filter(symbols, (symbol) =>
        this.props.ignoreList.indexOf(symbol.symbol) === -1
      );
    }
    // Limit ourselves to the number of completions we want and change them to be in the
    // correct format.
    symbols = map(take(symbols, this.state.autocompleteQueryLimit), (c) =>
      ({
        label: c.symbol + ' | ' + c.name,
        value: c.symbol,
        heading: 'Symbol ' + ('exchange' in c ? '(' + c.exchange + ')' : ''),
        type: 'symbol'
      })
    );
    list = list.concat(symbols);
    if (this.props.allowKeywords) {
      const keyword = {label: search, value: search, heading: 'Keyword', type: 'keyword'};
      if (symbols.length > 0 && search.toUpperCase() === symbols[0].value.toUpperCase()) {
        list.splice(1, 0, keyword);
      } else {
        list.splice(0, 0, keyword);
      }
    }
    this.setState({autoSymbols: list});
  }

  searchChange(e, val) {
    const value = val.replace('"', '').trim();
    // Handle autocomplete
    if (value.length) {
      fetchJsonp('https://data.benzinga.com/rest/v2/autocomplete?query=' + value, {timeout: 1000})
        .then(req => req.json())
        .then(json => this.calculateAutocomplete(value, json.result));
    } else {
      this.setState({autoSymbols: []});
    }

    if (this.props.onChange) {
      this.props.onChange(e, val);
    }
  }

  render() {
    const {ignoreList, allowKeywords, onChange, ...childProps} = this.props;
    return (
      <SearchSingle
        {...childProps}
        completions={this.state.autoSymbols}
        getItemValue={(item) => item.value}
        onChange={(e, value) => this.searchChange(e, value)}
      />
    );
  }
}

/**
 * Check SearchMulti for additional props.
 */
SymbolAutocomplete.propTypes = {
  /**
   * function(object symbol, boolean isHighlighted)
   *   Function used to render the symbols in the autocomplete list.
   *   Returns a JSX component.
   *   Note that symbols passed to this function will also have the properties 'label' and 'heading'.
  */
  renderItem: React.PropTypes.func,
  /**
   *  String[]
   *    A list of symbols to ignore and remove from the completion list.
   */
  ignoreList: React.PropTypes.arrayOf(React.PropTypes.string),
  /**
   * boolean, default: false
   *   Whether or not to include a 'keyword' option in the autocomplete with a
   *     value of whatever the user typed.
  */
  allowKeywords: React.PropTypes.bool,
  /**
   * function(event event, string value)
   *   Fired when the user makes a change to the input.
   */
  onChange: React.PropTypes.func,
};
SymbolAutocomplete.defaultProps = {
  renderItem(item, isHighlighted) {
    return (
    <li className={classnames('SearchResult', {'is-selected': isHighlighted})}>
      <div className="SearchResult-head">{item.heading}</div>
      <div className="SearchResult-desc">{item.label}</div>
    </li>
    );
  }
};

export default SymbolAutocomplete;
