/**
 * Trust V1 record — runtime-backed value object.
 *
 * Validated at the adapter boundary via fromDecoded(). No Zod —
 * integrity is guaranteed by git-cas (SHA-256 chunks), recordId
 * (content-addressed hash), and Ed25519 signatures.
 *
 * The signaturePayload is precomputed by the adapter from the raw
 * canonical form, so domain code never touches untyped wire data.
 *
 * @module domain/trust/TrustRecord
 * @see docs/specs/TRUST_CRYPTO_ALGORITHM.md
 */
import TrustError from "../errors/TrustError.js";
// -- Record type literal ------------------------------------------------------
const RECORD_TYPES = ['KEY_ADD', 'KEY_REVOKE', 'WRITER_BIND_ADD', 'WRITER_BIND_REVOKE'];
// -- Validation helpers -------------------------------------------------------
function requireString(obj, key, context) {
    const val = obj[key];
    if (typeof val !== 'string' || val.length === 0) {
        throw new TrustError(`${context}: missing or empty '${key}'`, { code: 'E_TRUST_RECORD_INVALID' });
    }
    return val;
}
function validateKeyAddSubject(subj) {
    return {
        keyId: requireString(subj, 'keyId', 'KEY_ADD subject'),
        publicKey: requireString(subj, 'publicKey', 'KEY_ADD subject'),
    };
}
function validateKeyRevokeSubject(subj) {
    return {
        keyId: requireString(subj, 'keyId', 'KEY_REVOKE subject'),
        reasonCode: requireString(subj, 'reasonCode', 'KEY_REVOKE subject'),
    };
}
function validateBindAddSubject(subj) {
    return {
        writerId: requireString(subj, 'writerId', 'WRITER_BIND_ADD subject'),
        keyId: requireString(subj, 'keyId', 'WRITER_BIND_ADD subject'),
    };
}
function validateBindRevokeSubject(subj) {
    return {
        writerId: requireString(subj, 'writerId', 'WRITER_BIND_REVOKE subject'),
        keyId: requireString(subj, 'keyId', 'WRITER_BIND_REVOKE subject'),
        reasonCode: requireString(subj, 'reasonCode', 'WRITER_BIND_REVOKE subject'),
    };
}
function validateSubject(recordType, subj) {
    switch (recordType) {
        case 'KEY_ADD': {
            return validateKeyAddSubject(subj);
        }
        case 'KEY_REVOKE': {
            return validateKeyRevokeSubject(subj);
        }
        case 'WRITER_BIND_ADD': {
            return validateBindAddSubject(subj);
        }
        case 'WRITER_BIND_REVOKE': {
            return validateBindRevokeSubject(subj);
        }
        default: {
            throw new TrustError(`Unknown record type: ${recordType}`, { code: 'E_TRUST_RECORD_INVALID' });
        }
    }
}
function validateSignature(sig) {
    if (sig.alg !== 'ed25519') {
        throw new TrustError(`Unsupported signature algorithm: ${sig.alg}`, { code: 'E_TRUST_RECORD_INVALID' });
    }
    if (typeof sig.sig !== 'string' || sig.sig.length === 0) {
        throw new TrustError('Empty signature', { code: 'E_TRUST_SIGNATURE_MISSING' });
    }
    return { alg: 'ed25519', sig: sig.sig };
}
// -- TrustRecord class --------------------------------------------------------
class TrustRecord {
    schemaVersion = 1;
    recordType;
    recordId;
    issuerKeyId;
    issuedAt;
    prev;
    subject;
    meta;
    signature;
    signaturePayload;
    constructor(recordType, recordId, issuerKeyId, issuedAt, prev, subject, meta, signature, signaturePayload) {
        this.recordType = recordType;
        this.recordId = recordId;
        this.issuerKeyId = issuerKeyId;
        this.issuedAt = issuedAt;
        this.prev = prev;
        this.subject = subject;
        this.meta = meta;
        this.signature = signature;
        this.signaturePayload = signaturePayload;
        Object.freeze(this);
    }
    /**
     * Constructs a TrustRecord from adapter-decoded data.
     *
     * The adapter is responsible for:
     * 1. CBOR decoding the raw blob (via git-cas)
     * 2. Verifying recordId against the raw canonical hash
     * 3. Computing signaturePayload from the raw canonical form
     * 4. Passing the decoded + verified data here for structural validation
     *
     * Throws TrustError on invalid structure.
     */
    static fromDecoded(input) {
        if (input.schemaVersion !== 1) {
            throw new TrustError(`Unsupported schema version: ${String(input.schemaVersion)}`, { code: 'E_TRUST_RECORD_INVALID' });
        }
        if (!RECORD_TYPES.includes(input.recordType)) {
            throw new TrustError(`Unknown record type: ${input.recordType}`, { code: 'E_TRUST_RECORD_INVALID' });
        }
        const recordType = input.recordType;
        return new TrustRecord(recordType, input.recordId, input.issuerKeyId, input.issuedAt, input.prev, validateSubject(recordType, input.subject), input.meta, validateSignature(input.signature), input.signaturePayload);
    }
    /** Type guard: is this a KEY_ADD record? */
    isKeyAdd() {
        return this.recordType === 'KEY_ADD';
    }
    /** Type guard: is this a KEY_REVOKE record? */
    isKeyRevoke() {
        return this.recordType === 'KEY_REVOKE';
    }
    /** Type guard: is this a WRITER_BIND_ADD record? */
    isBindAdd() {
        return this.recordType === 'WRITER_BIND_ADD';
    }
    /** Type guard: is this a WRITER_BIND_REVOKE record? */
    isBindRevoke() {
        return this.recordType === 'WRITER_BIND_REVOKE';
    }
}
export { TrustRecord, RECORD_TYPES };
