import MemoryBudgetError from "../../errors/MemoryBudgetError.js";
import WarpMemoryPool from "../../memory/WarpMemoryPool.js";
/** QueryReadModel wrapper that leases each streamed result from an explicit memory pool. */
export default class BoundedQueryReadModel {
    stateHash;
    _source;
    _pool;
    constructor(fields) {
        const validFields = requireReadModelFields(fields);
        this._source = requireQueryReadModel(validFields.source);
        this._pool = requireWarpMemoryPool(validFields.pool);
        this.stateHash = this._source.stateHash;
        Object.freeze(this);
    }
    async *nodes(request) {
        for await (const node of this._source.nodes(request)) {
            const lease = this._pool.acquire({ scope: 'query.nodes.result', amount: 1 });
            try {
                yield node;
            }
            finally {
                lease.release();
            }
        }
    }
    async *neighbors(nodeId, options) {
        for await (const neighbor of this._source.neighbors(nodeId, options)) {
            const lease = this._pool.acquire({ scope: 'query.neighbors.result', amount: 1 });
            try {
                yield neighbor;
            }
            finally {
                lease.release();
            }
        }
    }
    async nodeProps(nodeId) {
        const lease = this._pool.acquire({ scope: 'query.nodeProps.result', amount: 1 });
        try {
            return await this._source.nodeProps(nodeId);
        }
        finally {
            lease.release();
        }
    }
}
function requireReadModelFields(fields) {
    if (fields !== null && typeof fields === 'object') {
        return fields;
    }
    throw new MemoryBudgetError('BoundedQueryReadModel requires object fields', {
        code: 'E_MEMORY_BUDGET_INVALID',
        context: { field: 'fields' },
    });
}
function requireQueryReadModel(value) {
    if (hasQueryReadModelShape(value)) {
        return value;
    }
    throw new MemoryBudgetError('BoundedQueryReadModel requires a QueryReadModel source', {
        code: 'E_MEMORY_BUDGET_INVALID',
        context: { field: 'source' },
    });
}
function hasQueryReadModelShape(value) {
    if (value === null || typeof value !== 'object') {
        return false;
    }
    return hasQueryReadModelMembers(value);
}
function hasQueryReadModelMembers(value) {
    return typeof value.stateHash === 'string'
        && typeof value.nodes === 'function'
        && typeof value.neighbors === 'function'
        && typeof value.nodeProps === 'function';
}
function requireWarpMemoryPool(value) {
    if (value instanceof WarpMemoryPool) {
        return value;
    }
    throw new MemoryBudgetError('BoundedQueryReadModel requires a WarpMemoryPool', {
        code: 'E_MEMORY_BUDGET_INVALID',
        context: { field: 'pool' },
    });
}
