import QueryError from "../../errors/QueryError.js";
import CheckpointTailWitnessLocator from "./CheckpointTailWitnessLocator.js";
import Optic from "./Optic.js";
import OpticSupportRule from "./OpticSupportRule.js";
import { TraversalOpticCursor, } from "./TraversalOpticReadResult.js";
export default class TraversalOptic {
    _optic;
    _locator;
    constructor(options) {
        this._optic = validateTraversalOptic(options.optic);
        this._locator = validateLocator(options.locator);
        Object.freeze(this);
    }
    toOptic(options = {}) {
        return this._optic.withSupportRule(traversalSupportRule(options));
    }
    async read(options = {}) {
        return await this._locator.readTraversal(this.toOptic(options), options);
    }
}
export { TraversalOpticCursor };
function validateTraversalOptic(optic) {
    if (!(optic instanceof Optic) || optic.target.opticKind !== 'traversal') {
        throwTraversalOpticError('optic', 'invalid-optic');
    }
    return optic;
}
function validateLocator(locator) {
    if (!(locator instanceof CheckpointTailWitnessLocator)) {
        throwTraversalOpticError('locator', 'invalid-locator');
    }
    return locator;
}
function throwTraversalOpticError(field, reason) {
    throw new QueryError('Traversal optic is invalid.', {
        code: 'E_TRAVERSAL_OPTIC',
        context: { field, reason },
    });
}
function traversalSupportRule(options) {
    if (options.maxDepth === undefined
        || options.maxNodes === undefined
        || options.maxEdges === undefined) {
        return OpticSupportRule.globalDiscoveryRefused();
    }
    return OpticSupportRule.traversalWindow();
}
