/**
 * Factory that assembles a StrandCoordinator from a graph runtime.
 *
 * @module domain/services/strand/createStrandCoordinator
 */
import StrandDescriptorStore from "./StrandDescriptorStore.js";
import StrandMaterializer from "./StrandMaterializer.js";
import StrandPatchService from "./StrandPatchService.js";
import StrandIntentService from "./StrandIntentService.js";
import StrandCoordinator from "./StrandCoordinator.js";
import { frontierRecordsEqual } from "./StrandDescriptorValidation.js";
import { buildIntentId, buildTickId } from "./strandShared.js";
function baseObservationsEqual(left, right) {
    return (left.coordinateVersion === right.coordinateVersion
        && left.lamportCeiling === right.lamportCeiling
        && frontierRecordsEqual(left.frontier, right.frontier));
}
function wireDescriptors(graph, ref) {
    return new StrandDescriptorStore({
        graph,
        loadStrandOrThrow: async (strandId) => await ref.coordinator.getOrThrow(strandId),
        baseObservationsEqual,
    });
}
function wirePatches(graph, ref, subs) {
    return new StrandPatchService({
        graph,
        loadStrandOrThrow: async (strandId) => await ref.coordinator.getOrThrow(strandId),
        materializeDescriptor: async (descriptor, options) => await subs.materializer.materializeDescriptor(descriptor, options),
        writeDescriptor: async (descriptor) => await subs.descriptors.writeDescriptor(descriptor),
        buildOverlayRef: (strandId) => subs.descriptors.buildOverlayRef(strandId),
        buildIntentId,
    });
}
function wireIntents(graph, ref, subs) {
    return new StrandIntentService({
        graph,
        loadStrandOrThrow: async (strandId) => await ref.coordinator.getOrThrow(strandId),
        buildQueuedIntent: async (descriptor, build) => await subs.patches.buildQueuedIntent(descriptor, build),
        writeDescriptor: async (descriptor) => await subs.descriptors.writeDescriptor(descriptor),
        commitQueuedPatch: async (params) => await subs.patches.commitQueuedPatch(params),
        collectPatchEntries: async (descriptor, options) => await subs.materializer.collectPatchEntries(descriptor, options),
        buildTickId,
    });
}
/** Creates a StrandCoordinator wired to the given graph runtime. */
export default function createStrandCoordinator(graph) {
    const ref = { coordinator: null };
    const descriptors = wireDescriptors(graph, ref);
    const materializer = new StrandMaterializer({ graph });
    const patches = wirePatches(graph, ref, { descriptors, materializer });
    const intents = wireIntents(graph, ref, { descriptors, materializer, patches });
    ref.coordinator = new StrandCoordinator({
        graphName: graph._graphName,
        maxObservedLamport: () => graph._maxObservedLamport,
        crypto: graph._crypto,
        persistence: graph._persistence,
        descriptors,
        materializer,
        patches,
        intents,
        graph,
    });
    return ref.coordinator;
}
