/**
 * Shared Python-runtime probes. Used by Kokoro synthesis (which must
 * actually `import` a module before using it) and by the `auth status` /
 * `doctor` readiness checks (which only need to know whether a module is
 * installed, cheaply, without paying the cost of importing heavy packages
 * like torch).
 */

import { execFileSync } from "node:child_process";

/** Locate a Python 3: `HYPERFRAMES_PYTHON` env override first, then PATH. */
export function findPython(): string | undefined {
  const override = process.env.HYPERFRAMES_PYTHON;
  if (override) {
    try {
      const version = execFileSync(override, ["--version"], {
        encoding: "utf-8",
        stdio: ["pipe", "pipe", "pipe"],
        timeout: 5000,
      });
      if (/Python 3/.test(version)) return override;
    } catch {
      // fall through to the PATH probe
    }
  }
  for (const name of ["python3", "python"]) {
    try {
      const cmd = process.platform === "win32" ? "where" : "which";
      const output = execFileSync(cmd, [name], {
        encoding: "utf-8",
        stdio: ["pipe", "pipe", "pipe"],
        timeout: 5000,
      });
      const first = output
        .split(/\r?\n/)
        .map((s) => s.trim())
        .find(Boolean);
      if (!first) continue;

      // Verify it's Python 3
      const version = execFileSync(first, ["--version"], {
        encoding: "utf-8",
        stdio: ["pipe", "pipe", "pipe"],
        timeout: 5000,
      }).trim();

      if (version.includes("Python 3")) return first;
    } catch {
      // not found or not Python 3
    }
  }
  return undefined;
}

/** True if `import <pkg>` succeeds — actually executes the module. */
export function hasPythonPackage(python: string, pkg: string): boolean {
  try {
    execFileSync(python, ["-c", `import ${pkg}`], {
      stdio: ["pipe", "pipe", "pipe"],
      timeout: 10_000,
    });
    return true;
  } catch {
    return false;
  }
}

/**
 * True if every module is installed, checked via `importlib.util.find_spec`
 * so heavy packages (torch) are never imported — fast enough for a preflight.
 * Returns false when no Python 3 is found.
 */
export function hasPythonModules(modules: string[]): boolean {
  const python = findPython();
  if (!python) return false;
  const list = JSON.stringify(modules);
  const probe = `import importlib.util,sys; sys.exit(0 if all(importlib.util.find_spec(m) for m in ${list}) else 1)`;
  try {
    execFileSync(python, ["-c", probe], {
      stdio: ["pipe", "pipe", "pipe"],
      timeout: 10_000,
    });
    return true;
  } catch {
    return false;
  }
}
