import fs from "node:fs";
import http from "node:http";
import path from "node:path";
import open from "open";
import { google } from "googleapis";
import { GoogleTokensSchema } from "../config/types.js";
import { loadConfig, saveConfig } from "../config/index.js";
import { resolveGoogleOAuthCredentials } from "../google/oauth-credentials.js";
import { getE2EGuestTokensFile } from "./artifacts.js";
import { createOAuthSetupSession, deleteOAuthSetupSession, loadOAuthSetupSession, parseCallbackUrl, } from "./oauth-setup-store.js";
export const E2E_GUEST_SCOPES = [
    "https://www.googleapis.com/auth/calendar.readonly",
    "https://www.googleapis.com/auth/userinfo.email",
];
export function loadE2EGuestTokens() {
    const file = getE2EGuestTokensFile();
    if (!fs.existsSync(file))
        return null;
    try {
        return GoogleTokensSchema.parse(JSON.parse(fs.readFileSync(file, "utf-8")));
    }
    catch {
        return null;
    }
}
export function saveE2EGuestTokens(tokens) {
    const file = getE2EGuestTokensFile();
    fs.mkdirSync(path.dirname(file), { recursive: true });
    fs.writeFileSync(file, `${JSON.stringify(tokens, null, 2)}\n`, "utf-8");
}
export async function startGoogleGuestSetup(config, email, options) {
    if (options.remote) {
        return startRemoteGoogleGuestSetup(config, email, options);
    }
    return startLocalGoogleGuestSetup(config, email);
}
function startRemoteGoogleGuestSetup(config, email, options) {
    const { clientId, clientSecret } = resolveGoogleOAuthCredentials(config);
    const session = createOAuthSetupSession({
        expectedEmail: email,
        scopes: E2E_GUEST_SCOPES,
        redirectUri: "http://127.0.0.1:49321/callback",
        requestSource: options.requestSource ?? "cli",
        channel: options.channel,
        sender: options.sender,
    });
    const oauth2Client = new google.auth.OAuth2(clientId, clientSecret, session.redirectUri);
    const authUrl = oauth2Client.generateAuthUrl({
        access_type: "offline",
        scope: E2E_GUEST_SCOPES,
        prompt: "consent",
        state: session.state,
    });
    return {
        setupId: session.setupId,
        authUrl,
        message: [
            "E2E Google guest setup started (remote mode).",
            "",
            `Expected guest: ${email}`,
            `Setup ID: ${session.setupId}`,
            "",
            "Open this URL on any machine:",
            authUrl,
            "",
            "After authorization, copy the full callback URL and run:",
            `/e2e setup google-guest-code ${session.setupId} '<callbackUrl>'`,
        ].join("\n"),
    };
}
async function startLocalGoogleGuestSetup(config, email) {
    const { clientId, clientSecret } = resolveGoogleOAuthCredentials(config);
    return new Promise((resolve, reject) => {
        const server = http.createServer();
        server.listen(0, "127.0.0.1", () => {
            const addr = server.address();
            if (!addr || typeof addr === "string") {
                reject(new Error("Failed to start local OAuth server"));
                return;
            }
            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: E2E_GUEST_SCOPES,
                prompt: "consent",
            });
            void open(authUrl).catch(() => { });
            let settled = false;
            const timeout = setTimeout(() => {
                if (settled)
                    return;
                settled = true;
                server.close();
                reject(new Error("OAuth setup timed out after 10 minutes"));
            }, 10 * 60 * 1000);
            const finish = (fn) => {
                if (settled)
                    return;
                settled = true;
                clearTimeout(timeout);
                server.close();
                fn();
            };
            server.on("request", (req, res) => {
                void (async () => {
                    try {
                        const url = new URL(req.url ?? "/", redirectUri);
                        const code = url.searchParams.get("code");
                        const error = url.searchParams.get("error");
                        if (error)
                            throw new Error(`Google OAuth error: ${error}`);
                        if (!code) {
                            res.writeHead(400);
                            res.end("Missing code");
                            return;
                        }
                        const { tokens } = await oauth2Client.getToken(code);
                        if (!tokens.refresh_token)
                            throw new Error("No refresh token received");
                        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 ?? E2E_GUEST_SCOPES.join(" "),
                        };
                        await verifyGuestEmail(config, googleTokens, email);
                        saveE2EGuestTokens(googleTokens);
                        const cfg = loadConfig();
                        cfg.e2e ??= {};
                        cfg.e2e.google ??= {};
                        cfg.e2e.google.meetGuestEmail = email;
                        saveConfig(cfg);
                        res.writeHead(200, { "Content-Type": "text/html" });
                        res.end("<h1>E2E guest authorization complete</h1>");
                        finish(() => resolve({
                            authUrl,
                            message: `E2E Google guest setup completed for ${email}.`,
                        }));
                    }
                    catch (err) {
                        res.writeHead(500);
                        res.end("Authorization failed");
                        finish(() => reject(err instanceof Error ? err : new Error(String(err))));
                    }
                })();
            });
        });
    });
}
export async function completeGoogleGuestSetupFromCallback(config, setupId, callbackUrl) {
    const session = loadOAuthSetupSession(setupId);
    if (!session)
        throw new Error("OAuth setup session not found or expired");
    const { code, state } = parseCallbackUrl(callbackUrl);
    if (!state || state !== session.state)
        throw new Error("OAuth state mismatch");
    const { clientId, clientSecret } = resolveGoogleOAuthCredentials(config);
    const oauth2Client = new google.auth.OAuth2(clientId, clientSecret, session.redirectUri);
    const { tokens } = await oauth2Client.getToken(code);
    if (!tokens.refresh_token)
        throw new Error("No refresh token received");
    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 ?? session.scopes.join(" "),
    };
    await verifyGuestEmail(config, googleTokens, session.expectedEmail);
    saveE2EGuestTokens(googleTokens);
    deleteOAuthSetupSession(setupId);
    const cfg = loadConfig();
    cfg.e2e ??= {};
    cfg.e2e.google ??= {};
    cfg.e2e.google.meetGuestEmail = session.expectedEmail;
    saveConfig(cfg);
    return {
        message: `E2E Google guest setup completed for ${session.expectedEmail}.`,
        setupId,
    };
}
async function verifyGuestEmail(config, tokens, expectedEmail) {
    const { clientId, clientSecret } = resolveGoogleOAuthCredentials(config);
    const oauth2Client = new google.auth.OAuth2(clientId, clientSecret);
    oauth2Client.setCredentials({
        access_token: tokens.access_token,
        refresh_token: tokens.refresh_token,
        token_type: tokens.token_type,
        expiry_date: tokens.expiry_date,
    });
    const oauth2 = google.oauth2({ version: "v2", auth: oauth2Client });
    const profile = await oauth2.userinfo.get();
    const email = profile.data.email?.toLowerCase();
    if (!email || email !== expectedEmail.toLowerCase()) {
        throw new Error(`Authorized account ${email ?? "unknown"} does not match expected ${expectedEmail}`);
    }
}
export function createGuestCalendarClient(config) {
    const tokens = loadE2EGuestTokens();
    if (!tokens)
        return null;
    try {
        const { clientId, clientSecret } = resolveGoogleOAuthCredentials(config);
        const oauth2Client = new google.auth.OAuth2(clientId, clientSecret);
        oauth2Client.setCredentials({
            access_token: tokens.access_token,
            refresh_token: tokens.refresh_token,
            token_type: tokens.token_type,
            expiry_date: tokens.expiry_date,
        });
        return google.calendar({ version: "v3", auth: oauth2Client });
    }
    catch {
        return null;
    }
}
//# sourceMappingURL=setup-google-guest.js.map