import { compareStrings } from "../utils/StringComparison.js";
import GraphModelMigrationHistorySegment from "./GraphModelMigrationHistorySegment.js";
import WarpError from "../errors/WarpError.js";
/** Runtime-backed ordered legacy history input for graph-model migration. */
export default class GraphModelMigrationHistoryInput {
    segments;
    patches;
    constructor(fields) {
        const checkedFields = requireFields(fields);
        this.segments = freezeSegments(checkedFields.segments);
        this.patches = freezeOrderedPatches(this.segments);
        requireFrontierEvidence(this.patches);
        Object.freeze(this);
    }
}
/** Validates the constructor envelope. */
function requireFields(fields) {
    if (fields === null || fields === undefined) {
        throw new WarpError('GraphModelMigrationHistoryInput fields must be provided', 'E_VALIDATION');
    }
    return fields;
}
/** Validates, sorts, and freezes writer history segments. */
function freezeSegments(segments) {
    const checked = requireArray(segments, 'segments').map(requireSegment);
    requireUnique(checked.map((segment) => segment.writerId), 'writer segment');
    return Object.freeze([...checked].sort(compareSegments));
}
/** Flattens and freezes all patches in deterministic segment order. */
function freezeOrderedPatches(segments) {
    const patches = segments.flatMap((segment) => segment.patches);
    requireUnique(patches.map((patch) => patch.patchId), 'patch id');
    return Object.freeze(patches);
}
/** Requires frontier evidence for all equivalence-ready patch inputs. */
function requireFrontierEvidence(patches) {
    for (const patch of patches) {
        if (patch.frontierEvidence === null) {
            throw new WarpError(`patch ${patch.patchId} is missing frontier evidence`, 'E_VALIDATION');
        }
    }
}
/** Requires an array field. */
function requireArray(items, label) {
    if (items === null || items === undefined || !Array.isArray(items)) {
        throw new WarpError(`GraphModelMigrationHistoryInput ${label} must be an array`, 'E_VALIDATION');
    }
    const checkedItems = items;
    return checkedItems;
}
/** Requires a history segment instance. */
function requireSegment(segment) {
    if (!(segment instanceof GraphModelMigrationHistorySegment)) {
        throw new WarpError('segments must contain history segments', 'E_VALIDATION');
    }
    return segment;
}
/** Requires no duplicate keys in history input. */
function requireUnique(keys, label) {
    const seen = new Set();
    for (const key of keys) {
        if (seen.has(key)) {
            throw new WarpError(`GraphModelMigrationHistoryInput duplicates ${label} ${key}`, 'E_VALIDATION');
        }
        seen.add(key);
    }
}
/** Compares writer segments deterministically. */
function compareSegments(left, right) {
    return compareStrings(left.writerId, right.writerId);
}
