"use strict";
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
const reactBinding = require("@contember/react-binding");
const Slate = require("slate");
const useGetParentEntityRef = require("../useGetParentEntityRef.cjs");
const react = require("react");
const ElementWithReference = require("../elements/ElementWithReference.cjs");
const useRefreshBlocks = ({ editor, sortedBlocksRef, sortableBy, contentField, blockList, blockElementCache, blockElementPathRefs, referencesField, monolithicReferencesMode }) => {
  const desugaredBlockList = reactBinding.useDesugaredRelativeEntityList(blockList);
  const desugaredBlockContentField = reactBinding.useDesugaredRelativeSingleField(contentField);
  const desugaredSortableByField = reactBinding.useDesugaredRelativeSingleField(sortableBy);
  const getParentEntityRef = useGetParentEntityRef.useGetParentEntityRef();
  const trashFakeBlockId = react.useRef();
  reactBinding.useEntityBeforePersist(() => {
    if (trashFakeBlockId.current) {
      const block = getParentEntityRef.current().getRelativeEntityList(desugaredBlockList).getChildEntityById(trashFakeBlockId.current);
      block.deleteEntity();
      trashFakeBlockId.current = void 0;
    }
  });
  return react.useCallback(() => {
    const { children } = editor;
    const saveBlockElement = (getBlockList, id, element) => {
      getBlockList().getChildEntityById(id).getRelativeSingleField(desugaredBlockContentField).updateValue(editor.serializeNodes([element]));
      blockElementCache.set(getBlockList().getChildEntityById(id), element);
    };
    getParentEntityRef.current().batchUpdates((getAccessor) => {
      const processedAccessors = Array.from({
        length: editor.children.length
      });
      const blockList2 = getAccessor().getRelativeEntityList(desugaredBlockList);
      const getBlockList = blockList2.getAccessor;
      let cleanupStack = () => {
      };
      const knownReferences = /* @__PURE__ */ new Map();
      for (const [blockId, pathRef] of blockElementPathRefs) {
        const current = pathRef.current;
        const blockList3 = getBlockList();
        const block = blockList3.hasEntityId(blockId) ? blockList3.getChildEntityById(blockId) : null;
        if (block && !monolithicReferencesMode && referencesField) {
          for (const reference of block.getEntityList(referencesField)) {
            knownReferences.set(reference.id, [reference, block]);
          }
        }
        const cleanUp = () => {
          const prev = cleanupStack;
          cleanupStack = () => {
            prev();
            block?.deleteEntity();
            pathRef.unref();
            blockElementPathRefs.delete(blockId);
          };
        };
        if (current === null || current.length > 1 || block === null) {
          cleanUp();
        } else {
          const newBlockOrder = current[0];
          if (processedAccessors[newBlockOrder]) {
            cleanUp();
          } else {
            const originalElement = blockElementCache.get(block);
            const currentElement = editor.children[newBlockOrder];
            if (originalElement !== currentElement || block.getRelativeSingleField(desugaredSortableByField).value !== newBlockOrder) {
              block.getRelativeSingleField(desugaredSortableByField).updateValue(newBlockOrder);
              saveBlockElement(getBlockList, blockId, currentElement);
            }
            processedAccessors[newBlockOrder] = block;
          }
        }
      }
      for (const [topLevelIndex, child] of editor.children.entries()) {
        const blockOrder = topLevelIndex;
        const isProcessed = processedAccessors[blockOrder];
        if (!isProcessed) {
          const id = blockList2.createNewEntity((getAccessor2) => {
            const newId = getAccessor2().id;
            getAccessor2().getRelativeSingleField(desugaredSortableByField).updateValue(blockOrder);
            saveBlockElement(getBlockList, newId, child);
            blockElementPathRefs.set(newId, Slate.Editor.pathRef(editor, [topLevelIndex], { affinity: "backward" }));
          });
          processedAccessors[blockOrder] = blockList2.getChildEntityById(id.value);
        }
      }
      sortedBlocksRef.current = processedAccessors;
      if (!monolithicReferencesMode && referencesField) {
        for (const index in children) {
          const node = children[index];
          const nodeReferences = [];
          const block = processedAccessors[index];
          const references = block.getEntityList(referencesField);
          const collectReferences = (node2) => {
            if (!Slate.Element.isElement(node2)) {
              return;
            }
            if (ElementWithReference.isElementWithReference(node2)) {
              nodeReferences.push(node2.referenceId);
            }
            for (const child of node2.children) {
              collectReferences(child);
            }
          };
          collectReferences(node);
          for (const id of nodeReferences) {
            const entry = knownReferences.get(id);
            if (!entry) {
              if (trashFakeBlockId.current) {
                const fakeBlock = blockList2.getChildEntityById(trashFakeBlockId.current);
                const fakeReferences = fakeBlock.getEntityList(referencesField);
                const ref = fakeReferences.getChildEntityById(id);
                references.connectEntity(ref);
                fakeReferences.disconnectEntity(ref);
              } else {
                throw new reactBinding.BindingError(`Reference ${id} not found.`);
              }
            } else {
              const [reference, prevBlock] = entry;
              if (prevBlock !== block) {
                references.connectEntity(reference.getAccessor());
                prevBlock.getEntityList(referencesField).disconnectEntity(reference.getAccessor(), { noPersist: true });
              }
              knownReferences.delete(id);
            }
          }
        }
        for (const [, [reference, block]] of knownReferences) {
          if (!trashFakeBlockId.current) {
            blockList2.createNewEntity((getAccessor2) => {
              getAccessor2().getRelativeSingleField(desugaredSortableByField).updateValue(Number.MAX_SAFE_INTEGER);
              trashFakeBlockId.current = getAccessor2().id;
            });
          }
          const trashBlock = blockList2.getChildEntityById(trashFakeBlockId.current);
          trashBlock.getEntityList(referencesField).connectEntity(reference);
          block.getEntityList(referencesField).disconnectEntity(reference, { noPersist: true });
        }
      }
      cleanupStack();
    });
  }, [blockElementCache, blockElementPathRefs, desugaredBlockContentField, desugaredBlockList, desugaredSortableByField, editor, getParentEntityRef, monolithicReferencesMode, referencesField, sortedBlocksRef]);
};
exports.useRefreshBlocks = useRefreshBlocks;
//# sourceMappingURL=useRefreshBlocks.cjs.map
