import { TIPTAP_CAPTION_TYPE, TIPTAP_FIGURE_TYPE } from "./../../ricos-content/index.js";
import { activateCaption } from "./../../_shared/figure/activate-caption.js";
import { findParentNodeClosestToPos, isMacOS } from "./../../tiptap/index.js";
import { Fragment, Slice } from "./../../tiptap/pm/model.js";
import { NodeSelection, TextSelection } from "./../../tiptap/pm/state.js";
import generalStyles from "./../../editor-common/statics/styles/general-scss.js";
import { createRicosNodeExtension } from "./../../plugin-commons/index.js";
import { findNodeById } from "./../../tiptap-editor/helpers/index.js";
import { Figure } from "./figure.js";
const figureTiptapExtension = createRicosNodeExtension({
  type: "react-node",
  name: TIPTAP_FIGURE_TYPE,
  groups: ["custom-styles", "shortcuts-enabled"],
  reconfigure: (config, _extensions, _props, settings, services) => ({
    ...config,
    addOptions: () => ({
      services,
      ...settings
    })
  }),
  Component: Figure,
  renderingOptions: {
    onDragStart({ editor, dragHandle, event }) {
      if (!this.dom || !dragHandle) {
        return;
      }
      if (this.dom === dragHandle) {
        this.dom.classList.add(generalStyles.dragImageView);
        event.dataTransfer?.setDragImage(this.dom, 0, 0);
        setTimeout(() => {
          this.dom?.classList.remove(generalStyles.dragImageView);
        }, 0);
      } else {
        const figure = this.dom.querySelector("figure");
        if (!figure) {
          console.error("figure element not found");
          return;
        }
        const domBox = figure.getBoundingClientRect();
        const handleBox = dragHandle.getBoundingClientRect();
        const nativeEvent = "nativeEvent" in event ? event.nativeEvent : event;
        const x = handleBox.x - domBox.x + nativeEvent.offsetX;
        const y = handleBox.y - domBox.y + nativeEvent.offsetY;
        figure.classList.add(generalStyles.dragImageView);
        event.dataTransfer?.setDragImage(figure, x, y);
        setTimeout(() => {
          figure.classList.remove(generalStyles.dragImageView);
        }, 0);
      }
      const selection = NodeSelection.create(editor.view.state.tr.doc, this.getPos());
      const transaction = editor.view.state.tr.setSelection(selection);
      editor.view.dispatch(transaction);
    }
  },
  createExtensionConfig({ Plugin, PluginKey }) {
    return {
      name: this.name,
      group: "block smartBlockCellContent layoutCellContent collapsibleListItemBodyContent tableCellContent listItemFirstChildContent listItemSecondChildContent",
      selectable: true,
      draggable: true,
      content: "figureFirstChildContent figureSecondChildContent",
      priority: 105,
      parseHTML() {
        return [
          {
            tag: "figure"
          }
        ];
      },
      renderHTML({ HTMLAttributes }) {
        return ["figure", HTMLAttributes, 0];
      },
      addProseMirrorPlugins() {
        return [
          new Plugin({
            key: new PluginKey("remove-invalid-figures"),
            appendTransaction(transactions, oldState, newState) {
              const docChanged = transactions.some((transaction) => transaction.docChanged) && !oldState.doc.eq(newState.doc);
              if (!docChanged) {
                return;
              }
              const tr = newState.tr;
              const nodesToRemove = [];
              tr.doc.descendants((node, pos) => {
                if (node.type.name === TIPTAP_FIGURE_TYPE && node.firstChild?.attrs.id === null && !node.firstChild?.attrs.loading) {
                  nodesToRemove.push({ pos, nodeSize: node.nodeSize });
                }
              });
              if (nodesToRemove.length === 0) {
                return;
              }
              nodesToRemove.reverse().forEach(({ pos, nodeSize }) => {
                tr.delete(pos, pos + nodeSize);
              });
              tr.setMeta("remove-invalid-figure", true);
              return tr;
            }
          }),
          new Plugin({
            key: new PluginKey("figure-selection-listener"),
            // modifies selection to select whole figure when selection includes caption and any other node
            appendTransaction(_, __, newState) {
              const { tr, selection } = newState;
              const { $anchor, $head } = selection;
              if (!(selection instanceof TextSelection) || selection.$anchor.node().attrs.id === selection.$head.node().attrs.id || selection.anchor === selection.head) {
                return void 0;
              }
              const isAnchorCaption = $anchor.node().type.name === TIPTAP_CAPTION_TYPE;
              const isHeadCaption = $head.node().type.name === TIPTAP_CAPTION_TYPE;
              if (isAnchorCaption || isHeadCaption) {
                const $anchor2 = selection.$anchor;
                const $head2 = selection.$head;
                if (isHeadCaption && !isAnchorCaption && selection.head === selection.to) {
                  return tr.setSelection(
                    TextSelection.create(tr.doc, $anchor2.pos, $head2.end() + 2)
                  );
                }
                if (isHeadCaption && !isAnchorCaption && selection.from === selection.head) {
                  return tr.setSelection(
                    TextSelection.create(tr.doc, $anchor2.pos, $head2.before() - 2)
                  );
                }
                if (isAnchorCaption && !isHeadCaption && $anchor2.pos > $head2.pos) {
                  return tr.setSelection(
                    TextSelection.create(tr.doc, $anchor2.end() + 2, $head2.pos)
                  );
                }
                if (isAnchorCaption && !isHeadCaption && $anchor2.pos < $head2.pos) {
                  return tr.setSelection(
                    TextSelection.create(tr.doc, $anchor2.start() - 3, $head2.pos)
                  );
                }
              }
              return void 0;
            },
            props: {
              /*
               * On Mobile Web Android, every interaction is treated as a composition event.
               * To prevent undesired selection behavior when the user tries to select a child node of a figure,
               * we intercept these events and handle them appropriately.
               */
              handleDOMEvents: {
                compositionstart: (view, event) => {
                  if (view.state.selection instanceof NodeSelection && view.state.selection.node?.type.spec.group?.includes("figure")) {
                    event.preventDefault();
                  }
                },
                compositionupdate: (view, event) => {
                  if (view.state.selection instanceof NodeSelection && view.state.selection.node?.type.spec.group?.includes("figure")) {
                    event.preventDefault();
                  }
                }
              },
              handleKeyDown(view, event) {
                const mods = getMods(event);
                const backSpace = event.key === "Backspace";
                const arrowLeft = event.key === "ArrowLeft";
                const arrowRight = event.key === "ArrowRight";
                const arrowUp = event.key === "ArrowUp";
                const arrowDown = event.key === "ArrowDown";
                const deleteKey = event.key === "Delete";
                const ctrlP = isMacOS() && event.key.toLowerCase() === "p" && mods === "c";
                const ctrlN = isMacOS() && event.key.toLowerCase() === "n" && mods === "c";
                if (view.state.selection.content().size > 2) {
                  return;
                }
                if (backSpace || arrowLeft || arrowUp || ctrlP) {
                  const checkEndOfTextBlock = backSpace || arrowLeft;
                  const { node, pos } = findSelectableNodeBackward(view, checkEndOfTextBlock) || {};
                  if (node?.type.name === TIPTAP_FIGURE_TYPE && node?.lastChild?.textContent === "" && pos !== void 0) {
                    view.dispatch(
                      view.state.tr.setSelection(NodeSelection.create(view.state.doc, pos + 1)).scrollIntoView()
                    );
                    return true;
                  }
                }
                if ((arrowUp || ctrlP) && view.state.selection.$anchor.node().type.name === TIPTAP_CAPTION_TYPE) {
                  const parent = findParentNodeClosestToPos(
                    view.state.selection.$anchor,
                    (node) => node?.type?.name === TIPTAP_FIGURE_TYPE
                  );
                  if (!parent) {
                    return;
                  }
                  view.dispatch(
                    view.state.tr.setSelection(NodeSelection.create(view.state.doc, parent.pos + 1)).scrollIntoView()
                  );
                  return true;
                }
                if ((arrowDown || ctrlN || arrowRight) && view.state.selection instanceof NodeSelection) {
                  const parent = findParentNodeClosestToPos(
                    view.state.selection.$anchor,
                    (node) => node?.type?.name === TIPTAP_FIGURE_TYPE
                  );
                  if (parent && view.state.selection.$anchor.index() === 0) {
                    const captionNode = parent.node.lastChild;
                    const captionHasContent = !!captionNode?.content?.size;
                    const captionIsVisible = captionHasContent || !!captionNode?.attrs?.showEmpty;
                    if (!captionIsVisible) {
                      const afterFigurePos = parent.pos + parent.node.nodeSize;
                      view.dispatch(
                        view.state.tr.setSelection(
                          TextSelection.create(
                            view.state.doc,
                            afterFigurePos - 1,
                            afterFigurePos - 1
                          )
                        ).scrollIntoView()
                      );
                      return false;
                    }
                    return activateCaption(view, captionNode.attrs.id);
                  }
                }
                if (backSpace && view.state.selection.$anchor.node().type.name === TIPTAP_CAPTION_TYPE && view.state.selection.empty && view.state.selection.$anchor.pos === view.state.selection.$anchor.start()) {
                  const parent = findParentNodeClosestToPos(
                    view.state.selection.$anchor,
                    (node) => node?.type?.name === TIPTAP_FIGURE_TYPE
                  );
                  if (!parent) {
                    return;
                  }
                  const captionNode = view.state.selection.$anchor.node();
                  const tr = view.state.tr;
                  if (captionNode.attrs.showEmpty) {
                    const captionPos = view.state.selection.$anchor.pos - view.state.selection.$anchor.parentOffset - 1;
                    tr.setNodeAttribute(captionPos, "showEmpty", false);
                  }
                  tr.setSelection(NodeSelection.create(tr.doc, parent.pos + 1)).scrollIntoView();
                  view.dispatch(tr);
                  return true;
                }
                if (deleteKey) {
                  if (view.state.selection.$anchor.parent.type.name === TIPTAP_CAPTION_TYPE) {
                    const captionNode = view.state.selection.$anchor.parent;
                    const isCaptionEmpty = captionNode.content.size === 0;
                    const isAtEndOfCaption = view.state.selection.empty && view.state.selection.$anchor.parentOffset === captionNode.content.size;
                    if (!isCaptionEmpty && !isAtEndOfCaption) {
                      return false;
                    }
                    const parentFigure = findParentNodeClosestToPos(
                      view.state.selection.$anchor,
                      (node) => node?.type?.name === TIPTAP_FIGURE_TYPE
                    );
                    if (parentFigure) {
                      const tr = view.state.tr;
                      if (captionNode.attrs.showEmpty) {
                        const captionPos = view.state.selection.$anchor.pos - view.state.selection.$anchor.parentOffset - 1;
                        tr.setNodeAttribute(captionPos, "showEmpty", false);
                      }
                      tr.setSelection(
                        NodeSelection.create(tr.doc, parentFigure.pos)
                      ).scrollIntoView();
                      view.dispatch(tr);
                      return true;
                    }
                    return false;
                  }
                }
                return false;
              }
            }
          }),
          new Plugin({
            key: new PluginKey("figure-handle-paste"),
            props: {
              transformCopied: (slice, { state }) => {
                const node = slice.content.firstChild;
                if (slice.content.size === 1 && node?.type.spec.group?.includes("figure")) {
                  const childPos = findNodeById(state.tr, node.attrs.id)[0]?.pos;
                  const figureNode = state.doc.resolve(childPos).parent;
                  const newSlice = new Slice(
                    Fragment.from(figureNode),
                    slice.openStart,
                    slice.openEnd
                  );
                  return newSlice;
                }
                return slice;
              },
              transformPastedHTML(html) {
                if (!html.includes("<figure")) {
                  return html;
                }
                const newHtml = document.createElement("div");
                newHtml.innerHTML = html;
                newHtml.querySelectorAll("figure").forEach((figure) => {
                  const child = figure.querySelector(
                    "image-component, video-component, gif-component"
                  );
                  if (!child) {
                    figure.remove();
                  }
                });
                return newHtml.innerHTML;
              }
            }
          })
        ];
      },
      // TODO: move to createShortcut after fixing keymap-override
      addKeyboardShortcuts() {
        return {
          Enter: () => {
            const { state } = this.editor;
            const selection = state.selection;
            if (!(selection instanceof NodeSelection)) {
              return false;
            }
            const selectedNode = selection.node;
            let figureNode = selectedNode;
            if (selectedNode.type.name !== TIPTAP_FIGURE_TYPE) {
              const parentFigure = findParentNodeClosestToPos(
                selection.$from,
                (node) => node.type.name === TIPTAP_FIGURE_TYPE
              );
              if (!parentFigure) {
                return false;
              }
              figureNode = parentFigure.node;
            }
            const captionNode = figureNode.lastChild;
            const captionHasContent = captionNode && captionNode.content.size > 0;
            const captionIsVisible = captionNode && captionNode.attrs?.showEmpty;
            if (captionHasContent || captionIsVisible || !captionNode?.attrs?.id) {
              return false;
            }
            return activateCaption(this.editor.view, captionNode.attrs.id);
          }
        };
      }
    };
  }
});
function getMods(event) {
  let result = "";
  if (event.ctrlKey) {
    result += "c";
  }
  if (event.metaKey) {
    result += "m";
  }
  if (event.altKey) {
    result += "a";
  }
  if (event.shiftKey) {
    result += "s";
  }
  return result;
}
const findSelectableNodeBackward = (view, checkEndOfTextBlock) => {
  const { $head } = view.state.selection;
  let $cut = $head;
  if ($head.parent.isTextblock) {
    if (checkEndOfTextBlock && !view.endOfTextblock("backward", view.state)) {
      return null;
    }
    $cut = findCutBefore($head);
  }
  const node = $cut ? $cut.nodeBefore : null;
  if (!node || !NodeSelection.isSelectable(node)) {
    return null;
  }
  return { node, pos: $cut.pos - node.nodeSize };
};
const findCutBefore = ($pos) => {
  if (!$pos.parent.type.spec.isolating) {
    for (let i = $pos.depth - 1; i >= 0; i--) {
      if ($pos.index(i) > 0) {
        return $pos.doc.resolve($pos.before(i + 1));
      }
      if ($pos.node(i).type.spec.isolating) {
        break;
      }
    }
  }
  return null;
};
export {
  figureTiptapExtension
};
//# sourceMappingURL=figure-tiptap-extension.js.map
