// @flow
import React from 'react';
import cn from 'classnames';
import { Scrollbars } from 'react-custom-scrollbars';
import Icon from '../icons';

import SelectItem from './selectItem';
import SelectList from './selectList';
import getStrings from './strings';

import type { Option } from './selectItem';
/** Props передаваемые в SelectPanel
  * @property {Array<Option>} options - значения и их отображаемые наименования
  * @property {Array<string>} - выбранные элементы
  * @property {function (selected: any): void} onSelectedChanged - коллбэк, принимающий выбранные
  * элементы
  * @property {boolean} disableSearch - отображать ли строку поиска
  * @property {boolean} hasSelectAll - отображать или нет пункт "Выбрать все".
  * @property {{[string]: string}} overrideStrings - можно указать свои плейсхолдеры.
  * @property {Function} toggleExpanded - коллбэк скрывающий список.
  * @property {boolean} isMulti - включает функционал мультиселекта
  * @property {Function} getDirection - коллбэк получающий размеры элемента и вычисляющий
  * направление выпадения списка.
  * @property {Function} resetState - коллбэк сбрасывающий направление выпадения списка
  * на значение по умолчанию при размонтировании панели.
  * @property {boolean} panelIsDown - направление открытия выпадающего списка
  * @property {number} maxHeight - высота, после превышения которой появится скролл
  */
type SelectPanelProps = {
  options: Array<Option>,
  selected: Array<any>,
  onSelectedChanged: (selected: Array<any>) => void,
  displaySearch?: boolean,
  displayCheckboxes?: Boolean,
  hasSelectAll: boolean,
  overrideStrings?: {[string]: string},
  isMulti?: boolean,
  toggleExpanded: Function,
  getDirection: Function,
  resetState: Function,
  panelIsDown: boolean,
  maxHeight: number,
};

/** State компонента SelectPanel
  * @property {boolean} searchHasFocus - в фокусе или нет строка поиска
  * @property {string} searchString - введенный в строку поиска текст
  */
type SelectPanelState = {
  searchHasFocus: boolean,
  searchText: string,
};

/** Компонент SelectPanel - выводит поисковую строку или строки выбора вариантов */
export default class SelectPanel extends React.Component<SelectPanelProps, SelectPanelState> {
  constructor(props, context) {
    super(props, context);

    this.state = {
      searchHasFocus: false,
      searchText: props.searchText || '',
    };
  }

  panelRef: ?Object

  componentDidMount() {
    if (this.panelRef) {
      const elementSizes = this.panelRef.parentNode.getBoundingClientRect();
      this.props.getDirection(elementSizes);
    }
  }

  componentWillUnmount() {
    this.props.resetState();
  }

  componentDidUpdate(prevProps, prevState) {
    const { searchText } = this.state;
    const propsNotEqual = prevProps.searchText !== this.props.searchText;
    if (propsNotEqual && this.props.searchText !== searchText) {
      /* this.handleSearchChange({ target: { value: this.props.searchText } }); */
      this.setState({ searchText: this.props.searchText });
    }
  }

  selectAll = () => {
    const { onSelectedChanged, options } = this.props;
    const allValues = options.map((o) => o.value);
    onSelectedChanged(allValues);
  }

  selectNone = () => {
    const { onSelectedChanged } = this.props;
    onSelectedChanged([]);
  }

  selectAllChanged = (checked: boolean) => (checked ? this.selectAll() : this.selectNone());

  allAreSelected() {
    const { options, selected } = this.props;
    return options.length === selected.length;
  }

  filteredOptions() {
    const { searchText } = this.state;
    const { options } = this.props;
    const result: Array<Option> = options.filter((item: Option): boolean => {
      const val = item.label.toLowerCase();
      return val.includes(searchText.toLowerCase());
    });
    return result;
  }

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

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

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

  renderSearch = () => {
    const { searchHasFocus, searchText } = this.state;
    const search = cn({
      'omni-select__search': true,
      'omni-select__search_focused': searchHasFocus,
    });
    const { overrideStrings, searchRef } = this.props;

    return (
      <div className='omni-select__search-container'>
        <Icon name='search' className='omni-select__search__icon-search' />
        <input
          className={search}
          placeholder={getStrings('search', overrideStrings)}
          ref={(el) => searchRef(el)}
          type='text'
          value={searchText}
          onChange={this.handleSearchChange}
          onFocus={() => this.handleSearchFocus(true)}
          onBlur={() => this.handleSearchFocus(false)}
        />
        {searchText && <Icon
          onClick={this.handleClear}
          className='omni-select__search__icon-clear'
          name='clear'
        />}
      </div>
    );
  }

  renderSelectAll = () => {
    const { overrideStrings, displayCheckboxes } = this.props;
    const selectAllOption = {
      label: getStrings('selectAll', overrideStrings),
      value: '',
    };
    return <SelectItem
      displayCheckboxes={displayCheckboxes}
      checked={this.allAreSelected()}
      option={selectAllOption}
      onSelectionChanged={this.selectAllChanged}
    />;
  }

  render() {
    // const { searchHasFocus } = this.state;
    const {
      displaySearch,
      hasSelectAll,
      isMulti,
      panelIsDown,
      maxHeight,
    } = this.props;

    return (
      <div
        className='omni-select__select-panel'
        role='listbox'
        // eslint-disable-next-line no-return-assign
        ref={(el) => this.panelRef = el}
      >
        {panelIsDown && displaySearch && this.renderSearch()}
        {panelIsDown && hasSelectAll && isMulti && this.renderSelectAll()}
        <Scrollbars autoHeight autoHeightMax={maxHeight}>
        <SelectList
          {...this.props}
          options={this.filteredOptions()}
        />
        </Scrollbars>
        {!panelIsDown && hasSelectAll && isMulti && this.renderSelectAll()}
        {!panelIsDown && displaySearch && this.renderSearch()}
      </div>
    );
  }
}
