#!/usr/bin/env node
/**
 * Zed MCP bridge — translates JSON-RPC 2.0 (Zed's MCP client) to Vibn's
 * simpler {tool, params} HTTP API at /api/mcp.
 *
 * Usage:
 *   node mcp-zed-bridge.js
 *
 * Env:
 *   VIBN_MCP_URL  — defaults to https://vibnai.com/api/mcp
 *   VIBN_API_KEY  — your vibn_sk_... token
 */

const VIBNDEV_MCP_URL =
  process.env.VIBN_MCP_URL || "https://vibnai.com/api/mcp";
const VIBNDEV_API_KEY = process.env.VIBN_API_KEY || "";

if (!VIBNDEV_API_KEY) {
  process.stderr.write("VIBN_API_KEY is required\n");
  process.exit(1);
}

// ── JSON-RPC helpers ─────────────────────────────────────────────────

function sendJson(obj) {
  process.stdout.write(JSON.stringify(obj) + "\n");
}

function log(msg) {
  process.stderr.write(`[vibn-bridge] ${msg}\n`);
}

// ── Tool list from the API capability descriptor ──────────────────────

const TOOLS = [
  "workspace.describe",
  "gitea.credentials",
  "projects.list",
  "projects.get",
  "project.recent_errors",
  "project.error_detail",
  "project.error_resolve",
  "apps.list",
  "apps.get",
  "apps.create",
  "apps.update",
  "apps.rewire_git",
  "apps.delete",
  "apps.deploy",
  "apps.deployments",
  "apps.domains.list",
  "apps.domains.set",
  "apps.logs",
  "apps.exec",
  "apps.volumes.list",
  "apps.volumes.wipe",
  "apps.containers.up",
  "apps.containers.ps",
  "apps.repair",
  "apps.templates.list",
  "apps.templates.search",
  "apps.envs.list",
  "apps.envs.upsert",
  "apps.envs.delete",
  "databases.list",
  "databases.create",
  "databases.get",
  "databases.update",
  "databases.delete",
  "auth.list",
  "auth.create",
  "auth.delete",
  "domains.search",
  "domains.list",
  "domains.get",
  "domains.register",
  "domains.attach",
  "storage.describe",
  "storage.provision",
  "storage.inject_env",
  "gitea.repos.list",
  "gitea.repo.get",
  "gitea.repo.create",
  "gitea.file.read",
  "gitea.file.write",
  "gitea.file.delete",
  "gitea.branches.list",
  "gitea.branch.create",
  "devcontainer.ensure",
  "devcontainer.status",
  "devcontainer.suspend",
  "shell.exec",
  "fs.read",
  "fs.write",
  "fs.edit",
  "fs.list",
  "fs.tree",
  "fs.delete",
  "fs.glob",
  "fs.grep",
  "dev_server.start",
  "browser.console",
  "browser.navigate",
  "dev_server.stop",
  "dev_server.list",
  "dev_server.logs",
  "ship",
].map((name) => ({
  name,
  description: `Vibn workspace tool: ${name}`,
  inputSchema: {
    type: "object",
    properties: {
      projectId: { type: "string", description: "Vibn project ID" },
    },
  },
}));

// ── MCP protocol handlers ────────────────────────────────────────────

async function handleInitialize(id) {
  sendJson({
    jsonrpc: "2.0",
    id,
    result: {
      protocolVersion: "2024-11-05",
      capabilities: { tools: {} },
      serverInfo: { name: "vibn-mcp-bridge", version: "1.0.0" },
    },
  });
}

async function handleToolsList(id) {
  sendJson({
    jsonrpc: "2.0",
    id,
    result: { tools: TOOLS },
  });
}

async function handleToolsCall(id, params) {
  const { name, arguments: args } = params;

  try {
    const res = await fetch(VIBNDEV_MCP_URL, {
      method: "POST",
      headers: {
        "Content-Type": "application/json",
        Authorization: `Bearer ${VIBNDEV_API_KEY}`,
      },
      body: JSON.stringify({ tool: name, params: args }),
    });

    const data = await res.json();

    if (!res.ok) {
      sendJson({
        jsonrpc: "2.0",
        id,
        result: {
          content: [
            {
              type: "text",
              text: JSON.stringify(data, null, 2),
            },
          ],
          isError: true,
        },
      });
      return;
    }

    sendJson({
      jsonrpc: "2.0",
      id,
      result: {
        content: [
          {
            type: "text",
            text: JSON.stringify(data, null, 2),
          },
        ],
      },
    });
  } catch (err) {
    sendJson({
      jsonrpc: "2.0",
      id,
      result: {
        content: [
          {
            type: "text",
            text: `Error: ${err.message}`,
          },
        ],
        isError: true,
      },
    });
  }
}

// ── Main loop ─────────────────────────────────────────────────────────

let buffer = "";

process.stdin.setEncoding("utf8");
process.stdin.on("data", (chunk) => {
  buffer += chunk;
  const lines = buffer.split("\n");
  buffer = lines.pop() || "";

  for (const line of lines) {
    if (!line.trim()) continue;
    let msg;
    try {
      msg = JSON.parse(line);
    } catch {
      continue;
    }

    if (!msg.jsonrpc || !msg.method) continue;
    const id = msg.id;

    // Wrap in async IIFE so unhandled rejections don't crash the bridge
    (async () => {
      try {
        switch (msg.method) {
          case "initialize":
            await handleInitialize(id);
            break;
          case "notifications/initialized":
            // No response needed
            break;
          case "tools/list":
            await handleToolsList(id);
            break;
          case "tools/call":
            await handleToolsCall(id, msg.params);
            break;
          default:
            sendJson({
              jsonrpc: "2.0",
              id,
              error: {
                code: -32601,
                message: `Method not found: ${msg.method}`,
              },
            });
        }
      } catch (err) {
        log(`Error handling ${msg.method}: ${err.message}`);
        sendJson({
          jsonrpc: "2.0",
          id,
          error: { code: -32603, message: `Internal error: ${err.message}` },
        });
      }
    })();
  }
});

process.stdin.on("end", () => {
  log("stdin closed, exiting");
  process.exit(0);
});

log(`bridge started, proxying to ${VIBNDEV_MCP_URL}`);
