import _defineProperty from "@babel/runtime/helpers/defineProperty";
import _extends from "@babel/runtime/helpers/extends";
/* eslint-disable @repo/internal/react/no-class-components */
import React, { Component, useEffect, useLayoutEffect, useRef, useState } from 'react';
import memoizeOne from 'memoize-one';
import { NodeSelection } from '@atlaskit/editor-prosemirror/state';
import { fg } from '@atlaskit/platform-feature-flags';
import { expValEquals } from '@atlaskit/tmp-editor-statsig/exp-val-equals';
import { getExtensionModuleNodePrivateProps, getNodeRenderer } from '../extensions';
import { getExtensionRenderer, nodeToJSON, toJSON } from '../utils';
import Extension from './Extension/Extension';
import { isEmptyBodiedMacro } from './Extension/Extension/extension-utils';
import InlineExtension from './Extension/InlineExtension';
import MultiBodiedExtension from './MultiBodiedExtension';
const getBodiedExtensionContent = node => {
  const bodiedExtensionContent = [];
  node.content.forEach(childNode => {
    bodiedExtensionContent.push(nodeToJSON(childNode));
  });
  return !!bodiedExtensionContent.length ? bodiedExtensionContent : node.attrs.text;
};
export const ExtensionComponent = props => {
  const {
    extensionProvider: extensionProviderResolver,
    showLivePagesBodiedMacrosRendererView,
    node,
    ...restProps
  } = props;
  const [extensionProvider, setExtensionProvider] = useState(undefined);
  const [showBodiedExtensionRendererView, setShowBodiedExtensionRendererView] = useState(!!(showLivePagesBodiedMacrosRendererView !== null && showLivePagesBodiedMacrosRendererView !== void 0 && showLivePagesBodiedMacrosRendererView(nodeToJSON(node))) && !isEmptyBodiedMacro(node));
  const mountedRef = useRef(true);
  useLayoutEffect(() => {
    mountedRef.current = true;
    return () => {
      mountedRef.current = false;
    };
  }, []);
  useEffect(() => {
    extensionProviderResolver === null || extensionProviderResolver === void 0 ? void 0 : extensionProviderResolver.then(provider => {
      if (mountedRef.current) {
        setExtensionProvider(provider);
      }
    });
  }, [extensionProviderResolver]);
  return /*#__PURE__*/React.createElement(ExtensionComponentInner
  // Ignored via go/ees005
  // eslint-disable-next-line react/jsx-props-no-spreading
  , _extends({}, restProps, {
    extensionProvider: extensionProvider,
    node: node,
    showLivePagesBodiedMacrosRendererView: showLivePagesBodiedMacrosRendererView,
    showBodiedExtensionRendererView: showBodiedExtensionRendererView,
    setShowBodiedExtensionRendererView: setShowBodiedExtensionRendererView
  }));
};
class ExtensionComponentInner extends Component {
  constructor(...args) {
    super(...args);
    _defineProperty(this, "privatePropsParsed", false);
    _defineProperty(this, "state", {});
    // memoized to avoid rerender on extension state changes
    _defineProperty(this, "getNodeRenderer", memoizeOne(getNodeRenderer));
    _defineProperty(this, "getExtensionModuleNodePrivateProps", memoizeOne(getExtensionModuleNodePrivateProps));
    _defineProperty(this, "setIsNodeHovered", isHovered => {
      // Don't want to show hover interactions for live page view mode
      if (!this.props.isLivePageViewMode) {
        this.setState({
          isNodeHovered: isHovered
        });
      }
    });
    /**
     * Parses any private nodes once an extension provider is available.
     *
     * We do this separately from resolving a node renderer component since the
     * private props come from extension provider, rather than an extension
     * handler which only handles `render`/component concerns.
     */
    _defineProperty(this, "parsePrivateNodePropsIfNeeded", async () => {
      if (this.privatePropsParsed || !this.props.extensionProvider) {
        return;
      }
      this.privatePropsParsed = true;
      const {
        extensionType,
        extensionKey
      } = this.props.node.attrs;

      /**
       * getExtensionModuleNodePrivateProps can throw if there are issues in the
       * manifest
       */
      try {
        const privateProps = await this.getExtensionModuleNodePrivateProps(this.props.extensionProvider, extensionType, extensionKey);
        this.setState({
          _privateProps: privateProps
        });
      } catch (e) {
        // eslint-disable-next-line no-console
        console.error('Provided extension handler has thrown an error\n', e);
        /** We don't want this error to block renderer */
        /** We keep rendering the default content */
      }
    });
    _defineProperty(this, "handleExtension", (pmNode, actions) => {
      var _pmNode$marks, _pmNode$marks$find, _pmNode$marks$find$at;
      const {
        extensionHandlers,
        editorView,
        showBodiedExtensionRendererView,
        rendererExtensionHandlers
      } = this.props;
      const {
        extensionType,
        extensionKey,
        parameters,
        text
      } = pmNode.attrs;
      const isBodiedExtension = pmNode.type.name === 'bodiedExtension';
      if (isBodiedExtension && !showBodiedExtensionRendererView) {
        return;
      }
      const fragmentLocalId = pmNode === null || pmNode === void 0 ? void 0 : (_pmNode$marks = pmNode.marks) === null || _pmNode$marks === void 0 ? void 0 : (_pmNode$marks$find = _pmNode$marks.find(m => m.type.name === 'fragment')) === null || _pmNode$marks$find === void 0 ? void 0 : (_pmNode$marks$find$at = _pmNode$marks$find.attrs) === null || _pmNode$marks$find$at === void 0 ? void 0 : _pmNode$marks$find$at.localId;
      const content = isBodiedExtension ? getBodiedExtensionContent(pmNode) : text;
      const node = {
        type: pmNode.type.name,
        extensionType,
        extensionKey,
        parameters,
        content,
        localId: pmNode.attrs.localId,
        fragmentLocalId
      };
      if (isBodiedExtension) {
        const rendererExtensionHandler = rendererExtensionHandlers === null || rendererExtensionHandlers === void 0 ? void 0 : rendererExtensionHandlers[extensionType];
        // Forge bodied extensions don't get rendererExtensionHandlers passed in and use extensionHandlerFromProvider from the below logic instead
        if (rendererExtensionHandler) {
          return getExtensionRenderer(rendererExtensionHandler)(node, toJSON(editorView.state.doc));
        }
      }
      let result;
      if (extensionHandlers && extensionHandlers[extensionType]) {
        const render = getExtensionRenderer(extensionHandlers[extensionType]);
        result = render(node, editorView.state.doc, actions);
      }
      if (!result) {
        const extensionHandlerFromProvider = this.props.extensionProvider && this.getNodeRenderer(this.props.extensionProvider, extensionType, extensionKey);
        if (extensionHandlerFromProvider) {
          const NodeRenderer = extensionHandlerFromProvider;
          if (node.type === 'multiBodiedExtension') {
            return /*#__PURE__*/React.createElement(NodeRenderer, {
              node: node,
              references: this.props.references,
              actions: actions
            });
          }
          return /*#__PURE__*/React.createElement(NodeRenderer, {
            node: node,
            references: this.props.references,
            showUnknownMacroPlaceholder: fg('tinymce_display_unknown_macro_body_content')
          });
        }
      }
      return result;
    });
  }
  componentDidUpdate() {
    this.parsePrivateNodePropsIfNeeded();
  }
  render() {
    var _this$state$_privateP2;
    const {
      node,
      handleContentDOMRef,
      editorView,
      references,
      editorAppearance,
      pluginInjectionApi,
      getPos,
      eventDispatcher,
      macroInteractionDesignFeatureFlags,
      extensionProvider,
      showLivePagesBodiedMacrosRendererView,
      showUpdatedLivePages1PBodiedExtensionUI,
      showBodiedExtensionRendererView,
      setShowBodiedExtensionRendererView,
      isLivePageViewMode
    } = this.props;
    const {
      selection
    } = editorView.state;
    const selectedNode = selection instanceof NodeSelection && selection.node;
    const position = typeof getPos === 'function' && getPos();
    const resolvedPosition = position && editorView.state.doc.resolve(position);
    const isNodeNested = !!(resolvedPosition && resolvedPosition.depth > 0);
    if (node.type.name === 'multiBodiedExtension') {
      var _this$state$_privateP;
      const allowBodiedOverride = (_this$state$_privateP = this.state._privateProps) === null || _this$state$_privateP === void 0 ? void 0 : _this$state$_privateP.__allowBodiedOverride;
      return /*#__PURE__*/React.createElement(MultiBodiedExtension, {
        node: node,
        editorView: editorView,
        getPos: getPos,
        handleContentDOMRef: handleContentDOMRef,
        tryExtensionHandler: this.tryExtensionHandler.bind(this),
        eventDispatcher: eventDispatcher,
        pluginInjectionApi: pluginInjectionApi,
        editorAppearance: editorAppearance,
        macroInteractionDesignFeatureFlags: macroInteractionDesignFeatureFlags,
        isNodeSelected: selectedNode === node,
        isNodeNested: isNodeNested,
        isNodeHovered: expValEquals('cc_editor_ttvc_release_bundle_one', 'extensionHoverRefactor', true) ? undefined : this.state.isNodeHovered,
        setIsNodeHovered: expValEquals('cc_editor_ttvc_release_bundle_one', 'extensionHoverRefactor', true) ? undefined : this.setIsNodeHovered,
        isLivePageViewMode: isLivePageViewMode,
        allowBodiedOverride: allowBodiedOverride
      });
    }
    const extensionHandlerResult = this.tryExtensionHandler(undefined);
    switch (node.type.name) {
      case 'extension':
      case 'bodiedExtension':
        return /*#__PURE__*/React.createElement(Extension, {
          node: node,
          getPos: this.props.getPos,
          references: references,
          extensionProvider: extensionProvider,
          handleContentDOMRef: handleContentDOMRef,
          view: editorView,
          editorAppearance: editorAppearance,
          hideFrame: (_this$state$_privateP2 = this.state._privateProps) === null || _this$state$_privateP2 === void 0 ? void 0 : _this$state$_privateP2.__hideFrame,
          pluginInjectionApi: pluginInjectionApi,
          macroInteractionDesignFeatureFlags: macroInteractionDesignFeatureFlags,
          isNodeSelected: selectedNode === node,
          isNodeHovered: expValEquals('cc_editor_ttvc_release_bundle_one', 'extensionHoverRefactor', true) ? undefined : this.state.isNodeHovered,
          isNodeNested: isNodeNested,
          setIsNodeHovered: expValEquals('cc_editor_ttvc_release_bundle_one', 'extensionHoverRefactor', true) ? undefined : this.setIsNodeHovered,
          showLivePagesBodiedMacrosRendererView: !!(showLivePagesBodiedMacrosRendererView !== null && showLivePagesBodiedMacrosRendererView !== void 0 && showLivePagesBodiedMacrosRendererView(nodeToJSON(node))),
          showUpdatedLivePages1PBodiedExtensionUI: !!(showUpdatedLivePages1PBodiedExtensionUI !== null && showUpdatedLivePages1PBodiedExtensionUI !== void 0 && showUpdatedLivePages1PBodiedExtensionUI(nodeToJSON(node))),
          showBodiedExtensionRendererView: showBodiedExtensionRendererView,
          setShowBodiedExtensionRendererView: setShowBodiedExtensionRendererView,
          isLivePageViewMode: isLivePageViewMode
        }, extensionHandlerResult);
      case 'inlineExtension':
        return /*#__PURE__*/React.createElement(InlineExtension, {
          node: node,
          macroInteractionDesignFeatureFlags: macroInteractionDesignFeatureFlags,
          isNodeSelected: selectedNode === node,
          pluginInjectionApi: pluginInjectionApi,
          isNodeHovered: expValEquals('cc_editor_ttvc_release_bundle_one', 'extensionHoverRefactor', true) ? undefined : this.state.isNodeHovered,
          setIsNodeHovered: expValEquals('cc_editor_ttvc_release_bundle_one', 'extensionHoverRefactor', true) ? undefined : this.setIsNodeHovered,
          isLivePageViewMode: isLivePageViewMode
        }, extensionHandlerResult);
      default:
        return null;
    }
  }
  tryExtensionHandler(actions) {
    const {
      node
    } = this.props;
    try {
      const extensionContent = this.handleExtension(node, actions);
      if (extensionContent && /*#__PURE__*/React.isValidElement(extensionContent)) {
        return extensionContent;
      }
    } catch (e) {
      // eslint-disable-next-line no-console
      console.error('Provided extension handler has thrown an error\n', e);
      /** We don't want this error to block renderer */
      /** We keep rendering the default content */
    }
    return null;
  }
}