/**
 * transferShape — shape delta computation, property collectors, and sync/content aggregators.
 *
 * @module domain/services/transfer/transferShape
 */
import { compareStrings, collectEdgeRefs, } from "./transferKeys.js";
import { nodePropertyOp, edgePropertyOp, collectPropertyOps, collectNodeContentOps, collectEdgeContentOps, summarizeOps, } from "./transferOps.js";
export { summarizeOps };
/**
 * Compute added, removed, and surviving node sets.
 */
export function collectNodeShapeDelta(sourceNodeIds, targetNodeIds) {
    const sourceNodeSet = new Set(sourceNodeIds);
    const targetNodeSet = new Set(targetNodeIds);
    return {
        addedNodeOps: sourceNodeIds
            .filter((nodeId) => !targetNodeSet.has(nodeId))
            .map((nodeId) => ({ op: 'add_node', nodeId })),
        removedNodeOps: targetNodeIds
            .filter((nodeId) => !sourceNodeSet.has(nodeId))
            .map((nodeId) => ({ op: 'remove_node', nodeId })),
        propertyNodeIds: sourceNodeIds,
    };
}
/**
 * Build add-edge transfer operations from a list of edge refs.
 */
export function buildAddEdgeOps(edgeRefs) {
    return edgeRefs.map((edge) => ({
        op: 'add_edge',
        from: edge.from,
        to: edge.to,
        label: edge.label,
    }));
}
/**
 * Build remove-edge transfer operations from target-only edge keys.
 */
export function buildRemoveEdgeOps(removedKeys, targetEdgesByKey) {
    return removedKeys.map((key) => {
        const edge = targetEdgesByKey.get(key);
        return {
            op: 'remove_edge',
            from: edge.from,
            to: edge.to,
            label: edge.label,
        };
    });
}
/**
 * Compute added, removed, and surviving edge sets.
 */
export function collectEdgeShapeDelta(sourceReader, targetReader) {
    const sourceEdgesByKey = collectEdgeRefs(sourceReader);
    const targetEdgesByKey = collectEdgeRefs(targetReader);
    const sourceEdgeKeys = [...sourceEdgesByKey.keys()].sort(compareStrings);
    const targetEdgeKeys = [...targetEdgesByKey.keys()].sort(compareStrings);
    const targetEdgeSet = new Set(targetEdgeKeys);
    const addedEdgeRefs = sourceEdgeKeys
        .filter((key) => !targetEdgeSet.has(key))
        .map((key) => sourceEdgesByKey.get(key));
    const retainedEdgeRefs = sourceEdgeKeys
        .filter((key) => targetEdgeSet.has(key))
        .map((key) => sourceEdgesByKey.get(key));
    const removedKeys = targetEdgeKeys.filter((key) => !sourceEdgesByKey.has(key));
    return {
        addedEdgeOps: buildAddEdgeOps(addedEdgeRefs),
        removedEdgeOps: buildRemoveEdgeOps(removedKeys, targetEdgesByKey),
        edgeRefs: [...addedEdgeRefs, ...retainedEdgeRefs],
    };
}
// ── Property collectors ───────────────────────────────────────────────────────
/**
 * Collect property-diff ops for all nodes present in the source.
 */
export function collectNodePropertyOps(sourceReader, targetReader, nodeIds) {
    return nodeIds.flatMap((nodeId) => collectPropertyOps(sourceReader.getNodeProps(nodeId) ?? {}, targetReader.getNodeProps(nodeId) ?? {}, (key, value) => nodePropertyOp(nodeId, key, value)));
}
/**
 * Collect property-diff ops for all edges present in the source.
 */
export function collectEdgePropertyOps(sourceReader, targetReader, edgeRefs) {
    return edgeRefs.flatMap((edge) => collectPropertyOps(sourceReader.getEdgeProps(edge.from, edge.to, edge.label) ?? {}, targetReader.getEdgeProps(edge.from, edge.to, edge.label) ?? {}, (key, value) => edgePropertyOp(edge, key, value)));
}
/**
 * Collect synchronous property diff ops for nodes and edges.
 */
export function collectSyncPropertyOps(params) {
    return {
        nodePropertyOps: collectNodePropertyOps(params.sourceReader, params.targetReader, params.nodeShape.propertyNodeIds),
        edgePropertyOps: collectEdgePropertyOps(params.sourceReader, params.targetReader, params.edgeShape.edgeRefs),
    };
}
/**
 * Collect async content attach/clear ops for all nodes and edges.
 */
export async function collectAllContentOps(params) {
    const nodeContentOps = await collectNodeContentOps({
        sourceReader: params.sourceReader,
        targetReader: params.targetReader,
        nodeIds: params.nodeShape.propertyNodeIds,
        loadContent: params.loaders.loadNodeContent,
    });
    const edgeContentOps = await collectEdgeContentOps({
        sourceReader: params.sourceReader,
        targetReader: params.targetReader,
        edges: params.edgeShape.edgeRefs,
        loadContent: params.loaders.loadEdgeContent,
    });
    return { nodeContentOps, edgeContentOps };
}
