import http from "node:http";
import { URL } from "node:url";
import open from "open";
import { google } from "googleapis";
import { saveGoogleTokens, getTokensFile } from "../config/index.js";
import { resolveGoogleOAuthCredentials } from "../google/oauth-credentials.js";
import fs from "node:fs";
const SCOPES = [
    "https://www.googleapis.com/auth/gmail.modify",
    "https://www.googleapis.com/auth/gmail.send",
    "https://www.googleapis.com/auth/calendar",
    "https://www.googleapis.com/auth/calendar.events",
    "https://www.googleapis.com/auth/drive",
    "https://www.googleapis.com/auth/meetings.space.created",
    "https://www.googleapis.com/auth/meetings.space.settings",
];
export async function runGoogleOAuth(config, options) {
    const { clientId, clientSecret } = resolveGoogleOAuthCredentials(config);
    return new Promise((resolve, reject) => {
        // Create a temporary HTTP server to receive the OAuth callback
        const server = http.createServer();
        // Listen on all interfaces to avoid IPv4/IPv6 binding issues on some OSes
        server.listen(0, "0.0.0.0", () => {
            const addr = server.address();
            if (!addr || typeof addr === "string") {
                reject(new Error("Failed to start local server"));
                return;
            }
            // Google requires the redirect URI to be exactly 127.0.0.1 (or localhost)
            const redirectUri = `http://127.0.0.1:${addr.port}/callback`;
            const oauth2Client = new google.auth.OAuth2(clientId, clientSecret, redirectUri);
            const authUrl = oauth2Client.generateAuthUrl({
                access_type: "offline",
                scope: SCOPES,
                prompt: "consent",
            });
            console.log("\nOpening browser for Google OAuth consent...");
            console.log(`If the browser doesn't open, visit:\n${authUrl}\n`);
            // Emit a structured JSON line so the GUI setup-runner can detect the URL
            // and open it via Electron's shell.openExternal (reliable across sandboxed
            // child processes where the `open` npm package may silently fail).
            console.log(JSON.stringify({ __openUrl: authUrl }));
            const openUrl = options?.openUrl ?? (async (url) => {
                await open(url);
            });
            openUrl(authUrl).catch(() => {
                // Best-effort: the URL was already emitted above for the GUI to handle
            });
            server.on("request", (req, res) => {
                void (async () => {
                    try {
                        const url = new URL(req.url ?? "/", `http://127.0.0.1:${addr.port}`);
                        if (url.pathname !== "/callback") {
                            res.writeHead(404);
                            res.end("Not found");
                            return;
                        }
                        const code = url.searchParams.get("code");
                        const error = url.searchParams.get("error");
                        if (error) {
                            res.writeHead(400);
                            res.end(`Authorization error: ${error}`);
                            server.close();
                            reject(new Error(`Google OAuth error: ${error}`));
                            return;
                        }
                        if (!code) {
                            res.writeHead(400);
                            res.end("No authorization code received");
                            server.close();
                            reject(new Error("No authorization code received"));
                            return;
                        }
                        // Exchange the code for tokens
                        const { tokens } = await oauth2Client.getToken(code);
                        if (!tokens.refresh_token) {
                            res.writeHead(400);
                            res.end("No refresh token received. Please revoke access and try again.");
                            server.close();
                            reject(new Error("No refresh token received"));
                            return;
                        }
                        const googleTokens = {
                            access_token: tokens.access_token ?? "",
                            refresh_token: tokens.refresh_token,
                            token_type: tokens.token_type ?? "Bearer",
                            expiry_date: tokens.expiry_date ?? 0,
                            scope: tokens.scope ?? SCOPES.join(" "),
                        };
                        saveGoogleTokens(googleTokens);
                        // Report tokens back to the onboarding service so it can store them
                        // server-side and advance the profile phase to google_ready.
                        // Network failures are non-fatal: tokens are already on local disk.
                        if (options?.onboardingClient) {
                            try {
                                const tokensFile = getTokensFile();
                                const tokensJson = fs.readFileSync(tokensFile, "utf-8");
                                const reported = await options.onboardingClient.reportGoogleTokens(tokensJson);
                                if (reported) {
                                    console.log("[google-auth] OAuth tokens reported to onboarding service.");
                                }
                                else {
                                    console.warn("[google-auth] Failed to report OAuth tokens to onboarding service (non-fatal).");
                                }
                            }
                            catch (reflowErr) {
                                console.warn("[google-auth] Token reflow error (non-fatal):", reflowErr);
                            }
                        }
                        res.writeHead(200, { "Content-Type": "text/html" });
                        res.end(`
            <html>
              <body style="font-family: system-ui; text-align: center; padding: 50px;">
                <h1>VisionClaw Authorization Complete</h1>
                <p>You can close this window and return to the terminal.</p>
              </body>
            </html>
          `);
                        server.close();
                        resolve(googleTokens);
                    }
                    catch (err) {
                        res.writeHead(500);
                        res.end("Internal error");
                        server.close();
                        reject(err instanceof Error ? err : new Error(String(err)));
                    }
                })();
            });
            // Timeout after 30 minutes
            setTimeout(() => {
                server.close();
                reject(new Error("OAuth flow timed out (30 minutes)"));
            }, 30 * 60 * 1000);
        });
    });
}
//# sourceMappingURL=google-auth.js.map