import { next as A } from "@automerge/automerge";
import { ViewPlugin } from "@codemirror/view";
import { Annotation } from "@codemirror/state";
import { applyCmTransactionsToAmHandle } from "./codeMirrorToAm";
import { applyAmPatchesToCm } from "./amToCodemirror";
export const reconcileAnnotationType = Annotation.define();
export const isReconcileTx = (tr) => !!tr.annotation(reconcileAnnotationType);
export const automergeSyncPlugin = ({ handle, path, }) => {
    if (!handle.isReady) {
        throw new Error("ensure the handle is ready before initializing the automergeSyncPlugin");
    }
    return ViewPlugin.fromClass(class {
        view;
        reconciledHeads = A.getHeads(handle.docSync());
        isProcessingCmTransaction = false;
        constructor(view) {
            this.view = view;
            this.onChange = this.onChange.bind(this);
            handle.on("change", this.onChange);
        }
        update(update) {
            // start processing codemirror transaction
            // changes that are created through the transaction are ignored in the change listener on the handle
            this.isProcessingCmTransaction = true;
            const newHeads = applyCmTransactionsToAmHandle(handle, path, update.transactions);
            if (newHeads) {
                this.reconciledHeads = newHeads;
            }
            // finish processing transaction
            this.isProcessingCmTransaction = false;
        }
        onChange = () => {
            // ignore changes that where triggered while processing a codemirror transaction
            if (this.isProcessingCmTransaction) {
                return;
            }
            const currentHeads = A.getHeads(handle.docSync());
            if (A.equals(currentHeads, this.reconciledHeads)) {
                return;
            }
            // get the diff between the reconciled heads and the new heads
            // and apply that to the codemirror doc
            const patches = A.diff(handle.docSync(), this.reconciledHeads, currentHeads);
            applyAmPatchesToCm(this.view, path, patches);
            this.reconciledHeads = currentHeads;
        };
        destroy() {
            handle.off("change", this.onChange);
        }
    });
};
//# sourceMappingURL=plugin.js.map