import { appendAgentTurn, compactAgentSession, createAgentSession, deleteAgentSession, getAgentGenerationSettings, getAgentSession, getAgentWorkspacePayload, renameAgentSession, setAgentCurrentImage, setAgentGenerationSettings, setAgentLocks, setAgentWebSearch, } from "../lib/agentStore.js";
import { cancelAgentQueueItem, createAgentQueueItem, getAgentQueueItem, listAgentQueueItems, retryAgentQueueItem, } from "../lib/agentQueueStore.js";
import { ensureAgentQueueWorker, tickAgentQueueWorker } from "../lib/agentQueueWorker.js";
import { parseAgentSlashCommand, formatAgentQuestionReply, formatAgentSlashHelp } from "../lib/agentCommandParser.js";
import { requestAgentQuestionAnswer } from "../lib/agentQuestionResponder.js";
import { agentAllowedToolPayload, runAgentTurn } from "../lib/agentRuntime.js";
import { errInfo } from "../lib/errInfo.js";
import { requireRuntimeContext } from "../lib/runtimeContext.js";
export function registerAgentRoutes(app, ctxRaw) {
    const ctx = requireRuntimeContext(ctxRaw);
    ensureAgentQueueWorker(ctx);
    app.get("/api/agent/tools", (_req, res) => {
        res.json(agentAllowedToolPayload());
    });
    app.get("/api/agent/sessions", (req, res) => {
        const selectedId = typeof req.query.selectedSessionId === "string" ? req.query.selectedSessionId : null;
        res.json(getAgentWorkspacePayload(selectedId));
    });
    app.post("/api/agent/sessions", (req, res) => {
        try {
            const body = (req.body ?? {});
            const session = createAgentSession({
                title: body.title,
                currentImage: normalizeCurrentImage(body.currentImage),
                webSearchEnabled: body.webSearchEnabled !== false,
            });
            res.status(201).json(getAgentWorkspacePayload(session.id));
        }
        catch (error) {
            sendError(res, error);
        }
    });
    app.get("/api/agent/sessions/:sessionId", (req, res) => {
        const session = getAgentSession(req.params.sessionId);
        if (!session)
            return sendError(res, notFound(req.params.sessionId));
        res.json(getAgentWorkspacePayload(req.params.sessionId));
    });
    app.patch("/api/agent/sessions/:sessionId", (req, res) => {
        try {
            const body = (req.body ?? {});
            if (Object.prototype.hasOwnProperty.call(body, "title"))
                renameAgentSession(req.params.sessionId, body.title);
            if (typeof body.webSearchEnabled === "boolean")
                setAgentWebSearch(req.params.sessionId, body.webSearchEnabled);
            if (Object.prototype.hasOwnProperty.call(body, "generationSettings")) {
                setAgentGenerationSettings(req.params.sessionId, body.generationSettings);
            }
            if (Object.prototype.hasOwnProperty.call(body, "currentImageId")) {
                const ok = setAgentCurrentImage(req.params.sessionId, body.currentImageId);
                if (!ok)
                    throw imageNotFound(req.params.sessionId);
            }
            if (Array.isArray(body.styleLocks) || Array.isArray(body.subjectLocks))
                setAgentLocks(req.params.sessionId, body);
            res.json(getAgentWorkspacePayload(req.params.sessionId));
        }
        catch (error) {
            sendError(res, error);
        }
    });
    app.delete("/api/agent/sessions/:sessionId", (req, res) => {
        const ok = deleteAgentSession(req.params.sessionId);
        if (!ok)
            return sendError(res, notFound(req.params.sessionId));
        res.json(getAgentWorkspacePayload(null));
    });
    app.post("/api/agent/sessions/:sessionId/compact", (req, res) => {
        try {
            if (!getAgentSession(req.params.sessionId))
                throw notFound(req.params.sessionId);
            compactAgentSession(req.params.sessionId);
            res.json(getAgentWorkspacePayload(req.params.sessionId));
        }
        catch (error) {
            sendError(res, error);
        }
    });
    app.get("/api/agent/sessions/:sessionId/manifest", (req, res) => {
        const payload = getAgentWorkspacePayload(req.params.sessionId);
        if (!payload.selectedSessionId)
            return sendError(res, notFound(req.params.sessionId));
        res.type("application/xml").send(payload.manifest ?? "");
    });
    app.post("/api/agent/sessions/:sessionId/turns", async (req, res) => {
        try {
            const body = (req.body ?? {});
            const prompt = cleanPrompt(body.prompt);
            await runAgentTurn(ctx, req.params.sessionId, prompt, {
                provider: cleanOption(body.provider),
                quality: cleanOption(body.quality),
                size: cleanOption(body.size),
                format: cleanOption(body.format),
                moderation: cleanOption(body.moderation),
                model: cleanOption(body.model),
                reasoningEffort: cleanOption(body.reasoningEffort),
                requestId: cleanOption(body.requestId),
            });
            res.json(getAgentWorkspacePayload(req.params.sessionId));
        }
        catch (error) {
            sendError(res, error);
        }
    });
    app.get("/api/agent/queue", (_req, res) => {
        res.json({ queue: listAgentQueueItems() });
    });
    app.get("/api/agent/sessions/:sessionId/queue", (req, res) => {
        if (!getAgentSession(req.params.sessionId))
            return sendError(res, notFound(req.params.sessionId));
        res.json({ queue: listAgentQueueItems(req.params.sessionId) });
    });
    app.post("/api/agent/sessions/:sessionId/queue", async (req, res) => {
        try {
            if (!getAgentSession(req.params.sessionId))
                throw notFound(req.params.sessionId);
            const body = (req.body ?? {});
            const rawPrompt = cleanPrompt(body.prompt);
            const command = parseAgentSlashCommand(rawPrompt);
            appendAgentTurn({ sessionId: req.params.sessionId, role: "user", text: rawPrompt, status: "complete" });
            if (command?.name === "help") {
                appendAgentTurn({
                    sessionId: req.params.sessionId,
                    role: "assistant",
                    text: formatAgentSlashHelp(),
                    status: "complete",
                });
                return res.status(200).json({ queueItem: null, workspace: getAgentWorkspacePayload(req.params.sessionId) });
            }
            if (command?.name === "question") {
                const options = normalizeQueueOptions(req.params.sessionId, body);
                const question = command.prompt.trim();
                const answer = question
                    ? (await requestAgentQuestionAnswer(ctx, question, {
                        provider: cleanOption(options.provider),
                        model: cleanOption(options.model),
                        reasoningEffort: cleanOption(options.reasoningEffort),
                        requestId: cleanOption(body.requestId),
                    })).text
                    : formatAgentQuestionReply(command.prompt);
                appendAgentTurn({
                    sessionId: req.params.sessionId,
                    role: "assistant",
                    text: answer,
                    status: "complete",
                });
                return res.status(200).json({ queueItem: null, workspace: getAgentWorkspacePayload(req.params.sessionId) });
            }
            const prompt = command ? cleanPrompt(command.prompt) : rawPrompt;
            const queueItem = createAgentQueueItem({
                sessionId: req.params.sessionId,
                prompt,
                options: normalizeQueueOptions(req.params.sessionId, body),
                command,
            });
            void tickAgentQueueWorker(ctx);
            res.status(202).json({ queueItem, workspace: getAgentWorkspacePayload(req.params.sessionId) });
        }
        catch (error) {
            sendError(res, error);
        }
    });
    app.post("/api/agent/queue/:itemId/cancel", (req, res) => {
        const item = getAgentQueueItem(req.params.itemId);
        if (!item)
            return sendError(res, queueItemNotFound(req.params.itemId));
        const ok = cancelAgentQueueItem(item.id);
        if (!ok)
            return sendError(res, queueActionError("AGENT_QUEUE_CANCEL_FAILED", "Only queued Agent work can be canceled."));
        res.json(getAgentWorkspacePayload(item.sessionId));
    });
    app.post("/api/agent/queue/:itemId/retry", (req, res) => {
        const item = getAgentQueueItem(req.params.itemId);
        if (!item)
            return sendError(res, queueItemNotFound(req.params.itemId));
        const ok = retryAgentQueueItem(item.id);
        if (!ok)
            return sendError(res, queueActionError("AGENT_QUEUE_RETRY_FAILED", "Only failed or canceled Agent work can be retried."));
        void tickAgentQueueWorker(ctx);
        res.json(getAgentWorkspacePayload(item.sessionId));
    });
}
function normalizeCurrentImage(value) {
    if (!value || typeof value !== "object")
        return null;
    const item = value;
    return {
        id: cleanOption(item.id),
        filename: cleanOption(item.filename),
        url: cleanOption(item.url) ?? cleanOption(item.image),
        thumbUrl: cleanOption(item.thumbUrl) ?? cleanOption(item.thumb),
        prompt: cleanOption(item.prompt) ?? cleanOption(item.userPrompt),
        revisedPrompt: cleanOption(item.revisedPrompt),
        createdAt: typeof item.createdAt === "number" ? item.createdAt : null,
    };
}
function cleanOption(value) {
    return typeof value === "string" && value.trim() ? value.trim() : undefined;
}
function cleanPrompt(value) {
    const prompt = cleanOption(value);
    if (prompt)
        return prompt;
    const err = new Error("Prompt is required");
    err.code = "AGENT_PROMPT_REQUIRED";
    err.status = 400;
    throw err;
}
function normalizeQueueOptions(sessionId, body) {
    const current = getAgentGenerationSettings(sessionId);
    const input = body.options && typeof body.options === "object" ? body.options : {};
    return {
        ...current,
        ...input,
        provider: cleanOption(body.provider) ?? input.provider ?? current.provider,
        quality: cleanOption(body.quality) ?? input.quality ?? current.quality,
        size: cleanOption(body.size) ?? input.size ?? current.size,
        format: cleanOption(body.format) ?? input.format ?? current.format,
        moderation: cleanOption(body.moderation) ?? input.moderation ?? current.moderation,
        model: cleanOption(body.model) ?? input.model ?? current.model,
        reasoningEffort: cleanOption(body.reasoningEffort) ?? input.reasoningEffort ?? current.reasoningEffort,
        webSearchEnabled: typeof input.webSearchEnabled === "boolean" ? input.webSearchEnabled : current.webSearchEnabled,
        generationStrategy: input.generationStrategy ?? current.generationStrategy,
        variants: input.variants ?? current.variants,
        maxAutoVariants: input.maxAutoVariants ?? current.maxAutoVariants,
        parallelism: input.parallelism ?? current.parallelism,
    };
}
function queueActionError(code, message) {
    const err = new Error(message);
    err.code = code;
    err.status = 409;
    return err;
}
function queueItemNotFound(itemId) {
    const err = new Error(`Agent queue item not found: ${itemId}`);
    err.code = "AGENT_QUEUE_ITEM_NOT_FOUND";
    err.status = 404;
    return err;
}
function sendError(res, error) {
    const err = errInfo(error);
    res.status(err.status || 500).json({
        error: { code: err.code || "AGENT_ERROR", message: err.message },
        code: err.code || "AGENT_ERROR",
    });
}
function notFound(sessionId) {
    const err = new Error(`Agent session not found: ${sessionId}`);
    err.code = "AGENT_SESSION_NOT_FOUND";
    err.status = 404;
    return err;
}
function imageNotFound(sessionId) {
    const err = new Error(`Agent image not found in session: ${sessionId}`);
    err.code = "AGENT_IMAGE_NOT_FOUND";
    err.status = 404;
    return err;
}
