import { EventId, compareEventIds } from "../../utils/EventId.js";
import ReadIdentity from "./ReadIdentity.js";
const REDUCER_VERSION = 'checkpoint-tail-locator';
const PROJECTION_VERSION = 'optic-read-foundation';
export default class CheckpointTailReadIdentityBuilder {
    _worldline;
    constructor(options) {
        this._worldline = options.worldline;
        Object.freeze(this);
    }
    nodeLiveness(options) {
        return this._build({
            basis: options.basis,
            entityAspect: `node:${options.nodeId}:liveness`,
            checkpointIndexShards: options.checkpointIndexShards,
            tailWitnesses: options.tailWitnesses,
        });
    }
    nodeProperty(options) {
        return this._build({
            basis: options.basis,
            entityAspect: `node:${options.nodeId}:prop:${options.propertyKey}`,
            checkpointIndexShards: options.checkpointIndexShards,
            tailWitnesses: options.tailWitnesses,
        });
    }
    neighborhood(options) {
        return this._build({
            basis: options.basis,
            entityAspect: `node:${options.nodeId}:neighborhood:${options.direction}:${labelsAspect(options.labels)}`,
            checkpointIndexShards: options.checkpointIndexShards,
            tailWitnesses: options.tailWitnesses,
        });
    }
    _build(options) {
        return new ReadIdentity({
            worldline: this._worldline,
            entityAspect: options.entityAspect,
            checkpointSha: options.basis.checkpointSha,
            checkpointFrontier: frontierIdentity(options.basis.frontier),
            checkpointIndexShards: options.checkpointIndexShards,
            tailWitnesses: sortTailWitnesses(options.tailWitnesses),
            reducerVersion: REDUCER_VERSION,
            projectionVersion: PROJECTION_VERSION,
        });
    }
}
function labelsAspect(labels) {
    if (labels.length === 0) {
        return 'labels:*';
    }
    const encoded = [...labels]
        .sort()
        .map((label) => `${label.length}:${label}`)
        .join('|');
    return `labels:${encoded}`;
}
function frontierIdentity(frontier) {
    const entries = [];
    const sortedFrontier = [...frontier.entries()]
        .sort(([leftWriter], [rightWriter]) => leftWriter.localeCompare(rightWriter));
    for (const [writerId, patchSha] of sortedFrontier) {
        entries.push(Object.freeze({ writerId, patchSha }));
    }
    return Object.freeze(entries);
}
function sortTailWitnesses(witnesses) {
    return Object.freeze([...witnesses].sort((left, right) => compareTailWitnesses(left, right)));
}
function compareTailWitnesses(left, right) {
    return compareEventIds(new EventId(left.lamport, left.writerId, left.sha, 0), new EventId(right.lamport, right.writerId, right.sha, 0));
}
