import { PermissionReplyValidationError, PermissionRequestConflictError, PermissionRuntimeReplyError, } from "../permissions/PermissionBridgeService.js";
import { isRecord } from "../utils/json.js";
import { authorizeWorkspace, writeForbiddenWorkspace } from "./authGuards.js";
import { writeJson } from "./publicResponse.js";
import { readJsonBody, readLimit, readOptionalString, readString, readStringArray, } from "./requestParsing.js";
import { firstCapture, matchPath, secondCapture } from "./routeMatching.js";
import { formatPermissionActivityRecord, formatPermissionDecisionRecord, formatPermissionEvaluationPayload, formatPermissionRequestRecord, readPermissionCapabilities, readPermissionDecisionStatusParam, readPermissionOption, readPermissionRequestStatusParam, readRisk, } from "./permissionPayloads.js";
import { PermissionDecisionConflictError, PermissionDecisionNotFoundError, } from "../permissions/PermissionDecisionRegistry.js";
export async function handleWorkspacePermissionRoutes(context) {
    const { app, auth, request, response, url } = context;
    const workspacePermissionActivityMatch = matchPath(url.pathname, /^\/workspaces\/([^/]+)\/permissions\/activity$/);
    if (request.method === "GET" && workspacePermissionActivityMatch) {
        const workspaceId = firstCapture(workspacePermissionActivityMatch);
        if (!authorizeWorkspace(response, auth, workspaceId))
            return true;
        const runId = url.searchParams.get("runId") ?? undefined;
        const limit = readLimit(url.searchParams.get("limit"));
        const cursor = url.searchParams.get("cursor") ?? undefined;
        const activityInput = {
            workspaceId,
            ...(runId ? { runId } : {}),
            ...(limit ? { limit } : {}),
            ...(cursor ? { cursor } : {}),
        };
        const page = app.localStore.listPermissionActivity(activityInput);
        writeJson(response, 200, {
            events: page.events.map(formatPermissionActivityRecord),
            ...(page.nextCursor ? { nextCursor: page.nextCursor } : {}),
        });
        return true;
    }
    const workspacePermissionDecisionListMatch = matchPath(url.pathname, /^\/workspaces\/([^/]+)\/permissions\/decisions$/);
    if (request.method === "GET" && workspacePermissionDecisionListMatch) {
        const workspaceId = firstCapture(workspacePermissionDecisionListMatch);
        if (!authorizeWorkspace(response, auth, workspaceId))
            return true;
        const status = readPermissionDecisionStatusParam(url.searchParams.get("status"));
        const runId = url.searchParams.get("runId") ?? undefined;
        const limit = readLimit(url.searchParams.get("limit"));
        const cursor = url.searchParams.get("cursor") ?? undefined;
        const listInput = {
            workspaceId,
            scope: "session",
            effect: "allow",
            option: "allow_for_session",
            ...(status ? { status } : {}),
            ...(runId ? { runId } : {}),
            ...(limit ? { limit } : {}),
            ...(cursor ? { cursor } : {}),
        };
        const page = app.permissionDecisionRegistry.list(listInput);
        writeJson(response, 200, {
            decisions: page.decisions.map(formatPermissionDecisionRecord),
            ...(page.nextCursor ? { nextCursor: page.nextCursor } : {}),
        });
        return true;
    }
    const workspacePermissionDecisionRevokeMatch = matchPath(url.pathname, /^\/workspaces\/([^/]+)\/permissions\/decisions\/([^/]+)\/revoke$/);
    if (request.method === "POST" && workspacePermissionDecisionRevokeMatch) {
        const workspaceId = firstCapture(workspacePermissionDecisionRevokeMatch);
        const decisionId = secondCapture(workspacePermissionDecisionRevokeMatch);
        if (!authorizeWorkspace(response, auth, workspaceId))
            return true;
        const body = await readJsonBody(request);
        const reason = isRecord(body) ? readOptionalString(body.reason) : undefined;
        try {
            const decision = app.permissionDecisionRegistry.revoke({
                workspaceId,
                decisionId,
                source: auth.kind === "local-ui-session" ? "local_ui" : "bridge_api",
                ...(reason ? { reason } : {}),
            });
            writeJson(response, 200, {
                decision: formatPermissionDecisionRecord(decision),
            });
        }
        catch (error) {
            if (error instanceof PermissionDecisionNotFoundError) {
                writeJson(response, 404, {
                    error: "permission_decision_not_found",
                    message: "Permission decision was not found.",
                });
                return true;
            }
            if (error instanceof PermissionDecisionConflictError) {
                writeJson(response, 409, {
                    error: "permission_decision_already_revoked",
                    message: "Permission decision is already revoked.",
                });
                return true;
            }
            throw error;
        }
        return true;
    }
    return false;
}
export async function handlePermissionRoutes(context) {
    const { app, auth, request, response, url } = context;
    const permissionRequestsMatch = matchPath(url.pathname, /^\/permissions\/requests$/);
    if (request.method === "GET" && permissionRequestsMatch) {
        const options = {};
        const status = readPermissionRequestStatusParam(url.searchParams.get("status"));
        const runId = readOptionalString(url.searchParams.get("runId"));
        let workspaceId = readOptionalString(url.searchParams.get("workspaceId"));
        if (auth.kind === "local-ui-session") {
            if (workspaceId && workspaceId !== auth.session.workspaceId) {
                writeForbiddenWorkspace(response);
                return true;
            }
            workspaceId = auth.session.workspaceId;
        }
        const limit = readLimit(url.searchParams.get("limit"));
        const cursor = readOptionalString(url.searchParams.get("cursor"));
        options.status = status ?? "pending";
        if (runId)
            options.runId = runId;
        if (workspaceId)
            options.workspaceId = workspaceId;
        if (limit !== undefined)
            options.limit = limit;
        if (cursor)
            options.cursor = cursor;
        const page = app.localStore.listPermissionRequests(options);
        writeJson(response, 200, {
            requests: page.requests.map(formatPermissionRequestRecord),
            nextCursor: page.nextCursor ?? null,
        });
        return true;
    }
    const permissionReplyMatch = matchPath(url.pathname, /^\/permissions\/requests\/([^/]+)\/reply$/);
    if (request.method === "POST" && permissionReplyMatch) {
        const body = await readJsonBody(request);
        if (!isRecord(body)) {
            writeJson(response, 400, {
                error: "invalid_request",
                message: "Expected JSON body.",
            });
            return true;
        }
        const option = readPermissionOption(body.option);
        if (!option) {
            writeJson(response, 400, {
                error: "invalid_request",
                message: "Expected supported permission option.",
            });
            return true;
        }
        const input = { option };
        const capabilities = readPermissionCapabilities(body.capabilities);
        const message = readOptionalString(body.message);
        if (capabilities)
            input.capabilities = capabilities;
        if (message)
            input.message = message;
        if (body.breakGlassConfirmed === true)
            input.breakGlassConfirmed = true;
        if (body.externalServiceMutationConfirmed === true) {
            input.externalServiceMutationConfirmed = true;
        }
        const requestId = firstCapture(permissionReplyMatch);
        const existingPermissionRequest = app.localStore.findPermissionRequest(requestId);
        if (existingPermissionRequest &&
            !authorizeWorkspace(response, auth, existingPermissionRequest.workspaceId)) {
            return true;
        }
        try {
            const request = await app.permissionBridge.replyToPermissionRequest(requestId, input);
            if (!request) {
                writeJson(response, 404, {
                    error: "not_found",
                    message: "Permission request was not found.",
                });
                return true;
            }
            writeJson(response, 200, {
                request: formatPermissionRequestRecord(request),
            });
            return true;
        }
        catch (error) {
            if (error instanceof PermissionReplyValidationError) {
                writeJson(response, 400, {
                    error: "invalid_request",
                    message: error.message,
                });
                return true;
            }
            if (error instanceof PermissionRequestConflictError) {
                writeJson(response, 409, {
                    error: "conflict",
                    message: error.message,
                });
                return true;
            }
            if (error instanceof PermissionRuntimeReplyError) {
                writeJson(response, 502, {
                    error: "runtime_reply_failed",
                    message: "Permission reply could not be delivered to the runtime.",
                    request: formatPermissionRequestRecord(error.request),
                });
                return true;
            }
            throw error;
        }
    }
    if (request.method === "POST" && url.pathname === "/permissions/evaluate") {
        const body = await readJsonBody(request);
        if (!isRecord(body) ||
            !isRecord(body.toolCall) ||
            !isRecord(body.context)) {
            writeJson(response, 400, {
                error: "invalid_request",
                message: "Expected JSON body with toolCall and context objects.",
            });
            return true;
        }
        const toolCall = {
            id: readString(body.toolCall.id, "tool-call"),
            name: readString(body.toolCall.name, "unknown"),
            title: readString(body.toolCall.title, "Unknown tool"),
            risk: readRisk(body.toolCall.risk),
            inputPreview: readString(body.toolCall.inputPreview, ""),
        };
        const affectedPaths = readStringArray(body.toolCall.affectedPaths);
        if (affectedPaths)
            toolCall.affectedPaths = affectedPaths;
        const command = readOptionalString(body.toolCall.command);
        if (command)
            toolCall.command = command;
        const requestedWorkspaceId = readString(body.context.workspaceId, "default-workspace");
        if (!authorizeWorkspace(response, auth, requestedWorkspaceId))
            return true;
        const permissionContext = {
            workspaceId: requestedWorkspaceId,
            sessionId: readString(body.context.sessionId, "default-session"),
        };
        const userId = readOptionalString(body.context.userId);
        if (userId)
            permissionContext.userId = userId;
        const evaluation = app.permissionPolicy.evaluate(toolCall, permissionContext);
        writeJson(response, 200, formatPermissionEvaluationPayload(evaluation));
        return true;
    }
    return false;
}
