import GraphModelMigrationHistoryPatchInput from "./GraphModelMigrationHistoryPatchInput.js";
import WarpError from "../errors/WarpError.js";
/** Runtime-backed ordered legacy history segment for one writer. */
export default class GraphModelMigrationHistorySegment {
    writerId;
    patches;
    constructor(fields) {
        const checkedFields = requireFields(fields);
        this.writerId = requireNonEmptyString(checkedFields.writerId, 'writerId');
        this.patches = freezePatches(this.writerId, checkedFields.patches);
        Object.freeze(this);
    }
}
/** Validates the constructor envelope. */
function requireFields(fields) {
    if (fields === null || fields === undefined) {
        throw new WarpError('GraphModelMigrationHistorySegment fields must be provided', 'E_VALIDATION');
    }
    return fields;
}
/** Validates a required non-empty string. */
function requireNonEmptyString(value, name) {
    if (typeof value !== 'string' || value.length === 0) {
        throw new WarpError(`${name} must be a non-empty string`, 'E_VALIDATION');
    }
    return value;
}
/** Validates, sorts, and freezes patches in writer-chain order. */
function freezePatches(writerId, patches) {
    const checked = requireArray(patches, 'patches').map(requirePatchInput);
    requireAllPatchesBelongToWriter(writerId, checked);
    const sorted = [...checked].sort(comparePatches);
    requireContiguousWriterSequence(sorted);
    requireUnique(sorted.map((patch) => patch.patchId), 'patch id');
    return Object.freeze(sorted);
}
/** Requires an array field. */
function requireArray(items, label) {
    if (items === null || items === undefined || !Array.isArray(items)) {
        throw new WarpError(`GraphModelMigrationHistorySegment ${label} must be an array`, 'E_VALIDATION');
    }
    const checkedItems = items;
    return checkedItems;
}
/** Requires a history patch input instance. */
function requirePatchInput(patch) {
    if (!(patch instanceof GraphModelMigrationHistoryPatchInput)) {
        throw new WarpError('patches must contain history patch inputs', 'E_VALIDATION');
    }
    return patch;
}
/** Requires every patch in the segment to belong to the segment writer. */
function requireAllPatchesBelongToWriter(writerId, patches) {
    for (const patch of patches) {
        if (patch.writerId !== writerId) {
            throw new WarpError(`patch ${patch.patchId} belongs to the wrong writer`, 'E_VALIDATION');
        }
    }
}
/** Requires writer sequences to be contiguous from zero. */
function requireContiguousWriterSequence(patches) {
    patches.forEach((patch, position) => {
        if (patch.writerSequence !== position) {
            throw new WarpError('writer patch order must be contiguous per writer', 'E_VALIDATION');
        }
    });
}
/** Requires no duplicate keys in a history segment. */
function requireUnique(keys, label) {
    const seen = new Set();
    for (const key of keys) {
        if (seen.has(key)) {
            throw new WarpError(`GraphModelMigrationHistorySegment duplicates ${label} ${key}`, 'E_VALIDATION');
        }
        seen.add(key);
    }
}
/** Compares history patch inputs by writer sequence. */
function comparePatches(left, right) {
    if (left.writerSequence < right.writerSequence) {
        return -1;
    }
    if (left.writerSequence > right.writerSequence) {
        return 1;
    }
    return 0;
}
