import React from 'react';
import ReactDOM from 'react-dom';
import PropTypes from 'prop-types';

import '../base';
import { visualProvided } from '../atoms/VisualProvider';
import styles from './Toolbar.Filter.styl';
import IconButton from '../atoms/IconButton';
import FilterBox from './Toolbar.FilterBox';
import FilterDropdown from './FilterDropdown';
import FilterTextField from './FilterTextfield';
import FilterDatepickerRange from './FilterDatepickerRange';
import MultiSelectGroup from '../atoms/MultiSelectGroup';

const CLICK_HANDLED_FLAG = 'HANDLED_IN_TOOLBAR_FILTER';

class ToolbarFilter extends React.Component {
  constructor(props) {
    super(props);
    const open = props.open || false;
    this.state = { open, activeFilters: [] };

    this.toggleOpen = this.toggleOpen.bind(this);
    this.setFilterActive = this.setFilterActive.bind(this);
    this.handleClickOutsideFilterBox = this.handleClickOutsideFilterBox.bind(this);
  }

  getChildContext() {
    return {
      setFilterActive: this.setFilterActive
    };
  }

  componentDidMount() {
    this.renderFilterBox();
  }

  componentWillReceiveProps(newProps, newState, newContext) {
    if (!newContext || !newContext.filterBoxNode) {
      this.unmountFilters();
    }
  }

  componentDidUpdate() {
    this.renderFilterBox();
  }

  componentWillUnmount() {
    this.unmountFilters();
  }

  setFilterActive(changedFilter, active) {
    // Use setState in functional mode to ensure we do not modify a stale `this.state.activeFilters`
    // if `setFilterActive()` is called multiple times in a short timespan.
    this.setState(({ activeFilters, open }) => {
      const newActiveFilters = activeFilters.filter((filter) => filter !== changedFilter);
      if (active) {
        newActiveFilters.push(changedFilter);
      }
      // If the filters change, the filter menu should always be open.
      const newOpen = (activeFilters.length !== newActiveFilters.length) ? true : open;
      return {
        activeFilters: newActiveFilters,
        open: newOpen
      };
    });
  }

  active() {
    return !!this.state.activeFilters.length;
  }

  handleClickOutsideFilterBox(e) {
    if (this.state.open && !this.active()) {
      this.setState({ open: false });
      // If the user clicks on the filter button itself, this handler will fire follow by `toggleOpen()`.
      // Mark the event so we don't immediately open again when `toggleOpen()` is triggered.
      // If the user clicks some other interface element (for instance the Search button), only this function will fire.
      // Using `e.stopPropagation()` here would prevent this event from bubbling to this other component, so it is not used.
      e[CLICK_HANDLED_FLAG] = true; // eslint-disable-line no-param-reassign
    }
  }

  unmountFilters() {
    if (this.context && this.context.filterBoxNode) {
      ReactDOM.unmountComponentAtNode(this.context.filterBoxNode);
    }
  }

  toggleOpen(e) {
    if (e.nativeEvent[CLICK_HANDLED_FLAG]) return;
    this.setState({ open: !this.state.open });
  }

  renderFilterBox() {
    if (this.context.filterBoxNode) {
      // I'm forgoing the use of a Collapsible component here,
      // because placing collapsibles inside other collapsibles does not work.
      // I.E.: The height of the outer collapsible is not recalculated when the inner collapsible activates.
      ReactDOM.unstable_renderSubtreeIntoContainer(
        this,
        <FilterBox
          open={this.state.open}
          handleClickOutside={this.handleClickOutsideFilterBox}
        >
          {this.props.children}
        </FilterBox>,
        this.context.filterBoxNode
      );
    }
  }

  render() {
    const { t } = this.props;
    const { open } = this.state;

    return (
      <IconButton
        icon="doka-icon-filter"
        className={open ? styles.buttonActive : ''}
        active={!open && this.active()}
        onClick={this.toggleOpen}
      >
        {t('toolbarFilterToggleLabel')}
      </IconButton>
    );
  }

}

ToolbarFilter.contextTypes = {
  // eslint-disable-next-line react/forbid-prop-types
  filterBoxNode: PropTypes.any
};

ToolbarFilter.childContextTypes = {
  // The `setFilterActive` function can be used by FilterDropdown dropdowns to mark themselves as active.
  // It is necessary for the Toolbar.Filter component to figure out whether it should show itself as active.
  setFilterActive: PropTypes.func
};

const ExtendedToolbarFilter = visualProvided(ToolbarFilter);

export default ExtendedToolbarFilter;

ExtendedToolbarFilter.Group = MultiSelectGroup;
ExtendedToolbarFilter.Dropdown = FilterDropdown;
ExtendedToolbarFilter.Textfield = FilterTextField;
ExtendedToolbarFilter.DatepickerRange = FilterDatepickerRange;
