/**
 * Connection management API routes.
 *
 * Provides endpoints for listing connection templates, toggling
 * connections, managing secrets, and managing caller aliases —
 * all for local mode.
 *
 * All connection-scoped endpoints accept an optional `caller` parameter
 * (query param or body field) to specify which caller alias to operate on.
 * Defaults to "default" when omitted.
 */
import { Router } from "express";
import { listConnectionsWithStatus, getConnectionStatus, setConnectionEnabled, setSecrets, listCallerAliases, createCallerAlias, deleteCallerAlias, listRemoteConnections, setRemoteConnectionEnabled, setRemoteSecrets, getRemoteSecretStatus, listListenerInstances, addListenerInstance, updateListenerInstance, deleteListenerInstance, } from "../services/connection-manager.js";
import { getAgentSettings, getActiveMcpConfigDir } from "../services/agent-settings.js";
import { isProxyConfigured, getConfiguredAliases } from "../services/proxy-singleton.js";
import { createLogger } from "../utils/logger.js";
const log = createLogger("connections-routes");
export const connectionsRouter = Router();
// ── Caller alias management ─────────────────────────────────────────
/**
 * GET /api/connections/callers
 *
 * List all configured caller aliases.
 */
// #swagger.tags = ['Connections']
// #swagger.summary = 'List caller aliases'
/* #swagger.responses[200] = { description: "List of caller aliases" } */
connectionsRouter.get("/callers", (_req, res) => {
    try {
        const settings = getAgentSettings();
        const localActive = settings.proxyMode === "local" && !!getActiveMcpConfigDir();
        const remoteActive = settings.proxyMode === "remote" && isProxyConfigured();
        if (localActive) {
            const callers = listCallerAliases();
            res.json({ callers });
            return;
        }
        if (remoteActive) {
            // In remote mode, callers are key aliases (read-only, no create/delete)
            const aliases = getConfiguredAliases();
            const callers = aliases.map((alias) => ({
                alias,
                connectionCount: 0, // Unknown until routes are fetched
            }));
            res.json({ callers });
            return;
        }
        res.json({ callers: [] });
    }
    catch (err) {
        log.error(`Error listing caller aliases: ${err.message}`);
        res.status(500).json({ error: "Failed to list caller aliases" });
    }
});
/**
 * POST /api/connections/callers
 *
 * Create a new caller alias.
 * Body: { alias: string, name?: string }
 */
// #swagger.tags = ['Connections']
// #swagger.summary = 'Create a new caller alias'
/* #swagger.requestBody = {
  required: true,
  content: {
    "application/json": {
      schema: {
        type: "object",
        required: ["alias"],
        properties: {
          alias: { type: "string" },
          name: { type: "string" }
        }
      }
    }
  }
} */
/* #swagger.responses[200] = { description: "Caller created" } */
/* #swagger.responses[400] = { description: "Invalid request" } */
connectionsRouter.post("/callers", (req, res) => {
    const { alias, name } = req.body;
    if (!alias || typeof alias !== "string") {
        res.status(400).json({ error: "alias is required and must be a string" });
        return;
    }
    // Validate alias format (alphanumeric, hyphens, underscores)
    if (!/^[a-zA-Z0-9][a-zA-Z0-9_-]*$/.test(alias)) {
        res.status(400).json({
            error: "alias must start with a letter or number and contain only letters, numbers, hyphens, and underscores",
        });
        return;
    }
    try {
        const caller = createCallerAlias(alias, name);
        res.json({ caller });
    }
    catch (err) {
        if (err.message.includes("already exists")) {
            res.status(409).json({ error: err.message });
        }
        else {
            log.error(`Error creating caller alias: ${err.message}`);
            res.status(500).json({ error: "Failed to create caller alias" });
        }
    }
});
/**
 * DELETE /api/connections/callers/:callerAlias
 *
 * Delete a caller alias and its associated env vars.
 */
// #swagger.tags = ['Connections']
// #swagger.summary = 'Delete a caller alias'
/* #swagger.responses[200] = { description: "Caller deleted" } */
/* #swagger.responses[400] = { description: "Cannot delete default caller" } */
/* #swagger.responses[404] = { description: "Caller not found" } */
connectionsRouter.delete("/callers/:callerAlias", async (req, res) => {
    const { callerAlias } = req.params;
    try {
        await deleteCallerAlias(callerAlias);
        res.json({ deleted: callerAlias });
    }
    catch (err) {
        if (err.message.includes("Cannot delete")) {
            res.status(400).json({ error: err.message });
        }
        else if (err.message.includes("not found")) {
            res.status(404).json({ error: err.message });
        }
        else {
            log.error(`Error deleting caller alias: ${err.message}`);
            res.status(500).json({ error: "Failed to delete caller alias" });
        }
    }
});
// ── Connection template endpoints ───────────────────────────────────
/**
 * GET /api/connections
 *
 * List all connection templates with runtime status (enabled, secrets set).
 * Query: ?caller=X (default: "default")
 */
