import {
  TIPTAP_CARD_CONTENT_TYPE,
  TIPTAP_CARD_FOOTER_TYPE,
  TIPTAP_CARD_HEADER_TYPE,
  TIPTAP_CARD_TYPE,
  TIPTAP_LAYOUT_TYPE
} from "./../ricos-content/index.js";
import { Node_Type } from "./../ricos-schema/legacy/wix/rich_content/v1/index.js";
import { findParentNode } from "./../tiptap/core/index.js";
import { Fragment } from "./../tiptap/pm/model.js";
import { Selection } from "./../tiptap/pm/state.js";
import { createRicosNodeExtension } from "./../plugin-commons/index.js";
import { findNodeById } from "./../tiptap-editor/helpers/index.js";
import { createCardNodeView } from "./card-node-view.js";
import { createCardNormalizingTransactionPlugin } from "./card-normalizing.js";
import { createCardPastePlugin } from "./card-paste-plugin.js";
import { createCardsApiPlugin } from "./cards-api-plugin.js";
const cardExtension = createRicosNodeExtension({
  name: TIPTAP_CARD_TYPE,
  groups: ["no-trailing-node", "shortcuts-enabled"],
  type: "html-node",
  reconfigure: (config, _extensions, _props, settings, services) => ({
    ...config,
    addOptions() {
      return {
        ...settings,
        _services: services
      };
    }
  }),
  createExtensionConfig() {
    return {
      name: this.name,
      isolating: true,
      group: "block",
      selectable: true,
      draggable: false,
      content: `${TIPTAP_CARD_HEADER_TYPE}? ${TIPTAP_CARD_CONTENT_TYPE} ${TIPTAP_CARD_FOOTER_TYPE}?`,
      addStorage() {
        return {
          activePageFormat: void 0,
          formats: [],
          onPageFormatChange: /* @__PURE__ */ new Set(),
          pendingCardInsertions: [],
          onPendingCardInsertionsChange: /* @__PURE__ */ new Set()
        };
      },
      parseHTML() {
        return [];
      },
      renderHTML() {
        return ["div", 0];
      },
      addNodeView() {
        const services = this.options._services;
        return createCardNodeView({
          renderCardHeader: this.options.renderCardHeader,
          isMobile: services?.context.isMobile,
          getBoundaryWarningPortal: this.options.getBoundaryWarningPortal
        });
      },
      addAttributes: () => ({
        containerData: null,
        background: { default: void 0 },
        backgroundImage: { default: void 0 },
        loading: { default: void 0 }
      }),
      addCommands() {
        return {
          insertCard: () => ({ commands }) => {
            return commands.insertContent({
              type: TIPTAP_CARD_TYPE,
              content: [
                {
                  type: TIPTAP_CARD_CONTENT_TYPE,
                  content: [{ type: "PARAGRAPH" }]
                }
              ]
            });
          },
          addCardAfter: (index) => ({ editor, chain }) => {
            const { doc } = editor.state;
            let cardCount = 0;
            let insertPos = null;
            doc.descendants((node, pos) => {
              if (insertPos !== null) {
                return false;
              }
              if (node.type.name === TIPTAP_CARD_TYPE) {
                if (cardCount === index) {
                  insertPos = pos + node.nodeSize;
                  return false;
                }
                cardCount++;
              }
              return true;
            });
            if (insertPos === null) {
              insertPos = doc.content.size;
            }
            return chain().insertContentAt(insertPos, {
              type: TIPTAP_CARD_TYPE,
              content: [
                {
                  type: TIPTAP_CARD_CONTENT_TYPE,
                  content: [{ type: "PARAGRAPH" }]
                }
              ]
            }).focus().run();
          },
          duplicateCard: (index) => ({ editor, chain }) => {
            const { doc } = editor.state;
            let cardCount = 0;
            let targetPos = null;
            let targetNode = null;
            doc.descendants((node, pos) => {
              if (targetPos !== null) {
                return false;
              }
              if (node.type.name === TIPTAP_CARD_TYPE) {
                if (cardCount === index) {
                  targetPos = pos;
                  targetNode = node;
                  return false;
                }
                cardCount++;
              }
              return true;
            });
            if (targetPos === null || targetNode === null) {
              return false;
            }
            const insertPos = targetPos + targetNode.nodeSize;
            const duplicatedContent = targetNode.toJSON();
            return chain().insertContentAt(insertPos, duplicatedContent).focus().run();
          },
          deleteCard: (index) => ({ editor, chain }) => {
            const { doc } = editor.state;
            let cardCount = 0;
            let targetPos = null;
            let targetNode = null;
            doc.descendants((node, pos) => {
              if (targetPos !== null) {
                return false;
              }
              if (node.type.name === TIPTAP_CARD_TYPE) {
                if (cardCount === index) {
                  targetPos = pos;
                  targetNode = node;
                  return false;
                }
                cardCount++;
              }
              return true;
            });
            if (targetPos === null || targetNode === null) {
              return false;
            }
            const deleteFrom = targetPos;
            const deleteTo = deleteFrom + targetNode.nodeSize;
            return chain().deleteRange({ from: deleteFrom, to: deleteTo }).focus().run();
          },
          moveCard: (fromIndex, toIndex) => ({ state, tr, dispatch, editor }) => {
            if (fromIndex === toIndex) {
              return false;
            }
            const sourceCard = findCardAtIndex(state.doc, fromIndex);
            const targetCard = findCardAtIndex(state.doc, toIndex);
            if (!sourceCard || !targetCard) {
              return false;
            }
            const { node: sourceNode, pos: sourcePos } = sourceCard;
            const insertPos = fromIndex < toIndex ? targetCard.pos + targetCard.node.nodeSize - sourceNode.nodeSize : targetCard.pos;
            tr.delete(sourcePos, sourcePos + sourceNode.nodeSize);
            tr.insert(insertPos, sourceNode);
            if (dispatch) {
              dispatch(tr);
            }
            editor.commands.focus();
            return true;
          },
          selectCard: (index) => ({ editor, tr, dispatch }) => {
            const { doc } = editor.state;
            let cardCount = 0;
            let targetPos = null;
            doc.descendants((node, pos) => {
              if (targetPos !== null) {
                return false;
              }
              if (node.type.name === TIPTAP_CARD_TYPE) {
                if (cardCount === index) {
                  targetPos = pos;
                  return false;
                }
                cardCount++;
              }
              return true;
            });
            if (targetPos === null) {
              return false;
            }
            const $pos = doc.resolve(targetPos + 1);
            const selection = Selection.near($pos);
            if (dispatch) {
              tr.setSelection(selection);
              dispatch(tr);
            }
            if (!editor.isFocused) {
              editor.commands.focus();
            }
            return true;
          },
          splitCard: () => ({ tr, dispatch }) => {
            const $from = tr.selection.$from;
            const pos = $from.pos;
            let cardDepth = -1;
            for (let d = $from.depth; d >= 0; d--) {
              if ($from.node(d).type.name === TIPTAP_CARD_TYPE) {
                cardDepth = d;
                break;
              }
            }
            if (cardDepth < 0) {
              return false;
            }
            const wrapperRedirect = redirectSplitForCardWrapper(tr, $from, cardDepth);
            if (wrapperRedirect) {
              if (dispatch) {
                dispatch(tr.scrollIntoView());
              }
              return true;
            }
            const blockDepth = cardDepth + 2;
            const blockNode = $from.depth >= blockDepth ? $from.node(blockDepth) : null;
            if (blockNode?.isTextblock && $from.depth === blockDepth) {
              const splitDepth = $from.depth - cardDepth + 1;
              if (dispatch) {
                if (!splitCardTransaction(tr, { splitPos: pos, splitDepth })) {
                  return false;
                }
                tr.scrollIntoView();
                dispatch(tr);
              }
              return true;
            }
            const cardStart = $from.start(cardDepth);
            const cardNode = $from.node(cardDepth);
            const splitTarget = getCardSplitTargetAtPos($from, pos, cardDepth);
            if (!splitTarget) {
              const boundaryRedirect = redirectSplitForCardChildBoundary(tr, $from, cardDepth);
              if (boundaryRedirect) {
                if (dispatch) {
                  dispatch(tr.scrollIntoView());
                }
                return true;
              }
              return false;
            }
            const { splitPos } = splitTarget;
            const splitBoundaryRedirect = redirectSplitForCardChildBoundary(
              tr,
              tr.doc.resolve(splitPos),
              cardDepth
            );
            if (splitBoundaryRedirect) {
              if (dispatch) {
                dispatch(tr.scrollIntoView());
              }
              return true;
            }
            const posInCard = splitPos - cardStart;
            if (posInCard <= 0 || posInCard >= cardNode.content.size) {
              return false;
            }
            if (dispatch) {
              if (!splitCardTransaction(tr, splitTarget)) {
                return false;
              }
              tr.scrollIntoView();
              dispatch(tr);
            }
            return true;
          },
          splitCardAtPos: (pos) => ({ tr, dispatch, state }) => {
            const $pos = state.doc.resolve(pos);
            let cardDepth = -1;
            for (let d = $pos.depth; d >= 0; d--) {
              if ($pos.node(d).type.name === TIPTAP_CARD_TYPE) {
                cardDepth = d;
                break;
              }
            }
            if (cardDepth < 0) {
              return false;
            }
            const wrapperRedirect = redirectSplitForCardWrapper(tr, $pos, cardDepth);
            if (wrapperRedirect) {
              if (dispatch) {
                dispatch(tr.scrollIntoView());
              }
              return true;
            }
            const cardStart = $pos.start(cardDepth);
            const cardNode = $pos.node(cardDepth);
            const splitTarget = getCardSplitTargetAtPos($pos, pos, cardDepth);
            if (!splitTarget) {
              const boundaryRedirect2 = redirectSplitForCardChildBoundary(tr, $pos, cardDepth);
              if (boundaryRedirect2) {
                if (dispatch) {
                  dispatch(tr.scrollIntoView());
                }
                return true;
              }
              return false;
            }
            const { splitPos } = splitTarget;
            const boundaryRedirect = redirectSplitForCardChildBoundary(
              tr,
              tr.doc.resolve(splitPos),
              cardDepth
            );
            if (boundaryRedirect) {
              if (dispatch) {
                dispatch(tr.scrollIntoView());
              }
              return true;
            }
            const posInCard = splitPos - cardStart;
            if (posInCard <= 0 || posInCard >= cardNode.content.size) {
              return false;
            }
            if (dispatch) {
              if (!splitCardTransaction(tr, splitTarget)) {
                return false;
              }
              tr.scrollIntoView();
              dispatch(tr);
            }
            return true;
          },
          mergeCardWithNext: (cardIndex) => ({ state, dispatch }) => {
            const target = findCardAtIndex(state.doc, cardIndex);
            if (!target) {
              return false;
            }
            const { node: targetNode, pos: targetPos } = target;
            const nextCardPos = targetPos + targetNode.nodeSize;
            const nextNode = state.doc.nodeAt(nextCardPos);
            if (!nextNode || nextNode.type.name !== TIPTAP_CARD_TYPE) {
              return false;
            }
            if (!dispatch) {
              return true;
            }
            const tr = state.tr;
            demoteCardWrapper(tr, nextNode.attrs.id, TIPTAP_CARD_HEADER_TYPE, "start");
            demoteCardWrapper(tr, targetNode.attrs.id, TIPTAP_CARD_FOOTER_TYPE, "end");
            const mappedNextCardPos = tr.mapping.map(nextCardPos);
            dispatch(tr.join(mappedNextCardPos, 2).scrollIntoView());
            return true;
          }
        };
      },
      addKeyboardShortcuts() {
        return {
          Backspace: () => {
            const { state } = this.editor;
            const { selection } = state;
            if (selection.empty && selection.$from.parentOffset === 0) {
              const detached = detachEmptyBannerOnBackspace(this.editor);
              if (detached) {
                return true;
              }
            }
            const cardNode = findParentNode((node2) => node2.type.name === TIPTAP_CARD_TYPE)(selection);
            if (!cardNode) {
              return false;
            }
            const { node } = cardNode;
            const cardContent = node.firstChild;
            const isEmptyCard = node.childCount === 1 && cardContent?.type.name === TIPTAP_CARD_CONTENT_TYPE && cardContent.childCount === 1 && cardContent.firstChild?.isTextblock && cardContent.firstChild.content.size === 0;
            if (!isEmptyCard) {
              return false;
            }
            let cardCount = 0;
            let cardIndex = -1;
            state.doc.descendants((n, pos) => {
              if (n.type.name === TIPTAP_CARD_TYPE) {
                if (pos === cardNode.pos) {
                  cardIndex = cardCount;
                }
                cardCount++;
                return false;
              }
            });
            if (cardCount <= 1 || cardIndex === -1) {
              return false;
            }
            return this.editor.commands.deleteCard(cardIndex);
          },
          "Mod-Enter": () => this.editor.commands.splitCard()
        };
      },
      addProseMirrorPlugins() {
        const plugins = [createCardNormalizingTransactionPlugin(), createCardPastePlugin()];
        const getCardsApi = this.options.getCardsApi;
        const services = this.options._services;
        const formats = this.options.formats ?? [];
        const initialPageFormat = this.options.initialPageFormat;
        const storage = this.editor.storage[TIPTAP_CARD_TYPE];
        storage.formats = formats;
        if (initialPageFormat) {
          storage.activePageFormat = formats.find((f) => f.name === initialPageFormat);
        }
        if (getCardsApi && services) {
          plugins.push(
            createCardsApiPlugin({
              getCardsApi,
              editor: this.editor,
              services,
              formats
            })
          );
        }
        return plugins;
      }
    };
  }
});
const isBannerLayoutEmpty = (layoutNode) => {
  let allEmpty = true;
  layoutNode.content.forEach((cell) => {
    cell.content.forEach((child) => {
      if (!child.isTextblock || child.content.size > 0) {
        allEmpty = false;
      }
    });
  });
  return allEmpty;
};
const detachEmptyBannerOnBackspace = (editor) => {
  const $from = editor.state.selection.$from;
  if (!$from.parent.isTextblock || $from.parent.content.size > 0) {
    return false;
  }
  for (let d = $from.depth - 1; d > 0; d--) {
    const node = $from.node(d);
    if (node.type.name !== TIPTAP_LAYOUT_TYPE) {
      continue;
    }
    const parentName = $from.node(d - 1).type.name;
    const isBannerWrapper = parentName === TIPTAP_CARD_HEADER_TYPE || parentName === TIPTAP_CARD_FOOTER_TYPE;
    if (!isBannerWrapper || !isBannerLayoutEmpty(node)) {
      return false;
    }
    return editor.commands.setLayoutBanner(node.attrs.id, void 0);
  }
  return false;
};
const redirectSplitForCardWrapper = (tr, $pos, cardDepth) => {
  for (let d = $pos.depth; d > cardDepth; d--) {
    const wrapperNode = $pos.node(d);
    const name = wrapperNode.type.name;
    if (name !== TIPTAP_CARD_HEADER_TYPE && name !== TIPTAP_CARD_FOOTER_TYPE) {
      continue;
    }
    const cardType = tr.doc.type.schema.nodes[TIPTAP_CARD_TYPE];
    const newCard = cardType.createAndFill(null, wrapperNode);
    if (!newCard) {
      return false;
    }
    const wrapperFromPos = $pos.before(d);
    const cardOuterPos = name === TIPTAP_CARD_FOOTER_TYPE ? $pos.after(cardDepth) : $pos.before(cardDepth);
    return moveCardWrapperToSibling(tr, wrapperNode, wrapperFromPos, cardOuterPos, newCard);
  }
  return false;
};
const isListNode = (node) => node.type.name === Node_Type.BULLETED_LIST || node.type.name === Node_Type.ORDERED_LIST;
const getItemsBeforeListSplit = (listNode, listStart, splitPos) => {
  let itemsBeforeSplit = 0;
  listNode.forEach((_child, offset) => {
    if (listStart + offset < splitPos) {
      itemsBeforeSplit++;
    }
  });
  return itemsBeforeSplit;
};
const getTargetListDepth = ($pos, topListDepth) => {
  for (let depth = $pos.depth; depth >= topListDepth; depth--) {
    if (isListNode($pos.node(depth)) && (depth === $pos.depth || $pos.node(depth + 1)?.type.name === Node_Type.LIST_ITEM)) {
      return depth;
    }
  }
  return void 0;
};
const getListVisibleOffset = ($pos, topListDepth, targetListDepth) => {
  let offset = 0;
  let listCount = 0;
  for (let depth = topListDepth; depth <= targetListDepth; depth++) {
    const node = $pos.node(depth);
    if (isListNode(node)) {
      offset += node.attrs.offset ?? 0;
      listCount++;
    }
  }
  return offset + Math.max(0, listCount - 1);
};
const getTrailingNestedListSplitTarget = ($pos, cardDepth, topListDepth, topListNode, topListItemIndex) => {
  let topListItem;
  let topListItemPos = -1;
  topListNode.forEach((child, offset, index) => {
    if (index === topListItemIndex) {
      topListItem = child;
      topListItemPos = $pos.start(topListDepth) + offset;
    }
  });
  if (!topListItem || topListItemPos === -1) {
    return void 0;
  }
  let targetListNode;
  let targetListIndex = -1;
  let targetListOffsetInTopItem = -1;
  topListItem.forEach((child, offset, index) => {
    if (isListNode(child)) {
      targetListNode = child;
      targetListIndex = index;
      targetListOffsetInTopItem = offset;
    }
  });
  if (!targetListNode || targetListIndex <= 0) {
    return void 0;
  }
  return {
    splitPos: topListItemPos + 1 + targetListOffsetInTopItem,
    splitDepth: 1,
    nestedListSplit: {
      cardPos: $pos.before(cardDepth),
      cardContentPos: $pos.before(cardDepth + 1),
      topListPos: $pos.before(topListDepth),
      topListItemIndex,
      targetListPos: topListItemPos + 1 + targetListOffsetInTopItem,
      targetListOffsetInTopItem,
      itemsBeforeSplit: 0,
      continuationOffset: (topListNode.attrs.offset ?? 0) + (targetListNode.attrs.offset ?? 0) + 1,
      ...topListNode.type.name === Node_Type.ORDERED_LIST ? { outerOrderedListStart: topListNode.attrs.start + topListItemIndex + 1 } : {}
    },
    ...targetListNode.type.name === Node_Type.ORDERED_LIST ? { orderedListStart: targetListNode.attrs.start } : {}
  };
};
const isAtEndOfDeepNestedBranch = ($pos, directListDepth, targetListDepth, itemsBeforeSplit) => {
  if (itemsBeforeSplit !== $pos.node(targetListDepth).childCount) {
    return false;
  }
  for (let depth = targetListDepth - 1; depth > directListDepth; depth -= 2) {
    if ($pos.index(depth) !== $pos.node(depth).childCount - 1) {
      return false;
    }
  }
  return true;
};
const getDeepNestedListEndSplitTarget = ($pos, cardDepth, topListDepth, targetListDepth, itemsBeforeSplit) => {
  const directListDepth = topListDepth + 2;
  if (targetListDepth <= directListDepth || !isListNode($pos.node(directListDepth)) || !isAtEndOfDeepNestedBranch($pos, directListDepth, targetListDepth, itemsBeforeSplit)) {
    return void 0;
  }
  const topListNode = $pos.node(topListDepth);
  const topListItemDepth = topListDepth + 1;
  const topListItemPos = $pos.before(topListItemDepth);
  const topListItemIndex = getItemsBeforeListSplit(
    topListNode,
    $pos.start(topListDepth),
    topListItemPos
  );
  const directListNode = $pos.node(directListDepth);
  const directListItemsBeforeSplit = $pos.index(directListDepth) + 1;
  const directListPos = $pos.before(directListDepth);
  return {
    splitPos: $pos.after(directListDepth + 1),
    splitDepth: 1,
    nestedListSplit: {
      cardPos: $pos.before(cardDepth),
      cardContentPos: $pos.before(cardDepth + 1),
      topListPos: $pos.before(topListDepth),
      topListItemIndex,
      targetListPos: directListPos,
      targetListOffsetInTopItem: directListPos - (topListItemPos + 1),
      itemsBeforeSplit: directListItemsBeforeSplit,
      continuationOffset: getListVisibleOffset($pos, topListDepth, directListDepth),
      ...topListNode.type.name === Node_Type.ORDERED_LIST ? { outerOrderedListStart: topListNode.attrs.start + topListItemIndex + 1 } : {}
    },
    ...directListNode.type.name === Node_Type.ORDERED_LIST ? { orderedListStart: directListNode.attrs.start + directListItemsBeforeSplit } : {}
  };
};
const getListItemSplitTargetAtPos = ($pos, pos, cardDepth, topListDepth) => {
  const targetListDepth = getTargetListDepth($pos, topListDepth);
  if (targetListDepth === void 0) {
    return void 0;
  }
  const listNode = $pos.node(targetListDepth);
  const isAtListChildBoundary = $pos.depth === targetListDepth;
  const listItemDepth = targetListDepth + 1;
  const isAtListItemEnd = !isAtListChildBoundary && pos >= $pos.end(listItemDepth) - 1;
  const splitPos = isAtListChildBoundary ? pos : isAtListItemEnd ? $pos.after(listItemDepth) : $pos.before(listItemDepth);
  const itemsBeforeSplit = isAtListChildBoundary ? $pos.index(targetListDepth) : getItemsBeforeListSplit(listNode, $pos.start(targetListDepth), splitPos);
  if (isAtListChildBoundary && targetListDepth === topListDepth && itemsBeforeSplit > 0) {
    const trailingNestedListSplitTarget = getTrailingNestedListSplitTarget(
      $pos,
      cardDepth,
      topListDepth,
      listNode,
      itemsBeforeSplit - 1
    );
    if (trailingNestedListSplitTarget) {
      return trailingNestedListSplitTarget;
    }
  }
  if (targetListDepth > topListDepth) {
    const deepNestedListEndSplitTarget = getDeepNestedListEndSplitTarget(
      $pos,
      cardDepth,
      topListDepth,
      targetListDepth,
      itemsBeforeSplit
    );
    if (deepNestedListEndSplitTarget) {
      return deepNestedListEndSplitTarget;
    }
    const topListNode = $pos.node(topListDepth);
    const topListItemDepth = topListDepth + 1;
    const topListItemPos = $pos.before(topListItemDepth);
    const topListItemIndex = getItemsBeforeListSplit(
      topListNode,
      $pos.start(topListDepth),
      topListItemPos
    );
    return {
      splitPos,
      splitDepth: 1,
      nestedListSplit: {
        cardPos: $pos.before(cardDepth),
        cardContentPos: $pos.before(cardDepth + 1),
        topListPos: $pos.before(topListDepth),
        topListItemIndex,
        targetListPos: $pos.before(targetListDepth),
        targetListOffsetInTopItem: $pos.before(targetListDepth) - (topListItemPos + 1),
        itemsBeforeSplit,
        continuationOffset: getListVisibleOffset($pos, topListDepth, targetListDepth),
        ...topListNode.type.name === Node_Type.ORDERED_LIST ? { outerOrderedListStart: topListNode.attrs.start + topListItemIndex + 1 } : {}
      },
      ...listNode.type.name === Node_Type.ORDERED_LIST ? { orderedListStart: listNode.attrs.start + itemsBeforeSplit } : {}
    };
  }
  if (itemsBeforeSplit === 0) {
    return {
      splitPos: $pos.before(targetListDepth),
      splitDepth: 2,
      listSplit: {
        cardPos: $pos.before(cardDepth),
        cardContentPos: $pos.before(cardDepth + 1),
        listPos: $pos.before(topListDepth),
        itemsBeforeSplit
      }
    };
  }
  if (itemsBeforeSplit === listNode.childCount) {
    return {
      splitPos: $pos.after(targetListDepth),
      splitDepth: 2,
      listSplit: {
        cardPos: $pos.before(cardDepth),
        cardContentPos: $pos.before(cardDepth + 1),
        listPos: $pos.before(topListDepth),
        itemsBeforeSplit
      }
    };
  }
  return {
    splitPos,
    splitDepth: 1,
    listSplit: {
      cardPos: $pos.before(cardDepth),
      cardContentPos: $pos.before(cardDepth + 1),
      listPos: $pos.before(topListDepth),
      itemsBeforeSplit
    },
    ...listNode.type.name === Node_Type.ORDERED_LIST ? { orderedListStart: listNode.attrs.start + itemsBeforeSplit } : {}
  };
};
const getCardSplitTargetAtPos = ($pos, pos, cardDepth) => {
  const blockDepth = cardDepth + 2;
  if ($pos.depth === blockDepth - 1) {
    return {
      splitPos: pos,
      splitDepth: 2
    };
  }
  const childNode = $pos.depth >= blockDepth ? $pos.node(blockDepth) : null;
  if (!childNode) {
    return void 0;
  }
  if (isListNode(childNode)) {
    const listItemSplitTarget = getListItemSplitTargetAtPos($pos, pos, cardDepth, blockDepth);
    if (listItemSplitTarget) {
      return listItemSplitTarget;
    }
  }
  const isInTextBlock = childNode.isTextblock;
  const offsetInBlock = pos - $pos.start(blockDepth);
  const atBlockStart = offsetInBlock === 0;
  const atBlockEnd = offsetInBlock === childNode.content.size;
  if (isInTextBlock && !atBlockStart && !atBlockEnd) {
    return {
      splitPos: pos,
      splitDepth: $pos.depth - cardDepth + 1
    };
  }
  if (!isInTextBlock) {
    return {
      splitPos: atBlockEnd ? $pos.after(blockDepth) : $pos.before(blockDepth),
      splitDepth: 2
    };
  }
  if (atBlockEnd) {
    return {
      splitPos: $pos.after(blockDepth),
      splitDepth: 2
    };
  }
  if (atBlockStart) {
    return {
      splitPos: $pos.before(blockDepth),
      splitDepth: 2
    };
  }
  return void 0;
};
const redirectSplitForCardChildBoundary = (tr, $pos, cardDepth) => {
  const cardNode = $pos.node(cardDepth);
  const cardStart = $pos.start(cardDepth);
  const boundaryOffset = $pos.pos - cardStart;
  if (boundaryOffset <= 0 || boundaryOffset >= cardNode.content.size) {
    return false;
  }
  let beforeBoundary;
  let afterBoundary;
  cardNode.forEach((child, offset) => {
    const childPos = cardStart + offset;
    if (!beforeBoundary && offset + child.nodeSize === boundaryOffset) {
      beforeBoundary = { node: child, pos: childPos };
    }
    if (!afterBoundary && offset === boundaryOffset) {
      afterBoundary = { node: child, pos: childPos };
    }
  });
  if (beforeBoundary?.node.type.name === TIPTAP_CARD_HEADER_TYPE) {
    return moveCardWrapperToSibling(
      tr,
      beforeBoundary.node,
      beforeBoundary.pos,
      $pos.before(cardDepth)
    );
  }
  if (afterBoundary?.node.type.name === TIPTAP_CARD_FOOTER_TYPE) {
    return moveCardWrapperToSibling(
      tr,
      afterBoundary.node,
      afterBoundary.pos,
      $pos.after(cardDepth)
    );
  }
  return false;
};
const moveCardWrapperToSibling = (tr, wrapperNode, wrapperPos, cardOuterPos, newCard = tr.doc.type.schema.nodes[TIPTAP_CARD_TYPE].createAndFill(null, wrapperNode)) => {
  if (!newCard) {
    return false;
  }
  tr.delete(wrapperPos, wrapperPos + wrapperNode.nodeSize);
  tr.insert(tr.mapping.map(cardOuterPos), newCard);
  return true;
};
const splitCardTransaction = (tr, splitTarget) => {
  if (splitTarget.listSplit) {
    return splitCardAtListItem(tr, splitTarget);
  }
  if (splitTarget.nestedListSplit) {
    return splitCardAtNestedListItem(tr, splitTarget);
  }
  try {
    tr.split(splitTarget.splitPos, splitTarget.splitDepth);
    return true;
  } catch {
    return false;
  }
};
const getNodeChildren = (node) => {
  const children = [];
  node.forEach((child) => children.push(child));
  return children;
};
const createListWithChildren = (listNode, children, attrs = listNode.attrs) => listNode.type.create(attrs, Fragment.fromArray(children));
const createListWithChildrenIfAny = (listNode, children, attrs = listNode.attrs) => children.length > 0 ? createListWithChildren(listNode, children, attrs) : void 0;
const createNestedContinuationSibling = (topListNode, child) => {
  if (!isListNode(child)) {
    return child;
  }
  return createListWithChildren(child, getNodeChildren(child), {
    ...child.attrs,
    offset: (topListNode.attrs.offset ?? 0) + (child.attrs.offset ?? 0) + 1
  });
};
const splitCardAtListItem = (tr, splitTarget) => {
  const listSplit = splitTarget.listSplit;
  if (!listSplit) {
    return false;
  }
  const cardNode = tr.doc.nodeAt(listSplit.cardPos);
  const cardContentNode = tr.doc.nodeAt(listSplit.cardContentPos);
  const listNode = tr.doc.nodeAt(listSplit.listPos);
  if (!cardNode || !cardContentNode || !listNode) {
    return false;
  }
  const cardChildren = getNodeChildren(cardNode);
  const cardContentIndex = cardChildren.findIndex((child) => child === cardContentNode);
  const cardContentChildren = getNodeChildren(cardContentNode);
  const listIndex = cardContentChildren.findIndex((child) => child === listNode);
  if (cardContentIndex === -1 || listIndex === -1) {
    return false;
  }
  const listChildren = getNodeChildren(listNode);
  const beforeList = createListWithChildrenIfAny(
    listNode,
    listChildren.slice(0, listSplit.itemsBeforeSplit)
  );
  const afterListAttrs = splitTarget.orderedListStart === void 0 ? listNode.attrs : { ...listNode.attrs, start: splitTarget.orderedListStart };
  const afterList = createListWithChildrenIfAny(
    listNode,
    listChildren.slice(listSplit.itemsBeforeSplit),
    afterListAttrs
  );
  const firstContentChildren = [
    ...cardContentChildren.slice(0, listIndex),
    ...beforeList ? [beforeList] : []
  ];
  const secondContentChildren = [
    ...afterList ? [afterList] : [],
    ...cardContentChildren.slice(listIndex + 1)
  ];
  if (firstContentChildren.length === 0 || secondContentChildren.length === 0) {
    return false;
  }
  const firstContent = cardContentNode.type.create(
    cardContentNode.attrs,
    Fragment.fromArray(firstContentChildren)
  );
  const secondContent = cardContentNode.type.create(
    cardContentNode.attrs,
    Fragment.fromArray(secondContentChildren)
  );
  const firstCard = cardNode.type.create(
    cardNode.attrs,
    Fragment.fromArray([...cardChildren.slice(0, cardContentIndex), firstContent])
  );
  const secondCard = cardNode.type.create(
    cardNode.attrs,
    Fragment.fromArray([secondContent, ...cardChildren.slice(cardContentIndex + 1)])
  );
  tr.replaceWith(
    listSplit.cardPos,
    listSplit.cardPos + cardNode.nodeSize,
    Fragment.fromArray([firstCard, secondCard])
  );
  return true;
};
const splitCardAtNestedListItem = (tr, splitTarget) => {
  const listSplit = splitTarget.nestedListSplit;
  if (!listSplit) {
    return false;
  }
  const cardNode = tr.doc.nodeAt(listSplit.cardPos);
  const cardContentNode = tr.doc.nodeAt(listSplit.cardContentPos);
  const topListNode = tr.doc.nodeAt(listSplit.topListPos);
  const targetListNode = tr.doc.nodeAt(listSplit.targetListPos);
  if (!cardNode || !cardContentNode || !topListNode || !targetListNode) {
    return false;
  }
  const cardChildren = getNodeChildren(cardNode);
  const cardContentIndex = cardChildren.findIndex((child) => child === cardContentNode);
  const cardContentChildren = getNodeChildren(cardContentNode);
  const topListIndex = cardContentChildren.findIndex((child) => child === topListNode);
  const topListChildren = getNodeChildren(topListNode);
  const topListItem = topListChildren[listSplit.topListItemIndex];
  if (cardContentIndex === -1 || topListIndex === -1 || !topListItem) {
    return false;
  }
  const topListItemChildren = getNodeChildren(topListItem);
  let targetListIndex = -1;
  topListItem.forEach((child, offset, index) => {
    if (offset === listSplit.targetListOffsetInTopItem && child.type === targetListNode.type) {
      targetListIndex = index;
    }
  });
  if (targetListIndex === -1) {
    return false;
  }
  const targetListChildren = getNodeChildren(targetListNode);
  const beforeTargetList = createListWithChildrenIfAny(
    targetListNode,
    targetListChildren.slice(0, listSplit.itemsBeforeSplit)
  );
  const afterTargetListAttrs = splitTarget.orderedListStart === void 0 ? { ...targetListNode.attrs, offset: listSplit.continuationOffset } : {
    ...targetListNode.attrs,
    offset: listSplit.continuationOffset,
    start: splitTarget.orderedListStart
  };
  const afterTargetList = createListWithChildrenIfAny(
    targetListNode,
    targetListChildren.slice(listSplit.itemsBeforeSplit),
    afterTargetListAttrs
  );
  const firstTopListItemChildren = [
    ...topListItemChildren.slice(0, targetListIndex),
    ...beforeTargetList ? [beforeTargetList] : []
  ];
  const firstTopListItem = topListItem.type.create(
    topListItem.attrs,
    Fragment.fromArray(firstTopListItemChildren)
  );
  const firstTopList = createListWithChildren(topListNode, [
    ...topListChildren.slice(0, listSplit.topListItemIndex),
    firstTopListItem
  ]);
  const secondContentChildren = [];
  if (afterTargetList) {
    secondContentChildren.push(afterTargetList);
  }
  secondContentChildren.push(
    ...topListItemChildren.slice(targetListIndex + 1).map((child) => createNestedContinuationSibling(topListNode, child))
  );
  const outerSuffixList = createListWithChildrenIfAny(
    topListNode,
    topListChildren.slice(listSplit.topListItemIndex + 1),
    listSplit.outerOrderedListStart === void 0 ? topListNode.attrs : { ...topListNode.attrs, start: listSplit.outerOrderedListStart }
  );
  if (outerSuffixList) {
    secondContentChildren.push(outerSuffixList);
  }
  secondContentChildren.push(...cardContentChildren.slice(topListIndex + 1));
  if (secondContentChildren.length === 0) {
    return false;
  }
  const firstContent = cardContentNode.type.create(
    cardContentNode.attrs,
    Fragment.fromArray([...cardContentChildren.slice(0, topListIndex), firstTopList])
  );
  const secondContent = cardContentNode.type.create(
    cardContentNode.attrs,
    Fragment.fromArray(secondContentChildren)
  );
  const firstCard = cardNode.type.create(
    cardNode.attrs,
    Fragment.fromArray([...cardChildren.slice(0, cardContentIndex), firstContent])
  );
  const secondCard = cardNode.type.create(
    cardNode.attrs,
    Fragment.fromArray([secondContent, ...cardChildren.slice(cardContentIndex + 1)])
  );
  tr.replaceWith(
    listSplit.cardPos,
    listSplit.cardPos + cardNode.nodeSize,
    Fragment.fromArray([firstCard, secondCard])
  );
  return true;
};
const demoteCardWrapper = (tr, cardId, wrapperType, insertAt) => {
  const card = findNodeById(tr, cardId)[0];
  if (!card) {
    return;
  }
  let wrapperPos = -1;
  let wrapperSize = -1;
  let layoutJson;
  card.node.forEach((child, offset) => {
    if (child.type.name !== wrapperType || wrapperPos !== -1) {
      return;
    }
    const layoutInside = child.firstChild;
    if (!layoutInside) {
      return;
    }
    wrapperPos = card.pos + 1 + offset;
    wrapperSize = child.nodeSize;
    const json = layoutInside.toJSON();
    layoutJson = {
      ...json,
      attrs: { ...json.attrs ?? {}, banner: void 0 }
    };
  });
  if (wrapperPos === -1 || !layoutJson) {
    return;
  }
  tr.delete(wrapperPos, wrapperPos + wrapperSize);
  const cardAfter = findNodeById(tr, cardId)[0];
  if (!cardAfter) {
    return;
  }
  let target = -1;
  cardAfter.node.forEach((child, offset) => {
    if (child.type.name !== TIPTAP_CARD_CONTENT_TYPE || target !== -1) {
      return;
    }
    const innerStart = cardAfter.pos + 1 + offset + 1;
    const innerEnd = cardAfter.pos + 1 + offset + child.nodeSize - 1;
    target = insertAt === "start" ? innerStart : innerEnd;
  });
  if (target === -1) {
    return;
  }
  tr.insert(target, tr.doc.type.schema.nodeFromJSON(layoutJson));
};
const findCardAtIndex = (doc, cardIndex) => {
  let currentCardIndex = 0;
  let result;
  doc.forEach((node, offset) => {
    if (node.type.name !== TIPTAP_CARD_TYPE) {
      return;
    }
    if (currentCardIndex === cardIndex) {
      result = { node, pos: offset };
    }
    currentCardIndex++;
  });
  return result;
};
export {
  cardExtension,
  getCardSplitTargetAtPos,
  redirectSplitForCardChildBoundary
};
//# sourceMappingURL=extension.js.map
