/**
 * find-security-sidecar — resolve the Node entry that runs the L4 ML
 * classifier sidecar.
 *
 * The sidecar can't be bundled into the compiled browse binary because
 * onnxruntime-node fails to dlopen from Bun's compile extract dir. It runs
 * as a separate Node subprocess instead. This module resolves the right
 * path + interpreter on each platform:
 *
 *   1. Prefer node on PATH + a bundled JS entry at
 *      browse/dist/security-sidecar.js (built by package.json's
 *      build:security-sidecar script).
 *   2. Dev fallback: node + browse/src/security-sidecar-entry.ts via tsx
 *      (only available in the source checkout, not the compiled install).
 *   3. If Node is missing or no entry resolves, return null. The /pty-inject-scan
 *      endpoint then responds with l4 { available: false } and the extension
 *      degrades to WARN+confirm (D7).
 */

import { existsSync } from "fs";
import { join, dirname } from "path";
import { execFileSync } from "child_process";

export interface SidecarLocation {
  node: string;
  entry: string;
  /** "compiled" if running from browse/dist/, "dev" if running from src */
  mode: "compiled" | "dev";
}

function nodeOnPath(): string | null {
  try {
    execFileSync("node", ["--version"], { stdio: "ignore", timeout: 2000, windowsHide: true });
    return "node";
  } catch {
    return null;
  }
}

function browseRoot(): string {
  // When running compiled, __dirname (via import.meta.dir) points at the
  // Bun extract temp. Walk up until we find a directory containing
  // browse/dist/ or browse/src/.
  let candidate = dirname(import.meta.path || "");
  for (let i = 0; i < 6; i += 1) {
    if (existsSync(join(candidate, "browse", "dist", "security-sidecar.js"))) {
      return candidate;
    }
    if (existsSync(join(candidate, "src", "security-sidecar-entry.ts"))) {
      return candidate;
    }
    const next = dirname(candidate);
    if (next === candidate) break;
    candidate = next;
  }
  return process.cwd();
}

export function findSecuritySidecar(): SidecarLocation | null {
  const node = nodeOnPath();
  if (!node) return null;

  const root = browseRoot();

  const compiled = join(root, "browse", "dist", "security-sidecar.js");
  if (existsSync(compiled)) {
    return { node, entry: compiled, mode: "compiled" };
  }

  // Dev fallback. Compiled installs won't have src/ on disk so this only
  // resolves when running from the source checkout.
  const devEntry = join(root, "src", "security-sidecar-entry.ts");
  if (existsSync(devEntry)) {
    return { node, entry: devEntry, mode: "dev" };
  }

  return null;
}
