import _objectWithoutPropertiesLoose from "@babel/runtime/helpers/esm/objectWithoutPropertiesLoose";
import _extends from "@babel/runtime/helpers/esm/extends";
import React, { useState, useImperativeHandle, useRef, useCallback } from 'react';
import { render, unmountComponentAtNode } from 'react-dom';
import PropTypes from 'prop-types';
import kebabCase from 'lodash/kebabCase';
import Transition from '../Animation/Transition';
import { useClassNames, guid, createChainedFunction } from '../utils';
var defaultProps = {
  as: 'div',
  classPrefix: 'toast-container',
  placement: 'topCenter'
};

var useMessages = function useMessages() {
  var _useState = useState([]),
      messages = _useState[0],
      setMessages = _useState[1];

  var getKey = useCallback(function (key) {
    if (typeof key === 'undefined' && messages.length) {
      key = messages[messages.length - 1].key;
    }

    return key;
  }, [messages]);
  var push = useCallback(function (message) {
    var key = guid();
    setMessages([].concat(messages, [{
      key: key,
      visible: true,
      node: message
    }]));
    return key;
  }, [messages]);
  var clear = useCallback(function () {
    // Set all existing messages to be invisible.
    setMessages(messages.map(function (msg) {
      return _extends({}, msg, {
        visible: false
      });
    })); // Remove all invisible messages after 400ms.
    // The delay removal here is to preserve the animation.

    setTimeout(function () {
      setMessages([]);
    }, 400);
  }, [messages]);
  var remove = useCallback(function (key) {
    // Set the message of the specified key to invisible.
    setMessages(messages.map(function (n) {
      if (n.key === getKey(key)) {
        n.visible = false;
      }

      return n;
    })); // Remove invisible messages after 400ms.

    setTimeout(function () {
      setMessages(messages.filter(function (msg) {
        return msg.visible;
      }));
    }, 400);
  }, [messages, getKey]);
  return {
    messages: messages,
    push: push,
    clear: clear,
    remove: remove
  };
};

var ToastContainer = /*#__PURE__*/React.forwardRef(function (props, ref) {
  var rootRef = useRef();

  var Component = props.as,
      className = props.className,
      classPrefix = props.classPrefix,
      placement = props.placement,
      rest = _objectWithoutPropertiesLoose(props, ["as", "className", "classPrefix", "placement"]);

  var _useClassNames = useClassNames(classPrefix),
      withClassPrefix = _useClassNames.withClassPrefix,
      merge = _useClassNames.merge,
      rootPrefix = _useClassNames.rootPrefix;

  var classes = merge(className, withClassPrefix(kebabCase(placement)));

  var _useMessages = useMessages(),
      push = _useMessages.push,
      clear = _useMessages.clear,
      remove = _useMessages.remove,
      messages = _useMessages.messages;

  useImperativeHandle(ref, function () {
    return {
      root: rootRef.current,
      push: push,
      clear: clear,
      remove: remove
    };
  });
  var elements = messages.map(function (item) {
    return /*#__PURE__*/React.createElement(Transition, {
      key: item.key,
      in: item.visible,
      exitedClassName: rootPrefix('toast-fade-exited'),
      exitingClassName: rootPrefix('toast-fade-exiting'),
      enteringClassName: rootPrefix('toast-fade-entering'),
      enteredClassName: rootPrefix('toast-fade-entered'),
      timeout: 300
    }, function (transitionProps, ref) {
      var _item$node, _item$node$props, _item$node2, _item$node2$props;

      var transitionClassName = transitionProps.className,
          rest = _objectWithoutPropertiesLoose(transitionProps, ["className"]);

      return /*#__PURE__*/React.cloneElement(item.node, _extends({}, rest, {
        ref: ref,
        // Remove the message after the specified time.
        onClose: createChainedFunction((_item$node = item.node) === null || _item$node === void 0 ? void 0 : (_item$node$props = _item$node.props) === null || _item$node$props === void 0 ? void 0 : _item$node$props.onClose, function () {
          return remove(item.key);
        }),
        className: merge(rootPrefix('toast'), (_item$node2 = item.node) === null || _item$node2 === void 0 ? void 0 : (_item$node2$props = _item$node2.props) === null || _item$node2$props === void 0 ? void 0 : _item$node2$props.className, transitionClassName)
      }));
    });
  });
  return /*#__PURE__*/React.createElement(Component, _extends({}, rest, {
    ref: rootRef,
    className: classes
  }), elements);
});

ToastContainer.getInstance = function (props) {
  var container = props.container,
      rest = _objectWithoutPropertiesLoose(props, ["container"]);

  var containerRef = /*#__PURE__*/React.createRef();
  var mountElement = document.createElement('div');
  var containerElement = typeof container === 'function' ? container() : container; //  Parent is document.body or the existing dom element

  var parentElement = containerElement || document.body; // Add the detached element to the parent

  parentElement.appendChild(mountElement);

  function destroy() {
    unmountComponentAtNode(mountElement);
    parentElement.removeChild(mountElement);
  }

  render( /*#__PURE__*/React.createElement(ToastContainer, _extends({}, rest, {
    ref: containerRef
  })), mountElement);
  return [containerRef, destroy];
};

ToastContainer.displayName = 'ToastContainer';
ToastContainer.defaultProps = defaultProps;
ToastContainer.propTypes = {
  className: PropTypes.string,
  classPrefix: PropTypes.string,
  duration: PropTypes.number,
  placement: PropTypes.elementType,
  container: PropTypes.oneOfType([PropTypes.node, PropTypes.func])
};
export default ToastContainer;