import http from "node:http";
import { applyCorsHeaders, authenticateRequest, writeAuthFailure, } from "./authGuards.js";
import { writeJson } from "./publicResponse.js";
import { RequestBodyTooLargeError } from "./requestParsing.js";
import { createRunIntentReceiptState } from "../authority/runIntentReceipts.js";
import { createLocalRunIntentReceiptSigner } from "../authority/LocalRunIntentReceiptSigner.js";
import { matchAuthedRoute, matchPreAuthRoute, requiredScopeFor, routeIdFor, } from "./routeTable.js";
export { writeJson } from "./publicResponse.js";
export function createHttpServer(app, config) {
    const runIntentReceiptState = createRunIntentReceiptState();
    // Local-first: in dev/test with development-fixture trust, the bridge can
    // self-mint run-intent receipts so a run starts without the hosted backend.
    // The signer is null in production / configured-key modes (fail-closed).
    const localRunIntentSigner = createLocalRunIntentReceiptSigner(config);
    const effectiveConfig = localRunIntentSigner
        ? {
            ...config,
            runIntentReceiptTrust: {
                ...config.runIntentReceiptTrust,
                trustedPublicKeys: [
                    ...config.runIntentReceiptTrust.trustedPublicKeys,
                    localRunIntentSigner.getTrustedPublicKey(),
                ],
            },
        }
        : config;
    const handler = async (request, response) => {
        try {
            const url = new URL(request.url ?? "/", `http://${request.headers.host ?? "localhost"}`);
            applyCorsHeaders(request, response, app);
            if (request.method === "OPTIONS") {
                response.statusCode = 204;
                response.end();
                return;
            }
            const method = request.method ?? "GET";
            const baseContext = {
                app,
                config: effectiveConfig,
                request,
                response,
                url,
                runIntentReceiptState,
                localRunIntentSigner,
            };
            // Pre-auth routes handle their own credentials (public health check and
            // the local-UI handoff endpoints) and run before central authentication.
            const preAuthRoute = matchPreAuthRoute(method, url.pathname);
            if (preAuthRoute && (await preAuthRoute.handler(baseContext)))
                return;
            // Central authentication: resolve the required scope for this route from
            // the declarative table (fail-closed — an unmatched route resolves to the
            // documented fallback scope, never an undefined policy), then enforce it.
            const auth = authenticateRequest(request, app, requiredScopeFor(method, url.pathname) ?? undefined);
            if (!writeAuthFailure(response, auth, {
                request,
                routeId: routeIdFor(method, url.pathname),
            })) {
                return;
            }
            const routeContext = { ...baseContext, auth };
            // Dispatch to the single matching authed handler. A matched handler that
            // declines (returns false) — e.g. a path served only for other methods —
            // falls through to the 404 below, exactly as the prior sequential router.
            const authedRoute = matchAuthedRoute(method, url.pathname);
            if (authedRoute && (await authedRoute.handler(routeContext)))
                return;
            writeJson(response, 404, {
                error: "not_found",
                message: `${request.method} ${url.pathname}`,
            });
        }
        catch (error) {
            if (error instanceof RequestBodyTooLargeError) {
                writeJson(response, 413, {
                    error: "request_too_large",
                    message: error.message,
                });
                return;
            }
            if (error instanceof SyntaxError) {
                writeJson(response, 400, {
                    error: "invalid_json",
                    message: "Request body must be valid JSON.",
                });
                return;
            }
            writeJson(response, 500, {
                error: "internal_error",
                message: "Internal bridge error.",
            });
        }
    };
    return http.createServer((request, response) => {
        void handler(request, response);
    });
}
