import React, { PureComponent } from 'react';
import PropTypes from 'prop-types';
import omit from 'lodash/omit';
import chunk from 'lodash/chunk';
import classNames from 'classnames';
import Collapse from 'react-collapse';

import Item from './Item';
import './collapsible.scss';

const propTypes = {
  className: PropTypes.string,
  children: PropTypes.func.isRequired,
  variant: PropTypes.oneOf(['cards']),
  items: PropTypes.arrayOf(PropTypes.shape({
    id: PropTypes.string.isRequired
  })).isRequired,
  itemRender: PropTypes.func.isRequired,
  columns: PropTypes.oneOf(['12', '11', '10', '9', '8', '7', '6', '5', '4', '3', '2']),
  selectedId: PropTypes.string,
  refId: PropTypes.string,
  component: PropTypes.oneOfType([
    PropTypes.string,
    PropTypes.object,
    PropTypes.func
  ]),
  duration: PropTypes.number,
  withHashTag: PropTypes.bool,
  scrollJump: PropTypes.bool,
  collapse: PropTypes.bool
};

const defaultProps = {
  className: undefined,
  duration: 500,
  component: 'div',
  variant: 'cards',
  columns: '4',
  selectedId: undefined,
  refId: 'id',
  children: null,
  withHashTag: false,
  scrollJump: false,
  collapse: true
};

class Collapsible extends PureComponent {
  state = {
    selectedId: undefined
  };

  handlerClick = item => () => {
    const { refId } = this.props;
    const { selectedId: oldSelectedId } = this.state;
    const id = item[refId];
    const selectedId = typeof this.state.selectedId !== 'undefined' ? this.state.selectedId : this.props.selectedId;
    this.setState({
      selectedId: selectedId !== id ? id : false,
      oldSelectedId
    });
  }

  cardsRender() {
    const { items: initialItems, columns } = this.props;
    const itemJunks = chunk(initialItems, parseInt(columns, 10));
    return itemJunks.reduce((resultArray, items, contentRow) => {
      items.forEach((item, row) => {
        resultArray.push(this.renderCard({ item, row }));
      });
      resultArray.push(this.renderPlainContent({ items, contentRow }));
      return resultArray;
    }, []);
  }

  renderCard({ item, row }) {
    const { itemRender, columns: initialColumns, scrollJump, duration, refId } = this.props;
    const selectedId = typeof this.state.selectedId !== 'undefined' ? this.state.selectedId : this.props.selectedId;
    const columns = parseInt(initialColumns, 10);
    return (
      <Item
        key={item[refId]}
        to={`content-row-${item[refId]}`}
        id={`content-row-${item[refId]}`}
        onClick={this.handlerClick(item)}
        styleName={classNames(`card-${columns}`, { 'last-card': (row + 1) === columns })}
        active={selectedId === item[refId]}
        scrollJump={scrollJump}
        duration={duration}
      >{itemRender(item)}</Item>
    );
  }

  renderPlainContent({ items, contentRow }) {
    const { children, collapse, refId } = this.props;
    const { oldSelectedId } = this.state;
    const selectedId = typeof this.state.selectedId !== 'undefined' ? this.state.selectedId : this.props.selectedId;
    const selectedItem = items.find(item => item[refId] === selectedId);
    const oldSelectedItem = items.find(item => item[refId] === oldSelectedId);

    const ComponentWrapper = collapse ? Collapse : 'div';
    return (
      <div
        styleName="plain-content-wrapper"
        key={`content-row-${contentRow}`}
      >
        {(collapse || !!selectedItem)
        && <ComponentWrapper isOpened={!!selectedItem}>
          <div styleName="plain-content">
            {(selectedItem || oldSelectedItem) && children(selectedItem || oldSelectedItem)}
          </div>
        </ComponentWrapper>}
      </div>
    );
  }

  render() {
    const { component: Component, className, variant, ...rest } = this.props;
    return (
      <Component
        className={className}
        styleName={classNames('base', variant)}
        onClick={this.handleClick}
        {...omit(rest, Object.keys(propTypes))}
      >
        {variant === 'cards' && this.cardsRender()}
      </Component>
    );
  }
}


Collapsible.propTypes = propTypes;
Collapsible.defaultProps = defaultProps;


export default Collapsible;
