import { isRecord } from "../utils/json.js";
import { authorizeWorkspace, requireLocalUiSessionForBrowserRoute, } from "./authGuards.js";
import { writeJson } from "./publicResponse.js";
import { readJsonBody, readOptionalString } from "./requestParsing.js";
import { bindRunIntentBridgeReceiptToRun, consumeRunIntentBridgeReceiptForCreate, formatRunIntentReceiptRejectionBody, releaseRunIntentBridgeReceiptForCreate, validateRunIntentBridgeReceiptForCreate, } from "../authority/runIntentReceipts.js";
import { formatCreateRunResult, readSessionCreateInput, } from "./runPayloads.js";
const MAX_WORK_ITEM_ID_LENGTH = 200;
const MAX_ROOT_PATH_LENGTH = 4096;
/**
 * Dev-only local run-intent mint + run-create route.
 *
 * POST /local-ui/run-intent-receipts/mint
 *
 * Local-first: when the bridge runs in dev/test mode with development-fixture
 * trust, it self-mints a run-intent receipt and immediately creates the
 * receipt-bound run, so a run starts without the hosted backend. In production
 * / configured-key modes there is no signer and this route reports not-found.
 *
 * The minted receipt never crosses the browser boundary — it is consumed
 * server-side. Only the bounded run projection (same shape as the hosted
 * receipt-bound create) is returned.
 */
export async function handleLocalRunIntentMintRoute(context) {
    const { app, auth, request, response, runIntentReceiptState, url, localRunIntentSigner, } = context;
    if (request.method !== "POST" ||
        url.pathname !== "/local-ui/run-intent-receipts/mint") {
        return false;
    }
    if (!requireLocalUiSessionForBrowserRoute(response, auth, {
        request,
        routeId: "local-ui.run-intent-receipts.mint",
    })) {
        return true;
    }
    // Fail-closed: no signer means local minting is not permitted here.
    if (!localRunIntentSigner) {
        writeJson(response, 404, {
            error: "not_found",
            message: "Local run-intent minting is not available.",
        });
        return true;
    }
    if (auth.kind !== "local-ui-session") {
        writeJson(response, 403, {
            error: "forbidden",
            message: "Local UI session required.",
        });
        return true;
    }
    const body = await readJsonBody(request);
    if (!isRecord(body) ||
        typeof body.workItemId !== "string" ||
        typeof body.rootPath !== "string") {
        writeJson(response, 400, {
            error: "invalid_request",
            message: "Expected JSON body with workItemId and rootPath strings.",
        });
        return true;
    }
    const workItemId = body.workItemId.trim();
    if (workItemId.length === 0 || workItemId.length > MAX_WORK_ITEM_ID_LENGTH) {
        writeJson(response, 400, {
            error: "invalid_request",
            message: "workItemId must be a non-empty bounded string.",
        });
        return true;
    }
    // rootPath is forwarded to run creation, which spawns a runtime against it.
    // Bound it the same way workItemId is bounded so an unbounded or empty path
    // cannot reach the run service. PATH_MAX (4096) is the upper bound.
    const rootPath = body.rootPath.trim();
    if (rootPath.length === 0 || rootPath.length > MAX_ROOT_PATH_LENGTH) {
        writeJson(response, 400, {
            error: "invalid_request",
            message: "rootPath must be a non-empty bounded string.",
        });
        return true;
    }
    const workspaceId = auth.session.workspaceId;
    if (!authorizeWorkspace(response, auth, workspaceId))
        return true;
    // Mint a self-trusted receipt and validate it exactly like a hosted receipt.
    const receipt = localRunIntentSigner.mintReceipt({ workspaceId, workItemId });
    const validation = validateRunIntentBridgeReceiptForCreate(receipt, workspaceId, runIntentReceiptState);
    if (validation) {
        writeJson(response, validation.statusCode, formatRunIntentReceiptRejectionBody(validation.reasonCode));
        return true;
    }
    const title = readOptionalString(body.title);
    const session = readSessionCreateInput(body.session, body.title);
    consumeRunIntentBridgeReceiptForCreate(receipt, runIntentReceiptState);
    let result;
    try {
        result = await app.runService.createRun({
            workspaceId,
            rootPath,
            ...(title ? { title } : {}),
            ...(session ? { session } : {}),
        });
    }
    catch (error) {
        releaseRunIntentBridgeReceiptForCreate(receipt, runIntentReceiptState);
        throw error;
    }
    bindRunIntentBridgeReceiptToRun(receipt, result.run.id, runIntentReceiptState);
    writeJson(response, 201, formatCreateRunResult(result));
    return true;
}
