"use strict";
var __defProp = Object.defineProperty;
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
var __getOwnPropNames = Object.getOwnPropertyNames;
var __hasOwnProp = Object.prototype.hasOwnProperty;
var __export = (target, all) => {
  for (var name in all)
    __defProp(target, name, { get: all[name], enumerable: true });
};
var __copyProps = (to, from, except, desc) => {
  if (from && typeof from === "object" || typeof from === "function") {
    for (let key of __getOwnPropNames(from))
      if (!__hasOwnProp.call(to, key) && key !== except)
        __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
  }
  return to;
};
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
var traversal_exports = {};
__export(traversal_exports, {
  GraphTraverser: () => GraphTraverser
});
module.exports = __toCommonJS(traversal_exports);
class GraphTraverser {
  constructor(db) {
    this.db = db;
  }
  /**
   * Breadth-first traversal from startId.
   * Visits all nodes at depth D before any node at depth D+1.
   */
  async traverseBFS(startId, opts = {}) {
    const {
      maxDepth = Infinity,
      edgeKinds,
      nodeKinds,
      direction = "outgoing",
      limit = Infinity,
      includeStart = false
    } = opts;
    const visited = /* @__PURE__ */ new Set();
    const result = [];
    const queue = [[startId, 0]];
    visited.add(startId);
    while (queue.length > 0) {
      const [currentId, depth] = queue.shift();
      if (currentId === startId) {
        if (includeStart) {
          const node = this.db.getNode(currentId);
          if (node && this.matchesNodeKinds(node, nodeKinds)) {
            result.push(node);
            if (result.length >= limit) break;
          }
        }
      } else {
        const node = this.db.getNode(currentId);
        if (node && this.matchesNodeKinds(node, nodeKinds)) {
          result.push(node);
          if (result.length >= limit) break;
        }
      }
      if (depth >= maxDepth) continue;
      const neighbors = this.getNeighbors(currentId, direction, edgeKinds);
      for (const neighborId of neighbors) {
        if (!visited.has(neighborId)) {
          visited.add(neighborId);
          queue.push([neighborId, depth + 1]);
        }
      }
    }
    return result;
  }
  /**
   * Depth-first traversal from startId.
   */
  async traverseDFS(startId, opts = {}) {
    const {
      maxDepth = Infinity,
      edgeKinds,
      nodeKinds,
      direction = "outgoing",
      limit = Infinity,
      includeStart = false
    } = opts;
    const visited = /* @__PURE__ */ new Set();
    const result = [];
    const dfs = (currentId, depth) => {
      if (result.length >= limit) return;
      if (visited.has(currentId)) return;
      visited.add(currentId);
      if (currentId === startId) {
        if (includeStart) {
          const node = this.db.getNode(currentId);
          if (node && this.matchesNodeKinds(node, nodeKinds)) {
            result.push(node);
          }
        }
      } else {
        const node = this.db.getNode(currentId);
        if (node && this.matchesNodeKinds(node, nodeKinds)) {
          result.push(node);
        }
      }
      if (depth >= maxDepth) return;
      const neighbors = this.getNeighbors(currentId, direction, edgeKinds);
      for (const neighborId of neighbors) {
        if (!visited.has(neighborId)) {
          dfs(neighborId, depth + 1);
          if (result.length >= limit) return;
        }
      }
    };
    dfs(startId, 0);
    return result;
  }
  /**
   * Get neighbor node IDs from the database, filtered by direction and edge kinds.
   */
  getNeighbors(nodeId, direction, edgeKinds) {
    const neighbors = [];
    if (direction === "outgoing" || direction === "both") {
      const edges = this.getOutgoingEdges(nodeId, edgeKinds);
      for (const e of edges) neighbors.push(e.target);
    }
    if (direction === "incoming" || direction === "both") {
      const edges = this.getIncomingEdges(nodeId, edgeKinds);
      for (const e of edges) neighbors.push(e.target);
    }
    return neighbors;
  }
  getOutgoingEdges(nodeId, edgeKinds) {
    const allEdges = this.db.getEdgesForNodes([nodeId]);
    return allEdges.filter((e) => e.source === nodeId).filter((e) => !edgeKinds || edgeKinds.includes(e.kind)).map((e) => ({ target: e.target }));
  }
  getIncomingEdges(nodeId, edgeKinds) {
    const allEdges = this.db.getEdgesForNodes([nodeId]);
    return allEdges.filter((e) => e.target === nodeId).filter((e) => !edgeKinds || edgeKinds.includes(e.kind)).map((e) => ({ target: e.source }));
  }
  matchesNodeKinds(node, nodeKinds) {
    if (!nodeKinds || nodeKinds.length === 0) return true;
    return nodeKinds.includes(node.kind);
  }
}
// Annotate the CommonJS export names for ESM import in node:
0 && (module.exports = {
  GraphTraverser
});
//# sourceMappingURL=traversal.js.map
