import React, { useState, useRef, useCallback, useEffect } from 'react';
import { classNames } from '../../utilities/css.js';
import styles from './Collapsible.scss.js';

function Collapsible({
  id,
  expandOnPrint,
  open,
  transition = true,
  preventMeasuringOnChildrenUpdate: _preventMeasuringOnChildrenUpdate,
  children,
  onAnimationEnd
}) {
  const [height, setHeight] = useState(0);
  const [isOpen, setIsOpen] = useState(open);
  const [animationState, setAnimationState] = useState('idle');
  const collapsibleContainer = useRef(null);
  const isFullyOpen = animationState === 'idle' && open && isOpen;
  const isFullyClosed = animationState === 'idle' && !open && !isOpen;
  const content = expandOnPrint || !isFullyClosed ? children : null;
  const wrapperClassName = classNames(styles.Collapsible, isFullyClosed && styles.isFullyClosed, expandOnPrint && styles.expandOnPrint);
  const transitionDisabled = isTransitionDisabled(transition);
  const transitionStyles = typeof transition === 'object' && {
    transitionDuration: transition.duration,
    transitionTimingFunction: transition.timingFunction
  };
  const collapsibleStyles = { ...transitionStyles,
    ...{
      maxHeight: isFullyOpen ? 'none' : `${height}px`,
      overflow: isFullyOpen ? 'visible' : 'hidden'
    }
  };
  const handleCompleteAnimation = useCallback(({
    target
  }) => {
    if (target === collapsibleContainer.current) {
      setAnimationState('idle');
      setIsOpen(open);
      onAnimationEnd && onAnimationEnd();
    }
  }, [onAnimationEnd, open]);
  const startAnimation = useCallback(() => {
    if (transitionDisabled) {
      setIsOpen(open);
      setAnimationState('idle');

      if (open && collapsibleContainer.current) {
        setHeight(collapsibleContainer.current.scrollHeight);
      } else {
        setHeight(0);
      }
    } else {
      setAnimationState('measuring');
    }
  }, [open, transitionDisabled]);
  useEffect(() => {
    if (open !== isOpen) {
      startAnimation();
    } // startAnimation should only be fired if the open state changes.
    // eslint-disable-next-line react-hooks/exhaustive-deps

  }, [open, isOpen]);
  useEffect(() => {
    if (!open || !collapsibleContainer.current) return; // If collapsible defaults to open, set an initial height

    setHeight(collapsibleContainer.current.scrollHeight); // eslint-disable-next-line react-hooks/exhaustive-deps
  }, []);
  useEffect(() => {
    if (!collapsibleContainer.current) return;

    switch (animationState) {
      case 'idle':
        break;

      case 'measuring':
        setHeight(collapsibleContainer.current.scrollHeight);
        setAnimationState('animating');
        break;

      case 'animating':
        setHeight(open ? collapsibleContainer.current.scrollHeight : 0);
    }
  }, [animationState, open, isOpen]);
  return /*#__PURE__*/React.createElement("div", {
    id: id,
    style: collapsibleStyles,
    ref: collapsibleContainer,
    className: wrapperClassName,
    onTransitionEnd: handleCompleteAnimation,
    "aria-hidden": !open
  }, content);
}
const zeroDurationRegex = /^0(ms|s)$/;

function isTransitionDisabled(transitionProp) {
  if (typeof transitionProp === 'boolean') {
    return !transitionProp;
  }

  const {
    duration
  } = transitionProp;

  if (duration && zeroDurationRegex.test(duration.trim())) {
    return true;
  }

  return false;
}

export { Collapsible };
