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, consumeRunIntentBridgeReceiptForPrompt, formatRunIntentReceiptRejectionBody, readRunIntentBridgeReceipt, releaseRunIntentBridgeReceiptForCreate, releaseRunIntentBridgeReceiptForPrompt, validateRunIntentBridgeReceiptForCreate, validateRunIntentBridgeReceiptForPrompt, } from "../authority/runIntentReceipts.js";
import { formatCreateRunResult, formatPromptResult, readRunSourceBinding, readSessionCreateInput, } from "./runPayloads.js";
import { firstCapture, matchPath } from "./routeMatching.js";
const INTENT_BOUND_PROMPT_ALLOWED_KEYS = new Set([
    "text",
    "runIntentBridgeReceipt",
]);
export async function handleRunIntentReceiptRoutes(context) {
    const { app, auth, config, request, response, runIntentReceiptState, url } = context;
    const intentBoundWorkspaceRunsMatch = matchPath(url.pathname, /^\/workspaces\/([^/]+)\/run-intent-receipts\/runs$/);
    if (request.method === "POST" && intentBoundWorkspaceRunsMatch) {
        if (!requireLocalUiSessionForBrowserRoute(response, auth, {
            request,
            routeId: "workspace.run-intent-receipts.runs",
        })) {
            return true;
        }
        const body = await readJsonBody(request);
        if (!isRecord(body) || typeof body.rootPath !== "string") {
            writeJson(response, 400, {
                error: "invalid_request",
                message: "Expected JSON body with rootPath string.",
            });
            return true;
        }
        const workspaceId = firstCapture(intentBoundWorkspaceRunsMatch);
        if (!authorizeWorkspace(response, auth, workspaceId))
            return true;
        const receipt = readRunIntentBridgeReceipt(body.runIntentBridgeReceipt, config.runIntentReceiptTrust);
        if (receipt.kind === "error") {
            writeRunIntentReceiptRejection(response, receipt.statusCode, receipt.reasonCode);
            return true;
        }
        const receiptValidation = validateRunIntentBridgeReceiptForCreate(receipt.receipt, workspaceId, runIntentReceiptState);
        if (receiptValidation) {
            writeRunIntentReceiptRejection(response, receiptValidation.statusCode, receiptValidation.reasonCode);
            return true;
        }
        const createRunInput = {
            workspaceId,
            rootPath: body.rootPath,
        };
        const title = readOptionalString(body.title);
        const session = readSessionCreateInput(body.session, body.title);
        const sourceBinding = readRunSourceBinding(body.sourceBinding);
        if (body.sourceBinding !== undefined && !sourceBinding) {
            writeRunIntentReceiptRejection(response, 422, "intent_receipt_unsupported");
            return true;
        }
        consumeRunIntentBridgeReceiptForCreate(receipt.receipt, runIntentReceiptState);
        let result;
        try {
            result = await app.runService.createRun({
                ...createRunInput,
                ...(title ? { title } : {}),
                ...(session ? { session } : {}),
                ...(sourceBinding ? { sourceBinding } : {}),
            });
        }
        catch (error) {
            releaseRunIntentBridgeReceiptForCreate(receipt.receipt, runIntentReceiptState);
            throw error;
        }
        bindRunIntentBridgeReceiptToRun(receipt.receipt, result.run.id, runIntentReceiptState);
        writeJson(response, 201, formatCreateRunResult(result));
        return true;
    }
    const intentBoundRunPromptMatch = matchPath(url.pathname, /^\/runs\/([^/]+)\/run-intent-receipts\/prompt$/);
    if (request.method === "POST" && intentBoundRunPromptMatch) {
        if (!requireLocalUiSessionForBrowserRoute(response, auth, {
            request,
            routeId: "runs.run-intent-receipts.prompt",
        })) {
            return true;
        }
        const body = await readJsonBody(request);
        if (!isRecord(body) || typeof body.text !== "string") {
            writeJson(response, 400, {
                error: "invalid_request",
                message: "Expected JSON body with text string.",
            });
            return true;
        }
        if (Object.keys(body).some((key) => !INTENT_BOUND_PROMPT_ALLOWED_KEYS.has(key))) {
            writeRunIntentReceiptRejection(response, 422, "intent_receipt_unsupported");
            return true;
        }
        const runId = firstCapture(intentBoundRunPromptMatch);
        const run = app.localStore.findRun(runId);
        if (!run) {
            writeJson(response, 404, {
                error: "not_found",
                message: `Run ${runId} was not found.`,
            });
            return true;
        }
        if (!authorizeWorkspace(response, auth, run.workspaceId))
            return true;
        const receipt = readRunIntentBridgeReceipt(body.runIntentBridgeReceipt, config.runIntentReceiptTrust);
        if (receipt.kind === "error") {
            writeRunIntentReceiptRejection(response, receipt.statusCode, receipt.reasonCode);
            return true;
        }
        const receiptValidation = validateRunIntentBridgeReceiptForPrompt(receipt.receipt, { runId, workspaceId: run.workspaceId }, runIntentReceiptState);
        if (receiptValidation) {
            writeRunIntentReceiptRejection(response, receiptValidation.statusCode, receiptValidation.reasonCode);
            return true;
        }
        consumeRunIntentBridgeReceiptForPrompt(receipt.receipt, runIntentReceiptState);
        let result;
        try {
            result = await app.runService.sendPrompt({
                runId,
                text: body.text,
            });
        }
        catch (error) {
            releaseRunIntentBridgeReceiptForPrompt(receipt.receipt, runIntentReceiptState);
            throw error;
        }
        writeJson(response, 202, formatPromptResult(result, {
            textLength: body.text.length,
            hasModel: false,
        }));
        return true;
    }
    return false;
}
function writeRunIntentReceiptRejection(response, statusCode, reasonCode) {
    writeJson(response, statusCode, formatRunIntentReceiptRejectionBody(reasonCode));
}
