/**
 * Immutable snapshot builders for public read-side returns.
 *
 * Snapshot construction is source-specific. This module does not preserve
 * unsupported class instances, clone prototypes, or reconstruct objects by
 * copying descriptors.
 *
 * @module domain/services/ImmutableSnapshot
 */
import { LWWRegister } from "../crdt/LWW.js";
import WarpError from "../errors/WarpError.js";
import { TickReceipt } from "../types/TickReceipt.js";
import ImmutableBytes from "./snapshot/ImmutableBytes.js";
import SnapshotORSet from "./snapshot/SnapshotORSet.js";
import SnapshotVersionVector from "./snapshot/SnapshotVersionVector.js";
import SnapshotWarpState from "./snapshot/SnapshotWarpState.js";
import WarpState from "./state/WarpState.js";
class ReadonlySnapshotPropMap extends Map {
    #sealed = false;
    constructor(source) {
        super();
        for (const [key, value] of source) {
            super.set(key, createLwwRegisterSnapshot(value));
        }
        this.#sealed = true;
    }
    set(key, value) {
        if (this.#sealed) {
            throw createReadonlyMutationError('Map', 'set');
        }
        return super.set(key, value);
    }
    delete(key) {
        if (this.#sealed) {
            throw createReadonlyMutationError('Map', 'delete');
        }
        return super.delete(key);
    }
    clear() {
        if (this.#sealed) {
            throw createReadonlyMutationError('Map', 'clear');
        }
        super.clear();
    }
}
class ReadonlySnapshotEventMap extends Map {
    #sealed = false;
    constructor(source) {
        super();
        for (const [key, value] of source) {
            super.set(key, value);
        }
        this.#sealed = true;
    }
    set(key, value) {
        if (this.#sealed) {
            throw createReadonlyMutationError('Map', 'set');
        }
        return super.set(key, value);
    }
    delete(key) {
        if (this.#sealed) {
            throw createReadonlyMutationError('Map', 'delete');
        }
        return super.delete(key);
    }
    clear() {
        if (this.#sealed) {
            throw createReadonlyMutationError('Map', 'clear');
        }
        super.clear();
    }
}
/**
 * Build a domain error for attempts to mutate a read-only collection snapshot.
 */
function createReadonlyMutationError(kind, method) {
    return new WarpError(`${kind} snapshot is read-only; ${method}() is not allowed`, 'E_IMMUTABLE_SNAPSHOT_MUTATION', { context: { kind, method } });
}
function createUnsupportedSnapshotSourceError(expected) {
    return new WarpError(`unsupported snapshot source: expected ${expected}`, 'E_IMMUTABLE_SNAPSHOT_UNSUPPORTED_SOURCE', { context: { expected } });
}
function createReadonlyPropMap(source) {
    const snapshot = new ReadonlySnapshotPropMap(source);
    Object.freeze(snapshot);
    return snapshot;
}
function createReadonlyEventMap(source) {
    const snapshot = new ReadonlySnapshotEventMap(source);
    Object.freeze(snapshot);
    return snapshot;
}
function createSnapshotPropValueArray(source) {
    const snapshot = [];
    for (const value of source) {
        snapshot.push(createSnapshotPropValue(value));
    }
    return Object.freeze(snapshot);
}
function createSnapshotPropValueObject(source) {
    const snapshot = {};
    for (const [key, value] of Object.entries(source)) {
        Object.defineProperty(snapshot, key, {
            value: createSnapshotPropValue(value),
            enumerable: true,
            configurable: false,
            writable: false,
        });
    }
    return Object.freeze(snapshot);
}
export function createSnapshotPropValue(source) {
    if (source instanceof Uint8Array) {
        return new ImmutableBytes(source);
    }
    if (Array.isArray(source)) {
        return createSnapshotPropValueArray(source);
    }
    if (source !== null && typeof source === 'object') {
        return createSnapshotPropValueObject(source);
    }
    return source;
}
export function createSnapshotPropertyValues(source) {
    return createSnapshotPropValueObject(source);
}
function createLwwRegisterSnapshot(source) {
    return new LWWRegister(source.eventId, createSnapshotPropValue(source.value));
}
export function createSnapshotORSet(value) {
    return new SnapshotORSet(value);
}
export function createSnapshotVersionVector(value) {
    return new SnapshotVersionVector(value);
}
export function createSnapshotWarpState(state) {
    if (!(state instanceof WarpState)) {
        throw createUnsupportedSnapshotSourceError('WarpState');
    }
    return new SnapshotWarpState({
        nodeAlive: createSnapshotORSet(state.nodeAlive),
        edgeAlive: createSnapshotORSet(state.edgeAlive),
        prop: createReadonlyPropMap(state.allPropEntries()),
        observedFrontier: createSnapshotVersionVector(state.observedFrontier),
        edgeBirthEvent: createReadonlyEventMap(state.edgeBirthEvent),
    });
}
/**
 * Create a detached, immutable public snapshot of a WarpState instance.
 */
export function createImmutableWarpStateSnapshot(state) {
    return createSnapshotWarpState(state);
}
/**
 * Create a detached, frozen public snapshot of materialization receipts.
 */
export function createImmutableTickReceiptArraySnapshot(receipts) {
    if (!Array.isArray(receipts)) {
        throw createUnsupportedSnapshotSourceError('TickReceipt[]');
    }
    const snapshot = [];
    for (const receipt of receipts) {
        if (!(receipt instanceof TickReceipt)) {
            throw createUnsupportedSnapshotSourceError('TickReceipt[]');
        }
        snapshot.push(receipt);
    }
    return Object.freeze(snapshot);
}
export { ImmutableBytes, SnapshotORSet, SnapshotVersionVector, SnapshotWarpState };
