import { once } from 'node:events';
import { createServer } from 'node:http';
const SUCCESS_PAGE = `<!doctype html>
<html>
  <head>
    <meta charset="utf-8" />
    <title>ShortcutXL Login Complete</title>
  </head>
  <body>
    <h1>Login complete</h1>
    <p>You can return to ShortcutXL.</p>
  </body>
</html>`;
function isLoopbackHost(hostname) {
    return hostname === '127.0.0.1' || hostname === 'localhost';
}
export async function startOAuthCallbackServer(redirectUrl, signal) {
    const targetUrl = new URL(redirectUrl);
    if (!isLoopbackHost(targetUrl.hostname)) {
        throw new Error(`OAuth callback host must be loopback, got ${targetUrl.hostname}`);
    }
    const listener = createServer();
    let settled = false;
    let resolveCallback;
    let rejectCallback;
    let resolvedRedirectUrl = targetUrl.toString();
    const callbackPromise = new Promise((resolve, reject) => {
        resolveCallback = resolve;
        rejectCallback = reject;
    });
    const close = async () => {
        if (!listener.listening) {
            return;
        }
        listener.close();
        await once(listener, 'close');
    };
    listener.on('request', async (req, res) => {
        const requestUrl = new URL(req.url ?? '/', resolvedRedirectUrl);
        if (requestUrl.pathname !== targetUrl.pathname) {
            res.writeHead(404, { 'content-type': 'text/plain; charset=utf-8' });
            res.end('Not found');
            return;
        }
        res.writeHead(200, { 'content-type': 'text/html; charset=utf-8' });
        res.end(SUCCESS_PAGE);
        if (!settled) {
            settled = true;
            resolveCallback?.(requestUrl.toString());
            resolveCallback = undefined;
            rejectCallback = undefined;
        }
        await close().catch(() => { });
    });
    listener.on('error', (error) => {
        if (!settled) {
            settled = true;
            rejectCallback?.(error instanceof Error ? error : new Error(String(error)));
            resolveCallback = undefined;
            rejectCallback = undefined;
        }
    });
    signal?.addEventListener('abort', () => {
        if (!settled) {
            settled = true;
            rejectCallback?.(new Error('Login cancelled'));
            resolveCallback = undefined;
            rejectCallback = undefined;
        }
        void close().catch(() => { });
    }, { once: true });
    listener.listen(targetUrl.port ? Number(targetUrl.port) : 0, targetUrl.hostname);
    await once(listener, 'listening');
    const address = listener.address();
    if (!address || typeof address === 'string') {
        throw new Error('OAuth callback server did not expose a loopback address');
    }
    const { port } = address;
    const actualUrl = new URL(targetUrl.toString());
    actualUrl.port = String(port);
    resolvedRedirectUrl = actualUrl.toString();
    return {
        redirectUrl: resolvedRedirectUrl,
        waitForCallback: () => callbackPromise,
        close
    };
}
//# sourceMappingURL=oauth-callback-server.js.map