// #swagger.tags = ['Connections']
// #swagger.summary = 'List all connection templates with status'
/* #swagger.responses[200] = { description: "Connection templates with status" } */
connectionsRouter.get("/", async (req, res) => {
    try {
        const settings = getAgentSettings();
        const localModeActive = settings.proxyMode === "local" && !!getActiveMcpConfigDir();
        const remoteModeActive = settings.proxyMode === "remote" && isProxyConfigured();
        if (localModeActive) {
            const callerAlias = req.query.caller || "default";
            const templates = listConnectionsWithStatus(callerAlias);
            const callers = listCallerAliases();
            res.json({ templates, callers, localModeActive: true, remoteModeActive: false, remoteConfigManagement: false });
            return;
        }
        if (remoteModeActive) {
            const callerAlias = req.query.caller || undefined;
            const { templates, callers, remoteConfigManagement } = await listRemoteConnections(callerAlias);
            res.json({ templates, callers, localModeActive: false, remoteModeActive: true, remoteConfigManagement });
            return;
        }
        // Neither mode is active
        res.json({ templates: [], callers: [], localModeActive: false, remoteModeActive: false, remoteConfigManagement: false });
    }
    catch (err) {
        log.error(`Error listing connections: ${err.message}`);
        res.status(500).json({ error: "Failed to list connections" });
    }
});
/**
 * POST /api/connections/:alias/enable
 *
 * Enable or disable a connection for a specific caller.
 * Body: { enabled: boolean, caller?: string }
 */
// #swagger.tags = ['Connections']
// #swagger.summary = 'Enable or disable a connection'
/* #swagger.requestBody = {
  required: true,
  content: {
    "application/json": {
      schema: {
        type: "object",
        required: ["enabled"],
        properties: {
          enabled: { type: "boolean" },
          caller: { type: "string" }
        }
      }
    }
  }
} */
/* #swagger.responses[200] = { description: "Connection toggled" } */
/* #swagger.responses[400] = { description: "Invalid request" } */
connectionsRouter.post("/:alias/enable", async (req, res) => {
    const { alias } = req.params;
    const { enabled, caller } = req.body;
    const callerAlias = caller || "default";
    if (typeof enabled !== "boolean") {
        res.status(400).json({ error: "enabled must be a boolean" });
        return;
    }
    try {
        const settings = getAgentSettings();
        const remoteModeActive = settings.proxyMode === "remote" && isProxyConfigured();
        if (remoteModeActive) {
            await setRemoteConnectionEnabled(alias, enabled, callerAlias);
        }
        else {
            await setConnectionEnabled(alias, enabled, callerAlias);
        }
        res.json({ alias, enabled });
    }
    catch (err) {
        log.error(`Error toggling connection ${alias}: ${err.message}`);
        res.status(500).json({ error: "Failed to toggle connection" });
    }
});
/**
 * PUT /api/connections/:alias/secrets
 *
 * Set secrets for a connection, scoped to a specific caller.
 * Body: { secrets: { SECRET_NAME: "value", ... }, caller?: string }
 * An empty string value deletes the secret.
 */
// #swagger.tags = ['Connections']
// #swagger.summary = 'Set secrets for a connection'
/* #swagger.requestBody = {
  required: true,
  content: {
    "application/json": {
      schema: {
        type: "object",
        required: ["secrets"],
        properties: {
          secrets: { type: "object", additionalProperties: { type: "string" } },
          caller: { type: "string" }
        }
      }
    }
  }
} */
/* #swagger.responses[200] = { description: "Secrets updated" } */
/* #swagger.responses[400] = { description: "Invalid request" } */
connectionsRouter.put("/:alias/secrets", async (req, res) => {
    const { secrets, caller } = req.body;
    const callerAlias = caller || "default";
    if (!secrets || typeof secrets !== "object") {
        res.status(400).json({ error: "secrets must be an object" });
        return;
    }
    try {
        const settings = getAgentSettings();
        const remoteModeActive = settings.proxyMode === "remote" && isProxyConfigured();
        const status = remoteModeActive ? await setRemoteSecrets(secrets, callerAlias) : await setSecrets(secrets, callerAlias);
        res.json({ secretsSet: status });
    }
    catch (err) {
        log.error(`Error setting secrets for ${req.params.alias}: ${err.message}`);
        res.status(500).json({ error: "Failed to set secrets" });
    }
});
/**
 * GET /api/connections/:alias/secrets
 *
 * Check which secrets are set for a connection (never returns actual values).
 * Query: ?caller=X (default: "default")
 * Returns { secretsSet: { SECRET_NAME: boolean, ... } }
 */
