import { spawn } from "node:child_process";
import { tmpdir } from "node:os";
import { resolvePackagePath } from "../../src/config/package-paths";

/** Reads the version from the installed package manifest. */
export async function readInstalledVersion(): Promise<string> {
  const metadata: unknown = await Bun.file(resolvePackagePath("package.json")).json();
  if (
    metadata === null ||
    typeof metadata !== "object" ||
    !("version" in metadata) ||
    typeof metadata.version !== "string"
  ) {
    throw new Error("Cartethyia package version is unavailable");
  }
  return metadata.version;
}

/** Asks the npm registry for the newest published version, or null on failure. */
export async function readLatestPublishedVersion(): Promise<string | null> {
  try {
    const response = await fetch("https://registry.npmjs.org/cartethyia/latest", {
      signal: AbortSignal.timeout(4_000),
    });
    if (!response.ok) return null;
    const metadata: unknown = await response.json();
    if (
      metadata !== null &&
      typeof metadata === "object" &&
      "version" in metadata &&
      typeof metadata.version === "string"
    ) {
      return metadata.version;
    }
    return null;
  } catch {
    return null;
  }
}

/**
 * Runs `npm install --global cartethyia@latest`. On Windows npm is a shell
 * script, so it has to go through cmd.exe rather than being spawned directly.
 */
export function npmUpdate(): Promise<number> {
  return new Promise((resolveExit) => {
    const command = process.platform === "win32" ? "cmd.exe" : "npm";
    const args =
      process.platform === "win32"
        ? ["/d", "/s", "/c", "npm install --global cartethyia@latest"]
        : ["install", "--global", "cartethyia@latest"];
    let child;
    try {
      child = spawn(command, args, { cwd: tmpdir(), stdio: "inherit" });
    } catch {
      console.error("Could not start npm. Install Node.js with npm, then retry the update.");
      resolveExit(1);
      return;
    }
    child.once("error", () => {
      console.error("Could not start npm. Install Node.js with npm, then retry the update.");
      resolveExit(1);
    });
    child.once("exit", (code) => resolveExit(code ?? 1));
  });
}
