/**
 * Port interface for neighbor lookups on any graph.
 *
 * Concrete providers back this with in-memory adjacency maps, bitmap indexes,
 * or remote APIs. All providers MUST return edges sorted by (neighborId, label)
 * using strict codepoint comparison (never localeCompare).
 */
import NeighborProviderError from "../domain/errors/NeighborProviderError.js";
const VALID_DIRECTIONS = new Set(['out', 'in', 'both']);
export function isDirection(value) {
    return VALID_DIRECTIONS.has(value);
}
export class NeighborEdge {
    neighborId;
    label;
    constructor(neighborId, label) {
        if (typeof neighborId !== 'string' || neighborId.length === 0) {
            throw new NeighborProviderError('neighborId must be a non-empty string', {
                code: NeighborProviderError.E_INVALID_NEIGHBOR_ID,
                context: { neighborId },
            });
        }
        if (typeof label !== 'string') {
            throw new NeighborProviderError('label must be a string', {
                code: NeighborProviderError.E_INVALID_NEIGHBOR_LABEL,
                context: { label },
            });
        }
        this.neighborId = neighborId;
        this.label = label;
        Object.freeze(this);
    }
    static from(edge) {
        return edge instanceof NeighborEdge ? edge : new NeighborEdge(edge.neighborId, edge.label);
    }
}
/** Port for neighbor lookups on any graph. */
export default class NeighborProviderPort {
    /**
     * Returns the latency class of this provider.
     *
     * Used by GraphTraversal to decide whether to enable neighbor memoization.
     * - 'sync': in-memory, no benefit from caching (e.g., AdjacencyNeighborProvider)
     * - 'async-local': disk-backed, caching avoids repeated reads (e.g., BitmapNeighborProvider)
     * - 'async-remote': network-backed, caching critical
     */
    get latencyClass() {
        return 'async-local';
    }
}
