#!/usr/bin/env node
/**
 * Headless derive: copy Grok Build OAuth into Pi auth.json as `xai-oauth`.
 *
 * Same rules as systray-ai PiAuthSync for Codex:
 * - Source of truth = ~/.grok/auth.json
 * - COPY tokens only — NEVER call auth.x.ai (refresh rotation revokes the shared session)
 *
 * Usage: node packages/pi-xai-oauth/import-from-grok.mjs
 */
import { readFile, writeFile, mkdir } from "node:fs/promises";
import { homedir } from "node:os";
import { join, dirname } from "node:path";

const PROVIDER = "xai-oauth";

function decodeJwtExpMs(access) {
	const parts = access.split(".");
	if (parts.length < 2) throw new Error("access token is not a JWT");
	const segment = parts[1];
	const padding = "=".repeat((4 - (segment.length % 4)) % 4);
	const claims = JSON.parse(Buffer.from(segment + padding, "base64url").toString("utf8"));
	if (typeof claims.exp !== "number") throw new Error("JWT missing numeric exp");
	return Math.trunc(claims.exp * 1000);
}

async function main() {
	const grokPath = process.env.GROK_AUTH_FILE || join(homedir(), ".grok", "auth.json");
	const piAuthPath = process.env.PI_AUTH_FILE || join(homedir(), ".pi", "agent", "auth.json");

	const grok = JSON.parse(await readFile(grokPath, "utf8"));
	let access = "";
	let refresh = "";
	let accountId;
	for (const [slot, entry] of Object.entries(grok)) {
		if (!entry || typeof entry !== "object") continue;
		const a = (entry.key || entry.access_token || "").trim();
		const r = (entry.refresh_token || "").trim();
		if (!a || !r) continue;
		if (!String(slot).includes("auth.x.ai") && !entry.oidc_client_id) continue;
		access = a;
		refresh = r;
		accountId = entry.principal_id || undefined;
		break;
	}
	if (!access || !refresh) {
		console.error(`No Grok OAuth tokens in ${grokPath}. Run: grok login`);
		process.exit(3);
	}

	const expires = decodeJwtExpMs(access);
	if (expires <= Date.now()) {
		console.error(
			"Grok access token already expired (JWT exp). " +
				"Do NOT use this script to hit the token endpoint. " +
				"Refresh via Grok CLI / `grok login`, then re-run this derive.",
		);
		process.exit(3);
	}

	const cred = {
		type: "oauth",
		access,
		refresh,
		expires,
	};
	if (accountId) cred.accountId = accountId;

	let pi = {};
	try {
		pi = JSON.parse(await readFile(piAuthPath, "utf8"));
	} catch {
		pi = {};
	}
	if (!pi || typeof pi !== "object") pi = {};
	pi[PROVIDER] = cred;

	await mkdir(dirname(piAuthPath), { recursive: true });
	await writeFile(piAuthPath, JSON.stringify(pi, null, 2) + "\n", { mode: 0o600 });
	const mins = Math.round((expires - Date.now()) / 60000);
	console.log(`derived ${PROVIDER} → ${piAuthPath} (access ~${mins}m left; no network)`);
}

main().catch((err) => {
	console.error(err);
	process.exit(1);
});
