import { oauthErrorHtml, oauthSuccessHtml } from "./oauth-page.js";
import { generatePKCE } from "./pkce.js";
//#region src/auth/oauth/vendor-pi-google/google-antigravity.ts
let _createServer = null;
let _httpImportPromise = null;
if (typeof process !== "undefined" && (process.versions?.node || process.versions?.bun)) _httpImportPromise = import("node:http").then((m) => {
	_createServer = m.createServer;
});
const ANTIGRAVITY_CLIENT_ID_ENV = "XOPC_GOOGLE_ANTIGRAVITY_OAUTH_CLIENT_ID";
const ANTIGRAVITY_CLIENT_SECRET_ENV = "XOPC_GOOGLE_ANTIGRAVITY_OAUTH_CLIENT_SECRET";
/** Desktop OAuth client for this flow — must be set locally (not committed; avoids GitHub push protection). */
function getAntigravityOAuthClient() {
	const clientId = process.env[ANTIGRAVITY_CLIENT_ID_ENV]?.trim();
	const clientSecret = process.env[ANTIGRAVITY_CLIENT_SECRET_ENV]?.trim();
	if (!clientId || !clientSecret) throw new Error(`Google Antigravity OAuth requires ${ANTIGRAVITY_CLIENT_ID_ENV} and ${ANTIGRAVITY_CLIENT_SECRET_ENV}.`);
	return {
		clientId,
		clientSecret
	};
}
const REDIRECT_URI = "http://localhost:51121/oauth-callback";
const SCOPES = [
	"https://www.googleapis.com/auth/cloud-platform",
	"https://www.googleapis.com/auth/userinfo.email",
	"https://www.googleapis.com/auth/userinfo.profile",
	"https://www.googleapis.com/auth/cclog",
	"https://www.googleapis.com/auth/experimentsandconfigs"
];
const AUTH_URL = "https://accounts.google.com/o/oauth2/v2/auth";
const TOKEN_URL = "https://oauth2.googleapis.com/token";
const DEFAULT_PROJECT_ID = "rising-fact-p41fc";
/**
* Start a local HTTP server to receive the OAuth callback
*/
async function getNodeCreateServer() {
	if (_createServer) return _createServer;
	if (_httpImportPromise) await _httpImportPromise;
	if (_createServer) return _createServer;
	throw new Error("Antigravity OAuth is only available in Node.js environments");
}
async function startCallbackServer() {
	const createServer = await getNodeCreateServer();
	return new Promise((resolve, reject) => {
		let settleWait;
		const waitForCodePromise = new Promise((resolveWait) => {
			let settled = false;
			settleWait = (value) => {
				if (settled) return;
				settled = true;
				resolveWait(value);
			};
		});
		const server = createServer((req, res) => {
			const url = new URL(req.url || "", `http://localhost:51121`);
			if (url.pathname === "/oauth-callback") {
				const code = url.searchParams.get("code");
				const state = url.searchParams.get("state");
				const error = url.searchParams.get("error");
				if (error) {
					res.writeHead(400, { "Content-Type": "text/html; charset=utf-8" });
					res.end(oauthErrorHtml("Google authentication did not complete.", `Error: ${error}`));
					return;
				}
				if (code && state) {
					res.writeHead(200, { "Content-Type": "text/html; charset=utf-8" });
					res.end(oauthSuccessHtml("Google authentication completed. You can close this window."));
					settleWait?.({
						code,
						state
					});
				} else {
					res.writeHead(400, { "Content-Type": "text/html; charset=utf-8" });
					res.end(oauthErrorHtml("Missing code or state parameter."));
				}
			} else {
				res.writeHead(404, { "Content-Type": "text/html; charset=utf-8" });
				res.end(oauthErrorHtml("Callback route not found."));
			}
		});
		server.on("error", (err) => {
			reject(err);
		});
		server.listen(51121, "127.0.0.1", () => {
			resolve({
				server,
				cancelWait: () => {
					settleWait?.(null);
				},
				waitForCode: () => waitForCodePromise
			});
		});
	});
}
/**
* Parse redirect URL to extract code and state
*/
function parseRedirectUrl(input) {
	const value = input.trim();
	if (!value) return {};
	try {
		const url = new URL(value);
		return {
			code: url.searchParams.get("code") ?? void 0,
			state: url.searchParams.get("state") ?? void 0
		};
	} catch {
		return {};
	}
}
/**
* Discover or provision a project for the user
*/
async function discoverProject(accessToken, onProgress) {
	const headers = {
		Authorization: `Bearer ${accessToken}`,
		"Content-Type": "application/json",
		"User-Agent": "google-api-nodejs-client/9.15.1",
		"X-Goog-Api-Client": "google-cloud-sdk vscode_cloudshelleditor/0.1",
		"Client-Metadata": JSON.stringify({
			ideType: "IDE_UNSPECIFIED",
			platform: "PLATFORM_UNSPECIFIED",
			pluginType: "GEMINI"
		})
	};
	const endpoints = ["https://cloudcode-pa.googleapis.com", "https://daily-cloudcode-pa.sandbox.googleapis.com"];
	onProgress?.("Checking for existing project...");
	for (const endpoint of endpoints) try {
		const loadResponse = await fetch(`${endpoint}/v1internal:loadCodeAssist`, {
			method: "POST",
			headers,
			body: JSON.stringify({ metadata: {
				ideType: "IDE_UNSPECIFIED",
				platform: "PLATFORM_UNSPECIFIED",
				pluginType: "GEMINI"
			} })
		});
		if (loadResponse.ok) {
			const data = await loadResponse.json();
			if (typeof data.cloudaicompanionProject === "string" && data.cloudaicompanionProject) return data.cloudaicompanionProject;
			if (data.cloudaicompanionProject && typeof data.cloudaicompanionProject === "object" && data.cloudaicompanionProject.id) return data.cloudaicompanionProject.id;
		}
	} catch {}
	onProgress?.("Using default project...");
	return DEFAULT_PROJECT_ID;
}
/**
* Get user email from the access token
*/
async function getUserEmail(accessToken) {
	try {
		const response = await fetch("https://www.googleapis.com/oauth2/v1/userinfo?alt=json", { headers: { Authorization: `Bearer ${accessToken}` } });
		if (response.ok) return (await response.json()).email;
	} catch {}
}
/**
* Refresh Antigravity token
*/
async function refreshAntigravityToken(refreshToken, projectId) {
	const { clientId, clientSecret } = getAntigravityOAuthClient();
	const response = await fetch(TOKEN_URL, {
		method: "POST",
		headers: { "Content-Type": "application/x-www-form-urlencoded" },
		body: new URLSearchParams({
			client_id: clientId,
			client_secret: clientSecret,
			refresh_token: refreshToken,
			grant_type: "refresh_token"
		})
	});
	if (!response.ok) {
		const error = await response.text();
		throw new Error(`Antigravity token refresh failed: ${error}`);
	}
	const data = await response.json();
	return {
		refresh: data.refresh_token || refreshToken,
		access: data.access_token,
		expires: Date.now() + data.expires_in * 1e3 - 300 * 1e3,
		projectId
	};
}
/**
* Login with Antigravity OAuth
*
* @param onAuth - Callback with URL and optional instructions
* @param onProgress - Optional progress callback
* @param onManualCodeInput - Optional promise that resolves with user-pasted redirect URL.
*                            Races with browser callback - whichever completes first wins.
*/
async function loginAntigravity(onAuth, onProgress, onManualCodeInput) {
	const { verifier, challenge } = await generatePKCE();
	const { clientId, clientSecret } = getAntigravityOAuthClient();
	onProgress?.("Starting local server for OAuth callback...");
	const server = await startCallbackServer();
	let code;
	try {
		onAuth({
			url: `${AUTH_URL}?${new URLSearchParams({
				client_id: clientId,
				response_type: "code",
				redirect_uri: REDIRECT_URI,
				scope: SCOPES.join(" "),
				code_challenge: challenge,
				code_challenge_method: "S256",
				state: verifier,
				access_type: "offline",
				prompt: "consent"
			}).toString()}`,
			instructions: "Complete the sign-in in your browser."
		});
		onProgress?.("Waiting for OAuth callback...");
		if (onManualCodeInput) {
			let manualInput;
			let manualError;
			const manualPromise = onManualCodeInput().then((input) => {
				manualInput = input;
				server.cancelWait();
			}).catch((err) => {
				manualError = err instanceof Error ? err : new Error(String(err));
				server.cancelWait();
			});
			const result = await server.waitForCode();
			if (manualError) throw manualError;
			if (result?.code) {
				if (result.state !== verifier) throw new Error("OAuth state mismatch - possible CSRF attack");
				code = result.code;
			} else if (manualInput) {
				const parsed = parseRedirectUrl(manualInput);
				if (parsed.state && parsed.state !== verifier) throw new Error("OAuth state mismatch - possible CSRF attack");
				code = parsed.code;
			}
			if (!code) {
				await manualPromise;
				if (manualError) throw manualError;
				if (manualInput) {
					const parsed = parseRedirectUrl(manualInput);
					if (parsed.state && parsed.state !== verifier) throw new Error("OAuth state mismatch - possible CSRF attack");
					code = parsed.code;
				}
			}
		} else {
			const result = await server.waitForCode();
			if (result?.code) {
				if (result.state !== verifier) throw new Error("OAuth state mismatch - possible CSRF attack");
				code = result.code;
			}
		}
		if (!code) throw new Error("No authorization code received");
		onProgress?.("Exchanging authorization code for tokens...");
		const tokenResponse = await fetch(TOKEN_URL, {
			method: "POST",
			headers: { "Content-Type": "application/x-www-form-urlencoded" },
			body: new URLSearchParams({
				client_id: clientId,
				client_secret: clientSecret,
				code,
				grant_type: "authorization_code",
				redirect_uri: REDIRECT_URI,
				code_verifier: verifier
			})
		});
		if (!tokenResponse.ok) {
			const error = await tokenResponse.text();
			throw new Error(`Token exchange failed: ${error}`);
		}
		const tokenData = await tokenResponse.json();
		if (!tokenData.refresh_token) throw new Error("No refresh token received. Please try again.");
		onProgress?.("Getting user info...");
		const email = await getUserEmail(tokenData.access_token);
		const projectId = await discoverProject(tokenData.access_token, onProgress);
		const expiresAt = Date.now() + tokenData.expires_in * 1e3 - 300 * 1e3;
		return {
			refresh: tokenData.refresh_token,
			access: tokenData.access_token,
			expires: expiresAt,
			projectId,
			email
		};
	} finally {
		server.server.close();
	}
}
const antigravityOAuthProvider = {
	id: "google-antigravity",
	name: "Antigravity (Gemini 3, Claude, GPT-OSS)",
	usesCallbackServer: true,
	async login(callbacks) {
		return loginAntigravity(callbacks.onAuth, callbacks.onProgress, callbacks.onManualCodeInput);
	},
	async refreshToken(credentials) {
		const creds = credentials;
		if (!creds.projectId) throw new Error("Antigravity credentials missing projectId");
		return refreshAntigravityToken(creds.refresh, creds.projectId);
	},
	getApiKey(credentials) {
		const creds = credentials;
		return JSON.stringify({
			token: creds.access,
			projectId: creds.projectId
		});
	}
};
//#endregion
export { antigravityOAuthProvider, loginAntigravity, refreshAntigravityToken };

//# sourceMappingURL=google-antigravity.js.map