import { defineHandler } from '@kb-labs/sdk';
import { buildDependencyGraph, getReverseDependencies, getImpactAnalysis } from '@kb-labs/quality-core/graph';

// src/rest/handlers/graph-handler.ts
var graph_handler_default = defineHandler({
  async execute(ctx, input) {
    const { packageName, mode } = input.query ?? { mode: "stats" };
    const cacheKey = `quality:graph:${ctx.cwd}`;
    const cached = await ctx.platform.cache.get(cacheKey);
    let graph;
    if (cached) {
      graph = {
        nodes: new Map(Object.entries(cached.nodes).map(([key, value]) => [
          key,
          {
            ...value,
            deps: new Set(value.deps),
            devDeps: value.devDeps ? new Set(value.devDeps) : void 0,
            dependents: new Set(value.dependents)
          }
        ])),
        workspacePackages: new Set(cached.workspacePackages)
      };
    } else {
      graph = buildDependencyGraph(ctx.cwd);
      const serialized = {
        nodes: Object.fromEntries(
          Array.from(graph.nodes.entries()).map(([key, value]) => [
            key,
            {
              ...value,
              deps: Array.from(value.deps),
              devDeps: value.devDeps ? Array.from(value.devDeps) : void 0,
              dependents: Array.from(value.dependents)
            }
          ])
        ),
        workspacePackages: Array.from(graph.workspacePackages)
      };
      await ctx.platform.cache.set(cacheKey, serialized, 12e4);
    }
    if (mode === "stats") {
      return {
        mode,
        stats: calculateGraphStats(graph)
      };
    }
    if (mode === "tree") {
      if (!packageName) {
        const rootPackages = [];
        for (const [name, node] of graph.nodes) {
          if (node.dependents.size === 0) {
            rootPackages.push(name);
          }
        }
        return {
          mode,
          tree: {
            name: "Root Packages",
            children: rootPackages.map((pkg) => buildDependencyTree(graph, pkg))
          }
        };
      }
      return {
        mode,
        packageName,
        tree: buildDependencyTree(graph, packageName)
      };
    }
    if (!packageName) {
      throw new Error("packageName is required for reverse and impact modes");
    }
    if (mode === "reverse") {
      const reverseDeps = getReverseDependencies(graph, packageName);
      return {
        mode,
        packageName,
        packages: Array.from(reverseDeps)
      };
    }
    if (mode === "impact") {
      const affected = getImpactAnalysis(graph, packageName);
      return {
        mode,
        packageName,
        packages: Array.from(affected)
      };
    }
    throw new Error(`Unknown mode: ${mode}`);
  }
});
function buildDependencyTree(graph, packageName, visited = /* @__PURE__ */ new Set()) {
  const node = graph.nodes.get(packageName);
  if (!node) {
    return { name: packageName, children: [] };
  }
  if (visited.has(packageName)) {
    return { name: `${packageName} (circular)`, children: [] };
  }
  visited.add(packageName);
  const children = Array.from(node.deps).map(
    (dep) => buildDependencyTree(graph, dep, new Set(visited))
  );
  return {
    name: packageName,
    children
  };
}
function calculateGraphStats(graph) {
  const { nodes } = graph;
  let totalDeps = 0;
  for (const node of nodes.values()) {
    totalDeps += node.deps.size;
  }
  const avgDeps = nodes.size > 0 ? totalDeps / nodes.size : 0;
  let maxDepth = 0;
  for (const [name] of nodes) {
    const depth = calculateDepth(graph, name, /* @__PURE__ */ new Set());
    if (depth > maxDepth) {
      maxDepth = depth;
    }
  }
  const dependentCounts = /* @__PURE__ */ new Map();
  for (const node of nodes.values()) {
    for (const dep of node.deps) {
      dependentCounts.set(dep, (dependentCounts.get(dep) ?? 0) + 1);
    }
  }
  const mostDepended = Array.from(dependentCounts.entries()).map(([name, count]) => ({ name, count })).sort((a, b) => b.count - a.count).slice(0, 5);
  return {
    totalPackages: nodes.size,
    maxDepth,
    avgDependencies: Number.parseFloat(avgDeps.toFixed(2)),
    mostDepended
  };
}
function calculateDepth(graph, packageName, visited) {
  const node = graph.nodes.get(packageName);
  if (!node || visited.has(packageName)) {
    return 0;
  }
  visited.add(packageName);
  let maxChildDepth = 0;
  for (const dep of node.deps) {
    const depth = calculateDepth(graph, dep, new Set(visited));
    if (depth > maxChildDepth) {
      maxChildDepth = depth;
    }
  }
  return 1 + maxChildDepth;
}

export { graph_handler_default as default };
//# sourceMappingURL=graph-handler.js.map
//# sourceMappingURL=graph-handler.js.map