import GraphModelMigrationPatchFrontierEvidence from "./GraphModelMigrationPatchFrontierEvidence.js";
import GraphModelMigrationPatchOperationFact from "./GraphModelMigrationPatchOperationFact.js";
import WarpError from "../errors/WarpError.js";
/** Runtime-backed ordered legacy patch input for migration planning. */
export default class GraphModelMigrationHistoryPatchInput {
    writerId;
    patchId;
    writerSequence;
    frontierEvidence;
    operations;
    constructor(fields) {
        const checkedFields = requireFields(fields);
        this.writerId = requireNonEmptyString(checkedFields.writerId, 'writerId');
        this.patchId = requireNonEmptyString(checkedFields.patchId, 'patchId');
        this.writerSequence = requireWriterSequence(checkedFields.writerSequence);
        this.frontierEvidence = requireOptionalFrontierEvidence(checkedFields.frontierEvidence);
        this.operations = freezeOperations(checkedFields.operations);
        Object.freeze(this);
    }
}
/** Validates the constructor envelope. */
function requireFields(fields) {
    if (fields === null || fields === undefined) {
        throw new WarpError('GraphModelMigrationHistoryPatchInput 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 a deterministic per-writer sequence number. */
function requireWriterSequence(value) {
    if (!Number.isSafeInteger(value) || value < 0) {
        throw new WarpError('writerSequence must be a non-negative safe integer', 'E_VALIDATION');
    }
    return value;
}
/** Requires frontier evidence when present. */
function requireOptionalFrontierEvidence(evidence) {
    if (evidence !== null && !(evidence instanceof GraphModelMigrationPatchFrontierEvidence)) {
        throw new WarpError('frontierEvidence must be a GraphModelMigrationPatchFrontierEvidence', 'E_VALIDATION');
    }
    return evidence;
}
/** Validates, sorts, and freezes patch operation facts. */
function freezeOperations(operations) {
    const checked = requireArray(operations, 'operations').map(requireOperationFact);
    const sorted = [...checked].sort(compareOperations);
    requireContiguousOperationIndexes(sorted);
    return Object.freeze(sorted);
}
/** Requires an array field. */
function requireArray(items, label) {
    if (items === null || items === undefined || !Array.isArray(items)) {
        throw new WarpError(`GraphModelMigrationHistoryPatchInput ${label} must be an array`, 'E_VALIDATION');
    }
    const checkedItems = items;
    return checkedItems;
}
/** Requires a patch operation fact instance. */
function requireOperationFact(operation) {
    if (!(operation instanceof GraphModelMigrationPatchOperationFact)) {
        throw new WarpError('operations must contain patch operation facts', 'E_VALIDATION');
    }
    return operation;
}
/** Requires operation indexes to be contiguous from zero. */
function requireContiguousOperationIndexes(operations) {
    operations.forEach((operation, position) => {
        if (operation.operationIndex !== position) {
            throw new WarpError('operation indexes must be contiguous per patch', 'E_VALIDATION');
        }
    });
}
/** Compares patch operation facts by operation index. */
function compareOperations(left, right) {
    if (left.operationIndex < right.operationIndex) {
        return -1;
    }
    if (left.operationIndex > right.operationIndex) {
        return 1;
    }
    return 0;
}
