/**
 * Proxy Tools — tool-server spec exposing proxy tools to agent sessions.
 *
 * Injected into EVERY chat session — both regular chats and agent chats.
 * In local mode: calls go through LocalProxy (in-process).
 * In remote mode: calls go through ProxyClient (encrypted HTTP).
 *
 * Returns a provider-neutral {@link ToolServerSpec}; callers translate to their
 * engine's registration shape via `provider.buildToolServer(spec)`.
 */
import { z } from "zod";
import { getProxy } from "./proxy-singleton.js";
import { createLogger } from "../utils/logger.js";
import { defineTool } from "../agents/ports/tools.js";
const log = createLogger("proxy-tools");
/**
 * Build a tool-server spec exposing proxy tools.
 *
 * @param keyAlias - The MCP key alias to use for proxy requests
 */
export function buildProxyToolsSpec(keyAlias) {
    log.debug(`Building proxy tools spec for alias="${keyAlias}"`);
    return {
        name: "mcp-proxy",
        version: "1.0.0",
        tools: [
            defineTool("secure_request", "Make an authenticated HTTP request through a configured connection. " +
                "Route-level headers (e.g., Authorization) are injected automatically by the server — " +
                "do not send them yourself. You may use ${VAR_NAME} placeholders for other secrets in " +
                "the URL, headers, or body. Use list_routes first to discover available APIs. " +
                "Supports file attachments via the files parameter for multipart uploads.", {
                method: z.enum(["GET", "POST", "PUT", "PATCH", "DELETE"]).describe("HTTP method"),
                url: z.string().describe("Full URL, may contain ${VAR} placeholders"),
                headers: z.record(z.string(), z.string()).optional().describe("Request headers, may contain ${VAR} placeholders"),
                body: z.any().optional().describe("Request body (object for JSON, string for raw)"),
                files: z
                    .array(z.object({
                    field: z.string().describe("Form field name (e.g., 'files[0]')"),
                    path: z.string().describe("Absolute path to the file on disk"),
                    filename: z.string().describe("Filename for the upload"),
                    contentType: z.string().describe("MIME type (e.g., 'image/png')"),
                }))
                    .optional()
                    .describe("File attachments for multipart upload"),
                bodyFieldName: z.string().optional().describe("Form field name for the JSON body (defaults to 'payload_json')"),
            }, async (input) => {
                const proxy = getProxy(keyAlias);
                if (!proxy) {
                    return {
                        content: [{ type: "text", text: "Proxy not configured. Set up proxy in Agent Settings." }],
                    };
                }
                try {
                    const result = await proxy.callTool("http_request", input);
                    return {
                        content: [{ type: "text", text: JSON.stringify(result) }],
                    };
                }
                catch (err) {
                    log.error(`secure_request failed: ${err.message}`);
                    return {
                        content: [{ type: "text", text: `Error: ${err.message}` }],
                    };
                }
            }),
            defineTool("list_routes", "List all available API routes/connections and their endpoints, " +
                "auto-injected headers, and available secret placeholder names. " +
                "Use this to discover which APIs are available before making requests.", {}, async () => {
                const proxy = getProxy(keyAlias);
                if (!proxy) {
                    return {
                        content: [{ type: "text", text: "Proxy not configured. Set up proxy in Agent Settings." }],
                    };
                }
                try {
                    const result = await proxy.callTool("list_routes");
                    return {
                        content: [{ type: "text", text: JSON.stringify(result) }],
                    };
                }
                catch (err) {
                    log.error(`list_routes failed: ${err.message}`);
                    return {
                        content: [{ type: "text", text: `Error: ${err.message}` }],
                    };
                }
            }),
            defineTool("poll_events", "Poll for new events from ingestors (Discord messages, GitHub webhooks, etc.). " +
                "Returns events received since the given cursor. Pass after_id from the last event " +
                "you received to get only new events. Omit connection to get events from all ingestors.", {
                connection: z.string().optional().describe('Connection alias to poll (e.g., "discord-bot"). Omit for all.'),
                after_id: z.number().optional().describe("Return events with id > after_id. Omit or -1 for all buffered events."),
                instance_id: z.string().optional().describe("Instance ID to filter events from. Only returns events from this specific listener instance."),
            }, async (input) => {
                const proxy = getProxy(keyAlias);
                if (!proxy) {
                    return {
                        content: [{ type: "text", text: "Proxy not configured. Set up proxy in Agent Settings." }],
                    };
                }
                try {
                    const result = await proxy.callTool("poll_events", input);
                    return {
                        content: [{ type: "text", text: JSON.stringify(result) }],
                    };
                }
                catch (err) {
                    log.error(`poll_events failed: ${err.message}`);
                    return {
                        content: [{ type: "text", text: `Error: ${err.message}` }],
                    };
                }
            }),
            defineTool("test_connection", "Verify API credentials with a non-destructive read-only test request. " +
                "Use this to check if a connection's secrets are correctly configured before making real requests.", {
                connection: z.string().describe('Connection alias to test (e.g., "github", "slack")'),
            }, async (input) => {
                const proxy = getProxy(keyAlias);
                if (!proxy) {
                    return {
                        content: [{ type: "text", text: "Proxy not configured. Set up proxy in Agent Settings." }],
                    };
                }
                try {
                    const result = await proxy.callTool("test_connection", input);
                    return {
                        content: [{ type: "text", text: JSON.stringify(result) }],
                    };
                }
                catch (err) {
                    log.error(`test_connection failed: ${err.message}`);
                    return {
                        content: [{ type: "text", text: `Error: ${err.message}` }],
                    };
                }
            }),
            defineTool("test_ingestor", "Verify event listener configuration without starting it. " +
                "Checks credentials, webhook secrets, and listener parameters for a connection's ingestor.", {
                connection: z.string().describe('Connection alias to test (e.g., "discord-bot", "github")'),
            }, async (input) => {
                const proxy = getProxy(keyAlias);
                if (!proxy) {
                    return {
                        content: [{ type: "text", text: "Proxy not configured. Set up proxy in Agent Settings." }],
                    };
                }
                try {
                    const result = await proxy.callTool("test_ingestor", input);
                    return {
                        content: [{ type: "text", text: JSON.stringify(result) }],
                    };
                }
                catch (err) {
                    log.error(`test_ingestor failed: ${err.message}`);
                    return {
                        content: [{ type: "text", text: `Error: ${err.message}` }],
                    };
                }
            }),
            defineTool("control_listener", "Start, stop, or restart an event listener for a connection. " +
                "Stopping a listener pauses event collection; starting resumes it. " +
                "Use restart after configuration changes.", {
                connection: z.string().describe('Connection alias (e.g., "discord-bot")'),
                action: z.enum(["start", "stop", "restart"]).describe("Lifecycle action to perform"),
                instance_id: z.string().optional().describe("Instance ID for multi-instance listeners. Omit to control all instances."),
            }, async (input) => {
                const proxy = getProxy(keyAlias);
                if (!proxy) {
                    return {
                        content: [{ type: "text", text: "Proxy not configured. Set up proxy in Agent Settings." }],
                    };
                }
                try {
                    const result = await proxy.callTool("control_listener", input);
                    return {
                        content: [{ type: "text", text: JSON.stringify(result) }],
                    };
                }
                catch (err) {
                    log.error(`control_listener failed: ${err.message}`);
                    return {
                        content: [{ type: "text", text: `Error: ${err.message}` }],
                    };
                }
            }),
            defineTool("list_listener_configs", "List configurable event listener schemas for all connections. " +
                "Returns field definitions (type, label, options, defaults) that can be used to render configuration forms.", {}, async () => {
                const proxy = getProxy(keyAlias);
                if (!proxy) {
                    return {
                        content: [{ type: "text", text: "Proxy not configured. Set up proxy in Agent Settings." }],
                    };
                }
                try {
                    const result = await proxy.callTool("list_listener_configs");
                    return {
                        content: [{ type: "text", text: JSON.stringify(result) }],
                    };
                }
                catch (err) {
                    log.error(`list_listener_configs failed: ${err.message}`);
                    return {
                        content: [{ type: "text", text: `Error: ${err.message}` }],
                    };
                }
            }),
            defineTool("resolve_listener_options", "Fetch dynamic options for a listener configuration field. " + "Some fields (like Trello boards) require an API call to populate their options list.", {
                connection: z.string().describe('Connection alias (e.g., "trello")'),
                paramKey: z.string().describe('The field key to resolve options for (e.g., "boardId")'),
            }, async (input) => {
                const proxy = getProxy(keyAlias);
                if (!proxy) {
                    return {
                        content: [{ type: "text", text: "Proxy not configured. Set up proxy in Agent Settings." }],
                    };
                }
                try {
                    const result = await proxy.callTool("resolve_listener_options", input);
                    return {
                        content: [{ type: "text", text: JSON.stringify(result) }],
                    };
                }
                catch (err) {
                    log.error(`resolve_listener_options failed: ${err.message}`);
                    return {
                        content: [{ type: "text", text: `Error: ${err.message}` }],
                    };
                }
            }),
            defineTool("get_listener_params", "Read current listener parameter overrides for a connection. " +
                "Returns both the active parameter values and their schema defaults. " +
                "Use this to populate configuration forms with actual values.", {
                connection: z.string().describe('Connection alias (e.g., "trello", "discord-bot")'),
                instance_id: z.string().optional().describe("Instance ID for multi-instance listeners. Omit for single-instance."),
            }, async (input) => {
                const proxy = getProxy(keyAlias);
                if (!proxy) {
                    return {
                        content: [{ type: "text", text: "Proxy not configured. Set up proxy in Agent Settings." }],
                    };
                }
                try {
                    const result = await proxy.callTool("get_listener_params", input);
                    return {
                        content: [{ type: "text", text: JSON.stringify(result) }],
                    };
                }
                catch (err) {
                    log.error(`get_listener_params failed: ${err.message}`);
                    return {
                        content: [{ type: "text", text: `Error: ${err.message}` }],
                    };
                }
            }),
            defineTool("set_listener_params", "Set listener parameter overrides for a connection. " +
                "Validates params against the schema, merges with existing config, and persists. " +
                "Supports create_instance flag for multi-instance listeners.", {
                connection: z.string().describe('Connection alias (e.g., "trello", "discord-bot")'),
                instance_id: z.string().optional().describe("Instance ID for multi-instance listeners. Omit for single-instance."),
                params: z.record(z.string(), z.unknown()).describe("Key-value pairs to set. Keys must match listener config field keys."),
                create_instance: z.boolean().optional().describe("If true, create the instance if it doesn't exist (multi-instance only)."),
            }, async (input) => {
                const proxy = getProxy(keyAlias);
                if (!proxy) {
                    return {
                        content: [{ type: "text", text: "Proxy not configured. Set up proxy in Agent Settings." }],
                    };
                }
                try {
                    const result = await proxy.callTool("set_listener_params", input);
                    return {
                        content: [{ type: "text", text: JSON.stringify(result) }],
                    };
                }
                catch (err) {
                    log.error(`set_listener_params failed: ${err.message}`);
                    return {
                        content: [{ type: "text", text: `Error: ${err.message}` }],
                    };
                }
            }),
            defineTool("list_listener_instances", "List all configured instances for a multi-instance listener connection. " +
                "Returns every instance from config (including stopped/disabled ones), " +
                "unlike ingestor_status which only shows running instances.", {
                connection: z.string().describe('Connection alias (e.g., "trello")'),
            }, async (input) => {
                const proxy = getProxy(keyAlias);
                if (!proxy) {
                    return {
                        content: [{ type: "text", text: "Proxy not configured. Set up proxy in Agent Settings." }],
                    };
                }
                try {
                    const result = await proxy.callTool("list_listener_instances", input);
                    return {
                        content: [{ type: "text", text: JSON.stringify(result) }],
                    };
                }
                catch (err) {
                    log.error(`list_listener_instances failed: ${err.message}`);
                    return {
                        content: [{ type: "text", text: `Error: ${err.message}` }],
                    };
                }
            }),
            defineTool("delete_listener_instance", "Remove a multi-instance listener instance. " + "Stops the running ingestor if active, removes from config, and cleans up.", {
                connection: z.string().describe('Connection alias (e.g., "trello")'),
                instance_id: z.string().describe("Instance ID to delete"),
            }, async (input) => {
                const proxy = getProxy(keyAlias);
                if (!proxy) {
                    return {
                        content: [{ type: "text", text: "Proxy not configured. Set up proxy in Agent Settings." }],
                    };
                }
                try {
                    const result = await proxy.callTool("delete_listener_instance", input);
                    return {
                        content: [{ type: "text", text: JSON.stringify(result) }],
                    };
                }
                catch (err) {
                    log.error(`delete_listener_instance failed: ${err.message}`);
                    return {
                        content: [{ type: "text", text: `Error: ${err.message}` }],
                    };
                }
            }),
            defineTool("ingestor_status", "Get the status of all active ingestors for this caller. " + "Shows connection state, buffer sizes, event counts, and any errors.", {}, async () => {
                const proxy = getProxy(keyAlias);
                if (!proxy) {
                    return {
                        content: [{ type: "text", text: "Proxy not configured. Set up proxy in Agent Settings." }],
                    };
                }
                try {
                    const result = await proxy.callTool("ingestor_status");
                    return {
                        content: [{ type: "text", text: JSON.stringify(result) }],
                    };
                }
                catch (err) {
                    log.error(`ingestor_status failed: ${err.message}`);
                    return {
                        content: [{ type: "text", text: `Error: ${err.message}` }],
                    };
                }
            }),
        ],
    };
}
