// @flow
import React from 'react';
import cn from 'classnames';

import Icon from '../icons';
import ResultItem from './resultItem';

import './scss/search.scss';
/* eslint-env browser */

/** Props, передаваемые в Search
  * @property {Function} onChange - передается функция-коллбэк, которая принимает значения
  * введенные в поисковую форму
  * @property {Array<any>} result - массив с результатами поиска, элементы массива выводятся
  * всплывающим списком рядом с поисковой строкой
  * @property {Function} onClickResult - передается функция-коллбэк, которая принимает значение
  * выбранного (по которому кликнули мышкой) элемента из списка result
  */
type SearchProps = {
  onChange: Function,
  result: Array<any>,
  onClickResult: Function,
};

/** State компонента Search
  * @property {boolean} searchHasFocus - в фокусе или нет строка поиска
  * @property {string} searchText - введенный в строку поиска текст
  * @property {boolean} resultIsOpen - отображается или нет список с результатами поиска
  */
type SearchState = {
  searchHasFocus: boolean,
  searchText: string,
  resultIsOpen: boolean,
};

/** Компонент Search - поисковая строка и список с результатами поиска
  * @example
  * <Search
  *   onChange={*функция, принимает значения введенные в поисковую строку и выполняет поиск*}
  *   result={*массив - результат работы функции, переданной в onChange*}
  *   onClickResult={*функция, принимает значение выбранного элемента из списка result*}
  * />
  */
export default class Search extends React.Component<SearchProps, SearchState> {
  static defaultProps = {};

  constructor(props: SearchProps) {
    super(props);
    this.state = {
      searchHasFocus: false,
      searchText: '',
      resultIsOpen: false,
    };
  }

  rootRef: Object

  componentDidUpdate(prevProps: SearchProps) {
    const { result } = this.props;
    const { resultIsOpen } = this.state;
    if (prevProps.result !== result && result.length > 0) {
      this.handleOpenResult();
    }
    if (resultIsOpen) {
      document.addEventListener('mousedown', this.handleDocumentClick);
    } else {
      document.removeEventListener('mousedown', this.handleDocumentClick);
    }
  }

  componentWillUnmount() {
    document.removeEventListener('mousedown', this.handleDocumentClick);
  }

  handleDocumentClick = (e: Event) => {
    if (this.rootRef && !this.rootRef.contains(e.target)) {
      this.handleCloseResult();
    }
  }

  handleSearchChange = (e: { target: { value: any } }) => {
    this.props.onChange(e.target.value);
    this.setState({
      searchText: e.target.value,
    });
  }

  handleSearchFocus = (searchHasFocus: boolean) => {
    this.setState({
      searchHasFocus,
    });
  }

  handleSubmit = (e: Event) => {
    e.preventDefault();
    this.props.onChange(this.state.searchText);
  }

  handleClick = (value: any) => () => {
    const { onClickResult } = this.props;
    onClickResult(value);
    this.handleCloseResult();
  }

  handleClear = () => {
    this.props.onChange('');
    this.setState({
      searchText: '',
    });
  }

  handleOpenResult = () => {
    this.setState({ resultIsOpen: true });
  }

  handleCloseResult = () => {
    this.setState({ resultIsOpen: false });
  }                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                  

  resultRenderer = () => {
    const { result } = this.props;
    return (
      <div className='omni-search__result'>
        {
          result.map((value, index) => (
            <ResultItem key={index} onClickItem={this.handleClick} value={value}/>
          ))
        }
      </div>
    );
  }

  render() {
    const { searchHasFocus, searchText, resultIsOpen } = this.state;
    const inputClasses = cn({
      'omni-search__input': true,
      'omni-search__input_focused': searchHasFocus,
    });

    return (
      // eslint-disable-next-line no-return-assign
      <div ref={(el) => this.rootRef = el} className='omni-ui-general omni-search'>
        <form onSubmit={this.handleSubmit}>
          <Icon name='search' className='omni-search__search-icon' />
          <input
            type='text'
            value={searchText}
            className={inputClasses}
            placeholder='Поиск'
            onChange={this.handleSearchChange}
            onFocus={() => this.handleSearchFocus(true)}
            onBlur={() => this.handleSearchFocus(false)}
          />
          {searchText && <Icon
            onClick={this.handleClear}
            className='omni-search__clear-icon'
            name='clear' 
          />}
        </form>
          {resultIsOpen && this.resultRenderer()}
      </div>
    );
  }
}
