import MemoryBudgetError from "../../errors/MemoryBudgetError.js";
import WarpMemoryPool from "../../memory/WarpMemoryPool.js";
import { compareEventIds } from "../../utils/EventId.js";
import { CheckpointContentAnchorFact, CheckpointEdgeFact, CheckpointNodeLivenessFact, CheckpointNodePropertyFact, } from "./CheckpointBasisFact.js";
/** Targeted resolver over checkpoint patch facts without full fact residency. */
export default class CheckpointFactResolver {
    _pool;
    constructor(fields) {
        const validFields = requireResolverFields(fields);
        this._pool = requireWarpMemoryPool(validFields.pool);
        Object.freeze(this);
    }
    async resolveNodeLiveness(facts, nodeId) {
        let latest = null;
        for await (const fact of facts) {
            const lease = this._pool.acquire({ scope: 'checkpoint.fact.node-liveness', amount: 1 });
            try {
                latest = newerMatch(matchingNodeLiveness(fact, nodeId), latest);
            }
            finally {
                lease.release();
            }
        }
        return latest?.alive ?? null;
    }
    async resolveEdgeEndpoints(facts, edge) {
        let latest = null;
        for await (const fact of facts) {
            const lease = this._pool.acquire({ scope: 'checkpoint.fact.edge-endpoints', amount: 1 });
            try {
                latest = newerMatch(matchingEdge(fact, edge), latest);
            }
            finally {
                lease.release();
            }
        }
        return latest === null ? null : edgeResolution(latest);
    }
    async resolveNodeProperty(facts, property) {
        let latest = null;
        for await (const fact of facts) {
            const lease = this._pool.acquire({ scope: 'checkpoint.fact.node-property', amount: 1 });
            try {
                latest = newerMatch(matchingNodeProperty(fact, property), latest);
            }
            finally {
                lease.release();
            }
        }
        return latest === null ? Object.freeze({ found: false, value: null }) : Object.freeze({ found: true, value: latest.value });
    }
    async resolveContentOid(facts, owner) {
        let latest = null;
        for await (const fact of facts) {
            const lease = this._pool.acquire({ scope: 'checkpoint.fact.content-anchor', amount: 1 });
            try {
                latest = newerMatch(matchingContentAnchor(fact, owner), latest);
            }
            finally {
                lease.release();
            }
        }
        return latest?.contentOid ?? null;
    }
}
function requireResolverFields(fields) {
    if (fields !== null && typeof fields === 'object') {
        return fields;
    }
    throw new MemoryBudgetError('CheckpointFactResolver requires object fields', {
        code: 'E_MEMORY_BUDGET_INVALID',
        context: { field: 'fields' },
    });
}
function requireWarpMemoryPool(value) {
    if (value instanceof WarpMemoryPool) {
        return value;
    }
    throw new MemoryBudgetError('CheckpointFactResolver requires a WarpMemoryPool', {
        code: 'E_MEMORY_BUDGET_INVALID',
        context: { field: 'pool' },
    });
}
function newerMatch(candidate, current) {
    if (candidate === null) {
        return current;
    }
    if (current === null || compareEventIds(candidate.eventId, current.eventId) > 0) {
        return candidate;
    }
    return current;
}
function matchingNodeLiveness(fact, nodeId) {
    if (fact instanceof CheckpointNodeLivenessFact && fact.nodeId === nodeId) {
        return fact;
    }
    return null;
}
function matchingEdge(fact, edge) {
    if (fact instanceof CheckpointEdgeFact && fact.from === edge.from && fact.to === edge.to && fact.label === edge.label) {
        return fact;
    }
    return null;
}
function matchingNodeProperty(fact, property) {
    if (fact instanceof CheckpointNodePropertyFact && fact.nodeId === property.nodeId && fact.key === property.key) {
        return fact;
    }
    return null;
}
function matchingContentAnchor(fact, owner) {
    if (fact instanceof CheckpointContentAnchorFact && fact.owner === owner) {
        return fact;
    }
    return null;
}
function edgeResolution(fact) {
    return Object.freeze({
        from: fact.from,
        to: fact.to,
        label: fact.label,
        alive: fact.alive,
    });
}
