import _set from "lodash/fp/set";
import _reduce from "lodash/fp/reduce";
import _pipe from "lodash/fp/pipe";
import _values from "lodash/fp/values";
import _identity from "lodash/fp/identity";
import _negate from "lodash/fp/negate";
import _some from "lodash/fp/some";
import _pickBy from "lodash/fp/pickBy";
import _noop from "lodash/fp/noop";
import _isString from "lodash/fp/isString";
import _isNil from "lodash/fp/isNil";
import _isArray from "lodash/fp/isArray";
import _includes from "lodash/fp/includes";
import _get from "lodash/fp/get";
import _getOr from "lodash/fp/getOr";
import _every from "lodash/fp/every";
import _assign from "lodash/fp/assign";
import React from 'react';
import PropTypes from 'prop-types';
import Animation from '../animation';
import Transition from '../transition';
const AnimationAdapter = ({
  animated,
  onAnimationEnd = _noop,
  name,
  children
}) => {
  return React.Children.map(children, child => /*#__PURE__*/React.cloneElement(child, {
    animated,
    onAnimationEnd: () => onAnimationEnd(name)
  }));
};
AnimationAdapter.propTypes = process.env.NODE_ENV !== "production" ? {
  name: PropTypes.string.isRequired,
  onAnimationEnd: PropTypes.func,
  animated: PropTypes.bool
} : {};
const pickByWithKey = _pickBy.convert({
  cap: true
});
const walker = (type, handler) => children => {
  return React.Children.map(children, (child, index) => {
    if (_isNil(child) || _isString(child)) return child;
    const newChild = child.type === type ? handler(child) : child;
    if (React.Children.count(newChild.props.children) === 0) return newChild;
    return /*#__PURE__*/React.cloneElement(newChild, {}, walker(type, handler)(newChild.props.children));
  });
};
const reduceChildren = fun => acc => children => {
  let newAcc = acc;
  React.Children.map(children, child => {
    newAcc = fun(newAcc, child);
    return child;
  });
  return newAcc;
};
const getAnimationNames = reduceChildren((acc, child) => {
  if (_isString(child)) return acc;
  const {
    type,
    props: {
      children
    }
  } = child;
  if (Animation !== type && Transition !== type && AnimationAdapter !== type) return [...acc, ...getAnimationNames(children)];
  const {
    props: {
      name
    }
  } = child;
  return [name, ...acc, ...getAnimationNames(children)];
})([]);
const mergeAnimationStates = (animations, children) => {
  const names = getAnimationNames(children);
  return _pipe(pickByWithKey((value, key) => _includes(key, names)), _assign(_reduce((acc, name) => _set(name, false, acc), {}, names)))(animations);
};
class AnimationScheduler extends React.Component {
  static getDerivedStateFromProps(props, state) {
    const {
      children
    } = props;
    const {
      animations
    } = state;
    return {
      animations: mergeAnimationStates(animations, children)
    };
  }
  constructor(props) {
    super(props);
    const {
      children
    } = props;
    this.state = {
      animations: mergeAnimationStates({}, children)
    };
  }
  isAnimated(after) {
    if (_isNil(after)) return true;
    const {
      animations
    } = this.state;
    const isAnimated = _every(name => _getOr(false, name, animations), _isArray(after) ? after : [after]);
    return isAnimated;
  }
  handlerAnimationEnd(name) {
    this.setState(_set(['animations', name], true), () => {
      const hasPendingAnimation = _pipe(_get('state.animations'), _values, _some(_negate(_identity)))(this);
      const {
        onAnimationEnd = _noop
      } = this.props;
      if (!hasPendingAnimation) return onAnimationEnd();
    });
  }
  processAnimation(child) {
    const {
      animated: parentAnimated
    } = this.props;
    const {
      animated,
      onAnimationEnd = _noop,
      after
    } = child.props;
    return /*#__PURE__*/React.cloneElement(child, {
      animated: parentAnimated ? this.isAnimated(after) || animated : animated,
      onAnimationEnd: name => {
        this.handlerAnimationEnd(name);
        return onAnimationEnd(name);
      }
    });
  }
  render() {
    const {
      children
    } = this.props;
    return _pipe(walker(Animation, this.processAnimation.bind(this)), walker(Transition, this.processAnimation.bind(this)), walker(AnimationAdapter, this.processAnimation.bind(this)))(children);
  }
}
AnimationScheduler.propTypes = process.env.NODE_ENV !== "production" ? {
  onAnimationEnd: PropTypes.func,
  animated: PropTypes.bool,
  children: PropTypes.node
} : {};
export default AnimationScheduler;
export { AnimationAdapter };
//# sourceMappingURL=index.js.map