// #swagger.tags = ['Connections']
// #swagger.summary = 'Check which secrets are set for a connection'
/* #swagger.responses[200] = { description: "Secret status" } */
/* #swagger.responses[404] = { description: "Connection not found" } */
connectionsRouter.get("/:alias/secrets", async (req, res) => {
    try {
        const callerAlias = req.query.caller || "default";
        const settings = getAgentSettings();
        const remoteModeActive = settings.proxyMode === "remote" && isProxyConfigured();
        if (remoteModeActive) {
            const { requiredSecretsSet, optionalSecretsSet } = await getRemoteSecretStatus(req.params.alias, callerAlias);
            res.json({ secretsSet: { ...requiredSecretsSet, ...optionalSecretsSet } });
            return;
        }
        const status = getConnectionStatus(req.params.alias, callerAlias);
        if (!status) {
            res.status(404).json({ error: "Connection template not found" });
            return;
        }
        res.json({
            secretsSet: {
                ...status.requiredSecretsSet,
                ...status.optionalSecretsSet,
            },
        });
    }
    catch (err) {
        log.error(`Error checking secrets for ${req.params.alias}: ${err.message}`);
        res.status(500).json({ error: "Failed to check secrets" });
    }
});
// ── Listener instance management (local mode only) ──────────────────
/**
 * GET /api/connections/:alias/listener-instances
 *
 * List all listener instances for a connection.
 * Query: ?caller=X (default: "default")
 */
connectionsRouter.get("/:alias/listener-instances", (req, res) => {
    try {
        const callerAlias = req.query.caller || "default";
        const instances = listListenerInstances(req.params.alias, callerAlias);
        res.json({ instances });
    }
    catch (err) {
        log.error(`Error listing listener instances for ${req.params.alias}: ${err.message}`);
        res.status(500).json({ error: "Failed to list listener instances" });
    }
});
/**
 * POST /api/connections/:alias/listener-instances
 *
 * Create a new listener instance.
 * Body: { instanceId: string, params?: Record<string, unknown>, caller?: string }
 */
connectionsRouter.post("/:alias/listener-instances", async (req, res) => {
    const { instanceId, params, caller } = req.body;
    const callerAlias = caller || "default";
    if (!instanceId || typeof instanceId !== "string") {
        res.status(400).json({ error: "instanceId is required and must be a string" });
        return;
    }
    // Validate instanceId format
    if (!/^[a-zA-Z0-9][a-zA-Z0-9_-]*$/.test(instanceId)) {
        res.status(400).json({
            error: "instanceId must start with a letter or number and contain only letters, numbers, hyphens, and underscores",
        });
        return;
    }
    try {
        const instance = await addListenerInstance(req.params.alias, instanceId, params || {}, callerAlias);
        res.json({ instance });
    }
    catch (err) {
        if (err.message.includes("already exists")) {
            res.status(409).json({ error: err.message });
        }
        else {
            log.error(`Error creating listener instance: ${err.message}`);
            res.status(500).json({ error: "Failed to create listener instance" });
        }
    }
});
/**
 * PUT /api/connections/:alias/listener-instances/:instanceId
 *
 * Update a listener instance's parameters.
 * Body: { params?: Record<string, unknown>, disabled?: boolean, caller?: string }
 */
connectionsRouter.put("/:alias/listener-instances/:instanceId", async (req, res) => {
    const { params, disabled, caller } = req.body;
    const callerAlias = caller || "default";
    try {
        const instance = await updateListenerInstance(req.params.alias, req.params.instanceId, params || {}, disabled, callerAlias);
        res.json({ instance });
    }
    catch (err) {
        if (err.message.includes("not found")) {
            res.status(404).json({ error: err.message });
        }
        else {
            log.error(`Error updating listener instance: ${err.message}`);
            res.status(500).json({ error: "Failed to update listener instance" });
        }
    }
});
/**
 * DELETE /api/connections/:alias/listener-instances/:instanceId
 *
 * Delete a listener instance.
 * Query: ?caller=X (default: "default")
 */
connectionsRouter.delete("/:alias/listener-instances/:instanceId", async (req, res) => {
    const callerAlias = req.query.caller || req.body?.caller || "default";
    try {
        await deleteListenerInstance(req.params.alias, req.params.instanceId, callerAlias);
        res.json({ deleted: req.params.instanceId });
    }
    catch (err) {
        if (err.message.includes("not found")) {
            res.status(404).json({ error: err.message });
        }
        else {
            log.error(`Error deleting listener instance: ${err.message}`);
            res.status(500).json({ error: "Failed to delete listener instance" });
        }
    }
});
