import React from 'react';
import PropTypes from 'prop-types';
import scopedScroll from '@particles/scoped-scroll';
import { Breadcrumbs, Popover, Spinner, Input, Icon } from '@procore/core-react';

export default class Dropdown extends React.Component {
  static propTypes = {
    actions: PropTypes.shape({
      advance: PropTypes.func,
      back: PropTypes.func,
      clearSearch: PropTypes.func,
      onChange: PropTypes.func,
      onSelect: PropTypes.func,
      onKeyDown: PropTypes.func,
      setHighlightIndex: PropTypes.func
    }).isRequired,
    breadcrumbs: PropTypes.arrayOf(PropTypes.oneOfType([PropTypes.number, PropTypes.string])),
    children: PropTypes.func.isRequired,
    clippedResultsMessage: PropTypes.string,
    composedStyles: PropTypes.shape({}).isRequired,
    data: PropTypes.arrayOf(PropTypes.shape({})),
    didClipData: PropTypes.bool.isRequired,
    didError: PropTypes.bool,
    errorMessage: PropTypes.string,
    highlightIndex: PropTypes.number,
    i18n: PropTypes.shape({
      noSearchResults: PropTypes.string
    }).isRequired,
    isLoading: PropTypes.bool,
    onHrefPrint: PropTypes.func.isRequired,
    optionIdKey: PropTypes.string,
    placeholder: PropTypes.string,
    searchTerm: PropTypes.string
  };

  static defaultProps = {
    breadcrumbs: [],
    clippedResultsMessage: 'List results are too large, please search to narrow results.',
    data: [],
    didError: false,
    errorMessage: null,
    highlightIndex: 0,
    isLoading: false,
    optionIdKey: 'id',
    placeholder: 'Search',
    searchTerm: ''
  };

  componentDidMount() {
    this.searchBarRef.focus();
  }

  componentWillReceiveProps(nextProps) {
    if (this.props.didError === true && nextProps.didError === false) {
      this.searchBarRef.focus();
    }
  }

  onBreadcrumbClick = (total, clickedIndex) => (e) => {
    this.props.actions.back(total - clickedIndex - 1, this.listInitialState);
  }

  onOptionClick = (option) => (e) => {
    this.props.actions.onSelect(option);
  }

  onOptionDrilldown = (option) => (e) => {
    e.preventDefault();
    e.stopPropagation();
    this.props.actions.advance(option, this.listInitialState);
  }

  onOptionMouseOver = (index) => (e) => {
    this.props.actions.setHighlightIndex(index);
  }

  listInitialState = () => {
    this.props.actions.setHighlightIndex(0);
    this.props.actions.clearSearch();
    this.searchBarRef.focus();
  }

  listRender = (isEmpty) => {
    const {
      children,
      composedStyles,
      data,
      didClipData,
      highlightIndex,
      onHrefPrint,
      i18n,
      optionIdKey
    } = this.props;

    if (isEmpty) {
      return (<div className={composedStyles.noResults}>{i18n.noSearchResults}</div>);
    }
    return (
      <ul
        className={composedStyles.list}
        onWheel={scopedScroll.scrollInside}
        ref={(ref) => { this.listRef = ref; }}
      >
        {data.map((option, i) => (
          <li key={option[optionIdKey]}>
            <a
              className={highlightIndex === i ? composedStyles.listItemHighlight : composedStyles.listItem}
              data-qatag={option[optionIdKey]}
              href={onHrefPrint(option)}
              onMouseOver={this.onOptionMouseOver(i)}
              onClick={this.onOptionClick(option)}
              ref={(ref) => { highlightIndex === i ? this.highlightedItemRef = ref : null; }}
            >
              {children(option, this.onOptionDrilldown(option))}
            </a>
          </li>
        ))}
        {didClipData &&
          <div className={composedStyles.clippedResults}>
            {this.props.clippedResultsMessage}
          </div>
        }
      </ul>
    );
  }

  render() {
    const {
      actions,
      breadcrumbs,
      composedStyles,
      data,
      didError,
      errorMessage,
      highlightIndex,
      i18n,
      isLoading,
      placeholder,
      searchTerm
    } = this.props;

    return (
      <Popover.Content placement='bottom' className={composedStyles.popover}>
        <div className={composedStyles.searchWrap}>
          <Input
            className={composedStyles.search}
            disabled={isLoading}
            inputRef={(ref) => { this.searchBarRef = ref; }}
            onChange={actions.onChange}
            onKeyDown={actions.onKeyDown(data.length, data[highlightIndex])}
            placeholder={placeholder}
            type='search'
            value={searchTerm}
          />
          <span className={composedStyles.inputIconPosition}>
            {
              searchTerm.length === 0 ?
                <Icon icon='search' className={composedStyles.searchIcon} /> :
                <button onClick={this.listInitialState} className={composedStyles.clearTarget}>
                  <Icon icon='x' className={composedStyles.clearIcon} />
                </button>
            }
          </span>
        </div>
        <Spinner loading={isLoading} label='' size='lg'>
          <div className={didError ? composedStyles.errorRowShow : composedStyles.errorRow}>
            <span className={composedStyles.errorTitle}>
              {didError && i18n.errorTitle}
            </span>
            <span className={composedStyles.errorMessage}>
              {errorMessage}
            </span>
          </div>
          <Breadcrumbs className={composedStyles.crumbs}>
            {breadcrumbs.map((name, i, arr) => (
              <Breadcrumbs.Crumb
                key={`${i}-${String(name).replace(/\s/g, '')}`}
                onClick={this.onBreadcrumbClick(arr.length, i)}
                active={i === (arr.length - 1)}
              >
                {name}
              </Breadcrumbs.Crumb>
            ))}
          </Breadcrumbs>
          {this.listRender(data.length === 0)}
        </Spinner>
      </Popover.Content>
    );
  }
}
