import React from 'react';
import PropTypes from 'prop-types';
import classNames from 'classnames';

import '../base';
import styles from './Collapsible.styl';
import CollapsibleIcon from './Collapsible.Icon';

export default class Collapsible extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      height: props.open ? 'auto' : 0
    };

    this.setRef = this.setRef.bind(this);
  }

  componentDidMount() {
    this.calculateHeight();
  }

  componentDidUpdate() {
    // The contents of the collapsible can change.
    this.calculateHeight();
  }

  setRef(containerElement) {
    this.containerElement = containerElement;
  }

  calculateHeight() {
    // Additional 2 offsetHeight fixes collapsible height issues.
    const newHeight = this.containerElement.offsetHeight + 2;
    if (this.state.height !== newHeight) this.setState({ height: newHeight });
  }

  render() {
    const { open, children, className, style, transitionDuration, defaultHeight, maxHeight } = this.props;
    const { height } = this.state;

    const classes = classNames({
      [styles.collapsible]: true,
      [className]: className,
      [styles.open]: open
    });

    const finalHeight = open ? defaultHeight || height : '0px';

    const finalStyle = { ...style, ...{ height: finalHeight, transitionDuration, maxHeight } };

    return (
      <div
        className={classes}
        style={finalStyle}
      >
        <div ref={this.setRef}>
          {children}
        </div>
      </div>
    );
  }
}

Collapsible.propTypes = {
  open: PropTypes.bool,
  children: PropTypes.node,
  className: PropTypes.string,
  style: PropTypes.object, // eslint-disable-line react/forbid-prop-types
  transitionDuration: PropTypes.string,
  defaultHeight: PropTypes.number,
  maxHeight: PropTypes.string
};

Collapsible.defaultProps = {
  open: false,
  children: undefined,
  className: undefined,
  style: undefined,
  transitionDuration: undefined,
  defaultHeight: undefined,
  maxHeight: undefined
};

Collapsible.Icon = CollapsibleIcon;
