import React from 'react';
import PropTypes from 'prop-types';
import cx from 'classnames';
import { I18n as I18nDecorator } from '@procore/core-react';

export class FilterAvailable extends React.Component {
  static propTypes = {
    data: PropTypes.arrayOf(PropTypes.shape({
      endpoint: PropTypes.string,
      key: PropTypes.string,
      value: PropTypes.string
    })).isRequired,
    disabled: PropTypes.bool.isRequired,
    I18n: PropTypes.shape().isRequired,
    onChange: PropTypes.func.isRequired,
    styles: PropTypes.shape().isRequired
  };

  constructor(props) {
    super(props);

    this.ignoreNextCollapse = false;

    this.state = {
      expanded: false,
      focusedItem: 0
    };
  }

  componentDidMount() {
    window.addEventListener('click', this.onCollapse);
  }

  componentWillUnmount() {
    window.removeEventListener('click', this.onCollapse);
  }

  onExpand = () => {
    this.ignoreNextCollapse = true;

    if (this.state.expanded === true || this.props.disabled) {
      this.onCollapse();
      return;
    }

    this.setState({ expanded: true, focusedItem: 0 });

    if (this.tokenBodyScroll) {
      this.tokenBodyScroll.scrollTop = 0;
    }
  }

  onCollapse = () => {
    if (this.ignoreNextCollapse === true) {
      this.ignoreNextCollapse = false;
      return;
    }

    this.setState({ expanded: false });
  }

  onChange = (evt) => {
    this.setState({ expanded: false });
    let key;

    if (evt.key === 'Enter') {
      key = this.props.data[this.state.focusedItem].key;
    } else {
      key = evt.currentTarget.dataset.key;
    }

    this.props.onChange(key);
    document.activeElement.blur();
  }

  onKeyDown = (evt) => {
    const { expanded } = this.state;
    let { focusedItem } = this.state;

    if (expanded) {
      switch (evt.key) {
        case 'Tab':
        case 'Escape':
          this.onCollapse();
          break;
        case 'ArrowDown':
          evt.preventDefault();
          if (focusedItem < this.props.data.length - 1) {
            focusedItem += 1;
            this.scrollDown(focusedItem);
            this.setState({ focusedItem });
          }
          break;
        case 'ArrowUp':
          evt.preventDefault();
          if (focusedItem > 0) {
            focusedItem -= 1;
            this.scrollUp(focusedItem);
            this.setState({ focusedItem });
          }
          break;
        case 'Enter':
          this.onChange(evt);
          break;
        default:
          break;
      }
    }
  };

  onHoverItem = item => this.setState({ focusedItem: item });

  scrollDown = (focusedItem) => {
    if (this.tokenBodyScroll) {
      const items = [...this.tokenBodyScroll.childNodes].slice(0, focusedItem + 1);
      const scrollPosition = items.reduce((acc, item) =>
        acc + item.clientHeight, 0) - this.tokenBodyScroll.clientHeight;

      if (scrollPosition >= this.tokenBodyScroll.scrollTop) {
        this.tokenBodyScroll.scrollTop = scrollPosition;
      }
    }
  }

  scrollUp = (focusedItem) => {
    if (this.tokenBodyScroll) {
      const items = [...this.tokenBodyScroll.childNodes].slice(0, focusedItem);
      const scrollPosition = items.reduce((acc, item) => acc + item.clientHeight, 0);

      if (scrollPosition <= this.tokenBodyScroll.scrollTop) {
        this.tokenBodyScroll.scrollTop = scrollPosition;
      }
    }
  }

  render() {
    const {
      data,
      disabled,
      I18n,
      styles
    } = this.props;

    const {
      expanded,
      focusedItem
    } = this.state;

    const items = data.map((item, i) => (
      <div
        className={cx(styles.availableRow, { [styles.focusedItem]: focusedItem === i })}
        data-key={item.key}
        data-qa={`filter-options-${item.key}`}
        key={`item-${item.key}`}
        onClick={this.onChange}
        onMouseMove={() => this.onHoverItem(i)}
      >
        {item.value}
      </div>
    ));

    const text = (
      <div
        className={cx(styles.tokenTitle, styles.availableTitle, {
          [styles.disabled]: disabled
        })}
      >
        {I18n.t('views.global.add_filter')}
      </div>
    );

    const caret = (items.length === 0)
      ? null
      : (<div className={cx(styles.tokenCaret, { [styles.disabled]: disabled })}>
        <span
          className={cx('fa', 'fa-caret-down', styles.arrow,
            { [styles.expanded]: expanded })}
        />
      </div>);

    return (
      <div className={styles.tokenContainer}>
        <button
          className={cx(styles.tokenHead, { [styles.disabled]: disabled })}
          data-key={'inactive'}
          data-qa="addFilter"
          disabled={disabled}
          onClick={this.onExpand}
          onKeyDown={this.onKeyDown}
        >
          {text}
          {caret}
        </button>

        <div className={cx(styles.tokenBody, { [styles.expanded]: expanded })}>
          <div className={styles.tokenBodyScroll} ref={(el) => { this.tokenBodyScroll = el; }}>
            {items}
          </div>
        </div>
      </div>
    );
  }
}

export default I18nDecorator.withConsumer(FilterAvailable);
