/**
 * ConflictCandidate — runtime-backed intermediate conflict record before trace assembly.
 *
 * @module domain/services/strand/ConflictCandidate
 */
import ConflictTarget from "../../types/conflict/ConflictTarget.js";
import ConflictResolution from "../../types/conflict/ConflictResolution.js";
import OpRecord from "./OpRecord.js";
import { requireEnum } from "../../types/conflict/validation.js";
import StrandError from "../../errors/StrandError.js";
const CTX = 'ConflictCandidate';
const VALID_KINDS = new Set(['supersession', 'eventual_override', 'redundancy']);
/**
 * Asserts that a value is an instance of the given constructor, else
 * throws a StrandError with the supplied field descriptor.
 */
function assertInstance(value, expectedClass, options) {
    if (!(value instanceof expectedClass)) {
        throw new StrandError(`${CTX}: ${options.fieldName} must be ${options.expectedLabel}`, { code: options.code });
    }
}
/**
 * A runtime-backed intermediate conflict record classified during candidate collection.
 *
 * Instances are frozen on construction.
 */
export default class ConflictCandidate {
    kind;
    target;
    winner;
    loser;
    resolution;
    noteCodes;
    constructor({ kind, target, winner, loser, resolution, noteCodes }) {
        assertInstance(target, ConflictTarget, { fieldName: 'target', code: 'E_CANDIDATE_INVALID_TARGET', expectedLabel: 'a ConflictTarget instance' });
        assertInstance(winner, OpRecord, { fieldName: 'winner', code: 'E_CANDIDATE_INVALID_WINNER', expectedLabel: 'an OpRecord instance' });
        assertInstance(loser, OpRecord, { fieldName: 'loser', code: 'E_CANDIDATE_INVALID_LOSER', expectedLabel: 'an OpRecord instance' });
        assertInstance(resolution, ConflictResolution, { fieldName: 'resolution', code: 'E_CANDIDATE_INVALID_RESOLUTION', expectedLabel: 'a ConflictResolution instance' });
        // requireEnum validates kind is one of VALID_KINDS
        requireEnum(kind, VALID_KINDS, { name: 'kind', context: CTX });
        this.kind = kind;
        this.target = target;
        this.winner = winner;
        this.loser = loser;
        this.resolution = resolution;
        this.noteCodes = Object.freeze(noteCodes.slice());
        Object.freeze(this);
    }
}
