import { createLogger } from "../../utils/logger/index.js";
import { init_logger } from "../../utils/logger.js";
import { CredentialResolver, init_credentials } from "../../auth/credentials.js";
import { anthropicOAuthProvider } from "../../auth/oauth/anthropic.js";
import { minimaxOAuthProvider } from "../../auth/oauth/minimax.js";
import { minimaxCnOAuthProvider } from "../../auth/oauth/minimax-cn.js";
import { kimiCodingOAuthProvider } from "../../auth/oauth/kimi-coding.js";
import { githubCopilotOAuthProvider } from "../../auth/oauth/github-copilot.js";
import { geminiCliOAuthProvider } from "../../auth/oauth/vendor-pi-google/google-gemini-cli.js";
import { antigravityOAuthProvider } from "../../auth/oauth/vendor-pi-google/google-antigravity.js";
import { openaiCodexOAuthProvider } from "../../auth/oauth/openai-codex.js";
import "../../auth/oauth/index.js";
import { Hono } from "hono";
//#region src/gateway/hono/oauth-async.ts
/**
* Async OAuth Handler
* 
* Provides non-blocking OAuth flow with session-based state management.
* This allows OAuth flows that require user interaction (browser login) 
* without blocking the HTTP request.
*/
init_logger();
init_credentials();
const log = createLogger("OAuthAsync");
/** User-facing message when undici/fetch fails (often DNS, firewall, or wrong machine for localhost callback). */
function formatOAuthAsyncError(err) {
	const base = err instanceof Error ? err.message : "OAuth login failed";
	const cause = err instanceof Error && err.cause instanceof Error ? err.cause.message : err instanceof Error && typeof err.cause === "string" ? err.cause : "";
	const detail = cause ? ` (${cause})` : "";
	if (/^fetch failed$/i.test(base) || base.includes("fetch failed")) return `Network request failed${detail}. If the browser opened on another device, the redirect goes to that device's localhost — copy the full URL from the browser address bar after sign-in (starts with http://127.0.0.1 or http://localhost) and paste it below. Otherwise check VPN/proxy/DNS/firewall access to Google OAuth.`;
	return base;
}
const OAUTH_PROVIDERS = {
	"kimi-coding": kimiCodingOAuthProvider,
	"minimax": minimaxOAuthProvider,
	"minimax-cn": minimaxCnOAuthProvider,
	"anthropic": anthropicOAuthProvider,
	"github-copilot": githubCopilotOAuthProvider,
	"google-gemini-cli": geminiCliOAuthProvider,
	"google-antigravity": antigravityOAuthProvider,
	"openai-codex": openaiCodexOAuthProvider
};
const oauthSessions = /* @__PURE__ */ new Map();
const SESSION_TTL_MS = 600 * 1e3;
setInterval(() => {
	const now = Date.now();
	for (const [id, session] of oauthSessions.entries()) if (now > session.expiresAt) {
		if (session.abortController) session.abortController.abort();
		oauthSessions.delete(id);
		log.debug({ sessionId: id }, "Cleaned up expired OAuth session");
	}
}, 60 * 1e3);
function generateSessionId() {
	return `oauth_${Date.now()}_${Math.random().toString(36).substring(2, 15)}`;
}
function createOAuthAsyncHandler(service) {
	const oauth = new Hono();
	/**
	* POST /api/auth/oauth-async/start
	* Start async OAuth flow - returns immediately with session ID
	*/
	oauth.post("/start", async (c) => {
		const { provider } = await c.req.json().catch(() => ({}));
		if (!provider) return c.json({ error: "Provider is required" }, 400);
		const oauthProvider = OAUTH_PROVIDERS[provider];
		if (!oauthProvider) return c.json({ error: `Unknown OAuth provider: ${provider}` }, 400);
		const sessionId = generateSessionId();
		const session = {
			id: sessionId,
			provider,
			status: "pending",
			createdAt: Date.now(),
			expiresAt: Date.now() + SESSION_TTL_MS
		};
		oauthSessions.set(sessionId, session);
		runOAuthFlow(session, oauthProvider, service).catch((err) => {
			log.error({
				sessionId,
				provider,
				error: err
			}, "Background OAuth flow failed");
			session.status = "failed";
			session.error = err instanceof Error ? err.message : "OAuth flow failed";
		});
		return c.json({
			ok: true,
			payload: {
				sessionId,
				provider,
				status: session.status
			}
		});
	});
	/**
	* GET /api/auth/oauth-async/:sessionId/status
	* Check OAuth session status
	*/
	oauth.get("/:sessionId/status", (c) => {
		const sessionId = c.req.param("sessionId");
		const session = oauthSessions.get(sessionId);
		if (!session) return c.json({ error: "Session not found" }, 404);
		return c.json({
			ok: true,
			payload: {
				sessionId: session.id,
				provider: session.provider,
				status: session.status,
				authUrl: session.authUrl,
				instructions: session.instructions,
				deviceCode: session.deviceCode,
				verificationUri: session.verificationUri,
				message: session.message,
				error: session.error,
				expiresAt: session.expiresAt
			}
		});
	});
	/**
	* POST /api/auth/oauth-async/:sessionId/code
	* Submit manual authorization code
	*/
	oauth.post("/:sessionId/code", async (c) => {
		const sessionId = c.req.param("sessionId");
		const { code } = await c.req.json().catch(() => ({}));
		if (!code) return c.json({ error: "Code is required" }, 400);
		const session = oauthSessions.get(sessionId);
		if (!session) return c.json({ error: "Session not found" }, 404);
		if (session.status !== "waiting_code" || !session.manualCodeResolve) return c.json({ error: "Session is not waiting for code" }, 400);
		session.manualCodeResolve(code);
		session.manualCodeResolve = void 0;
		session.manualCodeReject = void 0;
		return c.json({
			ok: true,
			payload: { message: "Code submitted, processing..." }
		});
	});
	/**
	* POST /api/auth/oauth-async/:sessionId/cancel
	* Cancel OAuth flow
	*/
	oauth.post("/:sessionId/cancel", async (c) => {
		const sessionId = c.req.param("sessionId");
		const session = oauthSessions.get(sessionId);
		if (!session) return c.json({ error: "Session not found" }, 404);
		if (session.abortController) session.abortController.abort();
		if (session.manualCodeReject) {
			session.manualCodeReject(/* @__PURE__ */ new Error("OAuth cancelled by user"));
			session.manualCodeReject = void 0;
			session.manualCodeResolve = void 0;
		}
		session.status = "cancelled";
		session.message = "OAuth flow cancelled";
		return c.json({
			ok: true,
			payload: { message: "OAuth flow cancelled" }
		});
	});
	/**
	* DELETE /api/auth/oauth-async/:sessionId
	* Clean up OAuth session
	*/
	oauth.delete("/:sessionId", (c) => {
		const sessionId = c.req.param("sessionId");
		if (oauthSessions.has(sessionId)) {
			const session = oauthSessions.get(sessionId);
			if (session.abortController) session.abortController.abort();
			oauthSessions.delete(sessionId);
		}
		return c.json({ ok: true });
	});
	return oauth;
}
/**
* Run OAuth flow in background
*/
async function runOAuthFlow(session, oauthProvider, _service) {
	const abortController = new AbortController();
	session.abortController = abortController;
	let manualCodePromise = null;
	let manualCodeResolve;
	let manualCodeReject;
	const callbacks = {
		onAuth: (auth) => {
			session.authUrl = auth.url;
			session.instructions = auth.instructions;
			if (oauthProvider.usesCallbackServer) {
				session.status = "waiting_code";
				session.message = "Complete authorization in browser, or paste the redirect URL below";
				manualCodePromise = new Promise((resolve, reject) => {
					manualCodeResolve = resolve;
					manualCodeReject = reject;
				});
				session.manualCodeResolve = manualCodeResolve;
				session.manualCodeReject = manualCodeReject;
			} else {
				session.status = "waiting_auth";
				session.message = "Complete authorization in browser";
			}
		},
		onPrompt: async (prompt) => {
			session.status = "waiting_code";
			session.deviceCode = prompt.deviceCode;
			session.verificationUri = prompt.verificationUri;
			session.message = prompt.message;
			manualCodePromise = new Promise((resolve, reject) => {
				manualCodeResolve = resolve;
				manualCodeReject = reject;
			});
			session.manualCodeResolve = manualCodeResolve;
			session.manualCodeReject = manualCodeReject;
			return "";
		},
		onProgress: (message) => {
			log.debug({
				sessionId: session.id,
				message
			}, "OAuth progress");
			session.message = message;
		},
		onManualCodeInput: async () => {
			if (manualCodePromise) return manualCodePromise;
			return "";
		},
		signal: abortController.signal
	};
	try {
		const credentials = await oauthProvider.login(callbacks);
		setOAuthCredentialsToCache(session.provider, credentials);
		const apiKey = oauthProvider.getApiKey(credentials);
		await new CredentialResolver().saveApiKey(session.provider, apiKey, { profileName: "default" });
		session.status = "completed";
		session.credentials = credentials;
		session.message = "OAuth login successful";
		log.info({
			sessionId: session.id,
			provider: session.provider
		}, "OAuth login completed");
	} catch (err) {
		if (abortController.signal.aborted) {
			session.status = "cancelled";
			session.message = "OAuth flow cancelled by user";
		} else {
			session.status = "failed";
			session.error = formatOAuthAsyncError(err);
			log.error({
				sessionId: session.id,
				provider: session.provider,
				error: err
			}, "OAuth login failed");
		}
	} finally {
		session.abortController = void 0;
		session.manualCodeResolve = void 0;
		session.manualCodeReject = void 0;
	}
}
const oauthCredentialsCache = /* @__PURE__ */ new Map();
function getOAuthCredentialsFromCache(provider) {
	return oauthCredentialsCache.get(provider);
}
function setOAuthCredentialsToCache(provider, creds) {
	oauthCredentialsCache.set(provider, creds);
}
function deleteOAuthCredentialsFromCache(provider) {
	oauthCredentialsCache.delete(provider);
}
//#endregion
export { createOAuthAsyncHandler, deleteOAuthCredentialsFromCache, getOAuthCredentialsFromCache, setOAuthCredentialsToCache };

//# sourceMappingURL=oauth-async.js.map