import { createServer } from "node:http";
import { SUCCESS_HTML, ERROR_HTML, FRAGMENT_EXTRACTOR_HTML } from "./templates/index.js";
/** Timeout for waiting for the OAuth callback (5 minutes). */
const OAUTH_TIMEOUT_MS = 5 * 60 * 1000;
/**
 * Start a temporary HTTP server on a random port to receive the OAuth callback.
 * The server listens only on 127.0.0.1 and closes automatically after the
 * callback is received or after a 5-minute timeout.
 */
export async function startOAuthServer() {
    let settled = false;
    let result = null;
    let error = null;
    let onSettle = null;
    function settle() {
        settled = true;
        onSettle?.();
    }
    const server = createServer((req, res) => {
        const reqUrl = new URL(req.url ?? "/", `http://127.0.0.1`);
        // Handle GET /auth/callback - serve HTML that extracts fragment tokens
        if (req.method === "GET" && reqUrl.pathname === "/auth/callback") {
            const errorParam = reqUrl.searchParams.get("error");
            if (errorParam) {
                res.writeHead(400, { "Content-Type": "text/html" });
                error = new Error(errorParam);
                // Wait for response to be fully sent before settling
                res.on("finish", settle);
                res.end(ERROR_HTML);
                return;
            }
            // Check for code flow (code in query string)
            const code = reqUrl.searchParams.get("code");
            if (code) {
                res.writeHead(200, { "Content-Type": "text/html" });
                result = { code };
                // Wait for response to be fully sent before settling
                res.on("finish", settle);
                res.end(SUCCESS_HTML);
                return;
            }
            // No code - serve HTML to extract tokens from fragment (implicit flow)
            res.writeHead(200, { "Content-Type": "text/html" });
            res.end(FRAGMENT_EXTRACTOR_HTML);
            return;
        }
        // Handle POST /auth/tokens - receive tokens from JavaScript
        if (req.method === "POST" && reqUrl.pathname === "/auth/tokens") {
            let body = "";
            req.on("data", (chunk) => {
                body += chunk.toString();
            });
            req.on("end", () => {
                try {
                    const data = JSON.parse(body);
                    if (data.access_token && data.refresh_token) {
                        res.writeHead(200, { "Content-Type": "application/json" });
                        result = { access_token: data.access_token, refresh_token: data.refresh_token };
                        // Wait for response to be fully sent before settling
                        res.on("finish", settle);
                        res.end(JSON.stringify({ success: true }));
                    }
                    else {
                        res.writeHead(400, { "Content-Type": "application/json" });
                        res.end(JSON.stringify({ error: "Missing tokens" }));
                    }
                }
                catch {
                    res.writeHead(400, { "Content-Type": "application/json" });
                    res.end(JSON.stringify({ error: "Invalid JSON" }));
                }
            });
            return;
        }
        res.writeHead(404, { "Content-Type": "text/plain" });
        res.end("Not Found");
    });
    // Wait for the server to be listening
    await new Promise((resolve, reject) => {
        server.on("error", reject);
        server.listen(0, "127.0.0.1", () => {
            resolve();
        });
    });
    const address = server.address();
    const port = address.port;
    const callbackUrl = `http://127.0.0.1:${port}/auth/callback`;
    // Set up timeout
    const timeout = setTimeout(() => {
        error = new Error("OAuth callback timed out after 5 minutes");
        settle();
        server.close();
    }, OAUTH_TIMEOUT_MS);
    function close() {
        clearTimeout(timeout);
        server.close();
    }
    async function waitForCallback() {
        if (!settled) {
            await new Promise((resolve) => {
                onSettle = resolve;
            });
        }
        clearTimeout(timeout);
        server.close();
        if (error) {
            throw error;
        }
        return result;
    }
    return {
        port,
        callbackUrl,
        waitForCallback,
        close,
    };
}
//# sourceMappingURL=oauth-server.js.map