/**
 * ConflictEffectPayload — runtime-backed effect identity for conflict hashing.
 *
 * @module domain/services/strand/ConflictEffectPayload
 */
import { compareStrings } from "../../types/conflict/validation.js";
import BlobValue from "../../types/ops/BlobValue.js";
import EdgeAdd from "../../types/ops/EdgeAdd.js";
import EdgePropSet from "../../types/ops/EdgePropSet.js";
import EdgeRemove from "../../types/ops/EdgeRemove.js";
import NodeAdd from "../../types/ops/NodeAdd.js";
import NodePropSet from "../../types/ops/NodePropSet.js";
import NodeRemove from "../../types/ops/NodeRemove.js";
import { receiptNameForOp } from "./CanonicalConflictOp.js";
import ConflictOpAnchor from "./ConflictOpAnchor.js";
import { normalizeHashableEffectValue } from "./conflictHashableEffectValue.js";
const ADD_RECEIPT_NAMES = new Set(['NodeAdd', 'EdgeAdd']);
const REMOVE_RECEIPT_NAMES = new Set(['NodeTombstone', 'EdgeTombstone']);
const PROPERTY_RECEIPT_NAMES = new Set(['PropSet', 'NodePropSet', 'EdgePropSet']);
export function normalizeNoteCodes(noteCodes) {
    return [...new Set(noteCodes)].sort(compareStrings);
}
export function normalizeObservedDots(observedDots) {
    if (observedDots === null || observedDots === undefined) {
        return [];
    }
    return [...observedDots].sort(compareStrings);
}
export default class ConflictEffectPayload {
    dot;
    observedDots;
    value;
    oid;
    constructor(fields) {
        if (fields.dot !== undefined) {
            this.dot = fields.dot;
        }
        if (fields.observedDots !== undefined) {
            this.observedDots = Object.freeze([...fields.observedDots]);
        }
        if (fields.value !== undefined) {
            this.value = fields.value;
        }
        if (fields.oid !== undefined) {
            this.oid = fields.oid;
        }
        Object.freeze(this);
    }
    static forOp(canonOp, receiptOpType) {
        if (canonOp === null) {
            return null;
        }
        return ConflictEffectPayload.forReceipt(canonOp, receiptOpType ?? receiptNameForOp(canonOp));
    }
    static forReceipt(canonOp, receiptOpType) {
        return ConflictEffectPayload.forStructuralReceipt(canonOp, receiptOpType)
            ?? ConflictEffectPayload.forValueReceipt(canonOp, receiptOpType);
    }
    static forStructuralReceipt(canonOp, receiptOpType) {
        return ConflictEffectPayload.forAddReceipt(canonOp, receiptOpType)
            ?? ConflictEffectPayload.forRemoveReceipt(canonOp, receiptOpType);
    }
    static forValueReceipt(canonOp, receiptOpType) {
        return ConflictEffectPayload.forPropertyReceipt(canonOp, receiptOpType)
            ?? ConflictEffectPayload.forBlobReceipt(canonOp, receiptOpType);
    }
    static forAddReceipt(canonOp, receiptOpType) {
        if (!ADD_RECEIPT_NAMES.has(receiptOpType)) {
            return null;
        }
        if (canonOp instanceof NodeAdd || canonOp instanceof EdgeAdd) {
            return new ConflictEffectPayload({ dot: canonOp.dot });
        }
        return canonOp instanceof ConflictOpAnchor ? new ConflictEffectPayload({ dot: canonOp.dot }) : null;
    }
    static forRemoveReceipt(canonOp, receiptOpType) {
        if (!REMOVE_RECEIPT_NAMES.has(receiptOpType)) {
            return null;
        }
        if (canonOp instanceof NodeRemove || canonOp instanceof EdgeRemove) {
            return new ConflictEffectPayload({ observedDots: normalizeObservedDots(canonOp.observedDots) });
        }
        return canonOp instanceof ConflictOpAnchor
            ? new ConflictEffectPayload({ observedDots: normalizeObservedDots(canonOp.observedDots) })
            : null;
    }
    static forPropertyReceipt(canonOp, receiptOpType) {
        if (!PROPERTY_RECEIPT_NAMES.has(receiptOpType)) {
            return null;
        }
        if (canonOp instanceof NodePropSet || canonOp instanceof EdgePropSet) {
            return new ConflictEffectPayload({ value: normalizeHashableEffectValue(canonOp.value) });
        }
        return canonOp instanceof ConflictOpAnchor ? new ConflictEffectPayload({ value: canonOp.value }) : null;
    }
    static forBlobReceipt(canonOp, receiptOpType) {
        if (receiptOpType !== 'BlobValue') {
            return null;
        }
        if (canonOp instanceof BlobValue) {
            return new ConflictEffectPayload({ oid: canonOp.oid });
        }
        return canonOp instanceof ConflictOpAnchor ? new ConflictEffectPayload({ oid: canonOp.oid }) : null;
    }
}
export class ConflictEffectEnvelope {
    targetKind;
    targetDigest;
    opType;
    payload;
    constructor({ target, opType, payload }) {
        this.targetKind = target.targetKind;
        this.targetDigest = target.targetDigest;
        this.opType = opType;
        this.payload = payload;
        Object.freeze(this);
    }
}
export function effectKey(target, effectDigest) {
    return `${target.targetDigest}:${effectDigest}`;
}
