import React from "react";

export interface INavbarCollapseProps {
  children?: React.ReactNode | React.ReactNode[];
  className?: string;
  isOpen: boolean;
  overflow?: string;
}

class NavbarCollapse extends React.PureComponent<INavbarCollapseProps> {
  private contentRef: React.RefObject<HTMLDivElement>;

  constructor(props: INavbarCollapseProps) {
    super(props);
    this.contentRef = React.createRef();

    this.state = {
      height: props.isOpen ? "auto" : "0",
      overflow: this.props.overflow ? this.props.overflow : "hidden"
    };
  }

  componentDidUpdate(prevProps: INavbarCollapseProps) {
    if ((this.props.isOpen && !prevProps.isOpen) || (!this.props.isOpen && prevProps.isOpen)) {
      this.setState({
        height: `${this.getHeight()}px`
      });
    }

    if (!this.props.isOpen && prevProps.isOpen) {
      window.requestAnimationFrame(() => {
        // "pausing" the JavaScript execution to let the rendering threads catch up
        // http://stackoverflow.com/questions/779379/why-is-settimeoutfn-0-sometimes-useful
        setTimeout(() => {
          this.setState({
            height: "0px"
          });
        });
      });
    }
  }

  onTransitionEnd = (e: React.TransitionEvent<HTMLDivElement>) => {
    const { isOpen } = this.props;

    if (e && e.currentTarget === this.contentRef.current && e.propertyName === "height") {
      if (isOpen) {
        this.setExpanded();
      }
    }
  };

  getHeight = () => {
    return this.contentRef.current?.scrollHeight;
  };

  setExpanded = () => {
    this.setState({
      height: "auto"
    });
  };

  render() {
    const { className, children, isOpen, ...props } = this.props;
    return (
      <div
        ref={this.contentRef}
        className={`collapsible-container ${className}`}
        style={this.state}
        onTransitionEnd={this.onTransitionEnd}
        {...props}
      >
        {children}
      </div>
    );
  }
}

export default NavbarCollapse;
