/**
 * EdgeRemove — removes an edge by tombstoning observed dots.
 */
import Op from "./Op.js";
import { OP_SCOPE_BOTH } from "./OpScope.js";
import { assertNonEmptyString, assertNoReservedBytes, assertArray } from "./validate.js";
import ReceiptBuilder from "../../services/ReceiptBuilder.js";
import DiffCalculator from "../../services/DiffCalculator.js";
export default class EdgeRemove extends Op {
    receiptName = 'EdgeTombstone';
    from;
    to;
    label;
    observedDots;
    constructor({ from, to, label, observedDots }) {
        super('EdgeRemove', OP_SCOPE_BOTH);
        assertNonEmptyString(from, 'EdgeRemove', 'from');
        assertNonEmptyString(to, 'EdgeRemove', 'to');
        assertNonEmptyString(label, 'EdgeRemove', 'label');
        assertNoReservedBytes(from, 'EdgeRemove', 'from');
        assertNoReservedBytes(to, 'EdgeRemove', 'to');
        assertNoReservedBytes(label, 'EdgeRemove', 'label');
        assertArray(observedDots, 'EdgeRemove', 'observedDots');
        for (let i = 0; i < observedDots.length; i += 1) {
            assertNonEmptyString(observedDots[i], 'EdgeRemove', `observedDots[${i}]`);
        }
        this.from = from;
        this.to = to;
        this.label = label;
        this.observedDots = Object.freeze([...observedDots]);
        Object.freeze(this);
    }
    validate() { }
    mutate(state) {
        const dots = new Set(this.observedDots);
        state.edgeAlive.remove(dots);
    }
    outcome(state) {
        return ReceiptBuilder.edgeRemoveOutcome(state.edgeAlive, {
            from: this.from, to: this.to, label: this.label,
            observedDots: this.observedDots,
        });
    }
    snapshot(state) {
        return { aliveBeforeEdges: DiffCalculator.aliveElementsForDots(state.edgeAlive, new Set(this.observedDots)) };
    }
    accumulate(diff, state, before) {
        DiffCalculator.collectEdgeRemovals(diff, state, before.aliveBeforeEdges);
    }
}
