import _defineProperty from "@babel/runtime/helpers/defineProperty";
var _class4;
import React from 'react';
import PropTypes from 'prop-types';
import { createPortal, unmountComponentAtNode, unstable_renderSubtreeIntoContainer } from 'react-dom';
import { injectIntl, RawIntlProvider, useIntl } from 'react-intl-next';
import { default as AnalyticsReactContext } from '@atlaskit/analytics-next-stable-react-context';
import { ACTION, ACTION_SUBJECT, ACTION_SUBJECT_ID, EVENT_TYPE } from '../../analytics';
import { EventDispatcher } from '../../event-dispatcher';
import IntlProviderIfMissingWrapper from '../IntlProviderIfMissingWrapper';
export class PortalProviderAPI extends EventDispatcher {
  constructor(intl, onAnalyticsEvent, analyticsContext) {
    super();
    _defineProperty(this, "portals", new Map());
    _defineProperty(this, "setContext", context => {
      this.context = context;
    });
    this.intl = intl;
    this.onAnalyticsEvent = onAnalyticsEvent;
    this.useAnalyticsContext = analyticsContext;
  }
  render(children, container, hasAnalyticsContext = false, hasIntlContext = false) {
    this.portals.set(container, {
      children: children,
      hasAnalyticsContext,
      hasIntlContext
    });
    let wrappedChildren = this.useAnalyticsContext ? /*#__PURE__*/React.createElement(AnalyticsContextWrapper, null, children()) : children();
    if (hasIntlContext) {
      wrappedChildren = /*#__PURE__*/React.createElement(RawIntlProvider, {
        value: this.intl
      }, wrappedChildren);
    }
    unstable_renderSubtreeIntoContainer(this.context, wrappedChildren, container);
  }

  // TODO: until https://product-fabric.atlassian.net/browse/ED-5013
  // we (unfortunately) need to re-render to pass down any updated context.
  // selectively do this for nodeviews that opt-in via `hasAnalyticsContext`
  forceUpdate({
    intl
  }) {
    this.intl = intl;
    this.portals.forEach((portal, container) => {
      if (!portal.hasAnalyticsContext && !this.useAnalyticsContext && !portal.hasIntlContext) {
        return;
      }
      let wrappedChildren = portal.children();
      if (portal.hasAnalyticsContext && this.useAnalyticsContext) {
        wrappedChildren = /*#__PURE__*/React.createElement(AnalyticsContextWrapper, null, wrappedChildren);
      }
      if (portal.hasIntlContext) {
        wrappedChildren = /*#__PURE__*/React.createElement(RawIntlProvider, {
          value: this.intl
        }, wrappedChildren);
      }
      unstable_renderSubtreeIntoContainer(this.context, wrappedChildren, container);
    });
  }
  remove(container) {
    this.portals.delete(container);

    // There is a race condition that can happen caused by Prosemirror vs React,
    // where Prosemirror removes the container from the DOM before React gets
    // around to removing the child from the container
    // This will throw a NotFoundError: The node to be removed is not a child of this node
    // Both Prosemirror and React remove the elements asynchronously, and in edge
    // cases Prosemirror beats React
    try {
      unmountComponentAtNode(container);
    } catch (error) {
      if (this.onAnalyticsEvent) {
        this.onAnalyticsEvent({
          payload: {
            action: ACTION.FAILED_TO_UNMOUNT,
            actionSubject: ACTION_SUBJECT.EDITOR,
            actionSubjectId: ACTION_SUBJECT_ID.REACT_NODE_VIEW,
            attributes: {
              error: error,
              domNodes: {
                container: container ? container.className : undefined,
                child: container.firstElementChild ? container.firstElementChild.className : undefined
              }
            },
            eventType: EVENT_TYPE.OPERATIONAL
          }
        });
      }
    }
  }
}
class BasePortalProvider extends React.Component {
  constructor(props) {
    super(props);
    this.portalProviderAPI = new PortalProviderAPI(props.intl, props.onAnalyticsEvent, props.useAnalyticsContext);
  }
  render() {
    return this.props.render(this.portalProviderAPI);
  }
  componentDidUpdate() {
    this.portalProviderAPI.forceUpdate({
      intl: this.props.intl
    });
  }
}
_defineProperty(BasePortalProvider, "displayName", 'PortalProvider');
export const PortalProvider = injectIntl(BasePortalProvider);
export const PortalProviderWithThemeProviders = ({
  onAnalyticsEvent,
  useAnalyticsContext,
  render
}) => /*#__PURE__*/React.createElement(IntlProviderIfMissingWrapper, null, /*#__PURE__*/React.createElement(PortalProviderWithThemeAndIntlProviders, {
  onAnalyticsEvent: onAnalyticsEvent,
  useAnalyticsContext: useAnalyticsContext,
  render: render
}));
const PortalProviderWithThemeAndIntlProviders = ({
  onAnalyticsEvent,
  useAnalyticsContext,
  render
}) => {
  const intl = useIntl();
  return /*#__PURE__*/React.createElement(BasePortalProvider, {
    intl: intl,
    onAnalyticsEvent: onAnalyticsEvent,
    useAnalyticsContext: useAnalyticsContext,
    render: render
  });
};
export class PortalRenderer extends React.Component {
  constructor(props) {
    super(props);
    _defineProperty(this, "handleUpdate", portals => this.setState({
      portals
    }));
    props.portalProviderAPI.setContext(this);
    props.portalProviderAPI.on('update', this.handleUpdate);
    this.state = {
      portals: new Map()
    };
  }
  render() {
    const {
      portals
    } = this.state;
    return /*#__PURE__*/React.createElement(React.Fragment, null, Array.from(portals.entries()).map(([container, children]) => /*#__PURE__*/createPortal(children, container)));
  }
}

/**
 * Wrapper to re-provide modern analytics context to ReactNodeViews.
 */
const dummyAnalyticsContext = {
  getAtlaskitAnalyticsContext() {},
  getAtlaskitAnalyticsEventHandlers() {}
};
const AnalyticsContextWrapper = (_class4 = class AnalyticsContextWrapper extends React.Component {
  render() {
    const {
      value
    } = this.context.contextAdapter.analytics || {
      value: dummyAnalyticsContext
    };
    return /*#__PURE__*/React.createElement(AnalyticsReactContext.Provider, {
      value: value
    }, this.props.children);
  }
}, _defineProperty(_class4, "contextTypes", {
  contextAdapter: PropTypes.object
}), _class4);