#!/usr/bin/env node
import { execSync } from "node:child_process";
/**
 * Bump version in package.json, then sync platform packages and pkg/package.json.
 * Usage: node scripts/bump-version.mjs <new-version>
 */
import { existsSync, readFileSync, writeFileSync } from "node:fs";
import { resolve } from "node:path";

const __dirname = import.meta.dirname;
const root = resolve(__dirname, "..");

const newVersion = process.argv[2];
if (!newVersion || !/^\d+\.\d+\.\d+$/.test(newVersion)) {
	console.error("Usage: node scripts/bump-version.mjs <X.Y.Z>");
	process.exit(1);
}

// 1. Update root package.json
const pkgPath = resolve(root, "package.json");
const pkg = JSON.parse(readFileSync(pkgPath, "utf-8"));
const oldVersion = pkg.version;
pkg.version = newVersion;
writeFileSync(pkgPath, JSON.stringify(pkg, null, 2) + "\n");
console.log(`[bump-version] package.json: ${oldVersion} → ${newVersion}`);

// 2. Update all non-private workspace packages under packages/
//    These share the root version to keep the repo's source of truth coherent
//    with what ships. The web package is private and has its own lifecycle.
const workspacePackages = [
	"daemon",
	"native",
	"agent-core",
	"ai",
	"coding-agent",
	"tui",
	"rpc-client",
];
for (const name of workspacePackages) {
	const wsPath = resolve(root, "packages", name, "package.json");
	if (!existsSync(wsPath)) continue;
	const ws = JSON.parse(readFileSync(wsPath, "utf-8"));
	const wsOld = ws.version;
	ws.version = newVersion;
	// Bump any internal @singularity-forge/* or @singularity-forge/* dep references to match.
	for (const field of ["dependencies", "devDependencies", "peerDependencies"]) {
		if (!ws[field]) continue;
		for (const dep of Object.keys(ws[field])) {
			if (
				workspacePackages.some(
					(n) =>
						dep === `@singularity-forge/${n}` ||
						dep === `@singularity-forge/${n}`,
				)
			) {
				ws[field][dep] = `^${newVersion}`;
			}
		}
	}
	writeFileSync(wsPath, JSON.stringify(ws, null, 2) + "\n");
	console.log(`[bump-version] ${name}: ${wsOld} → ${newVersion}`);
}

// 3. Sync platform package versions (reads from root package.json)
execSync("node rust-engine/scripts/sync-platform-versions.cjs", {
	cwd: root,
	stdio: "inherit",
});

// 4. Sync pkg/package.json (reads from coding-agent)
execSync("node scripts/sync-pkg-version.cjs", { cwd: root, stdio: "inherit" });

// 5. Regenerate root package-lock.json to match the new version.
//    --package-lock-only updates the lockfile in-place without touching node_modules.
execSync("npm install --package-lock-only --ignore-scripts", {
	cwd: root,
	stdio: "inherit",
});
console.log(`[bump-version] package-lock.json regenerated at ${newVersion}`);

// 6. Regenerate web/package-lock.json if the web app is present.
const webDir = resolve(root, "web");
if (existsSync(webDir)) {
	execSync("npm install --package-lock-only --ignore-scripts", {
		cwd: webDir,
		stdio: "inherit",
	});
	console.log(`[bump-version] web/package-lock.json regenerated`);
}
