/**
 * pm2 ecosystem entry for legal-mcp-http — the legal-ai MCP server exposed over
 * streamable-http (TaskMaster #231).
 *
 * Why it exists
 *   Agents driven over the Agent Client Protocol get their MCP servers from the
 *   *client* at session start, and that channel carries HTTP servers only. A
 *   stdio server has no path into such a session, which is how platform-driven
 *   agents ended up with none of the 108 tools. This service is the HTTP end
 *   they can actually be pointed at.
 *
 *   It does NOT replace the stdio path. Every interactive Claude Code session
 *   still reaches the same server through the `legal-ai` entry in
 *   ~/.claude.json, spawned per session. Same code, same tool registry, two
 *   transports (G2) — this is a second *door*, not a second server.
 *
 * Security
 *   The registry includes case_delete, precedent_library_delete, document_upload
 *   and every block-writing tool, so an open port here is a delete-any-case
 *   endpoint. Two defences, both required:
 *     1. Bind 127.0.0.1 — the platform runs on this host, so loopback suffices.
 *        Deliberately narrower than legal-chat-service's 10.0.1.1: nothing in a
 *        container needs to call MCP.
 *     2. Bearer token — MCP_HTTP_SHARED_SECRET, loaded below. The server
 *        REFUSES TO START without it (services/http_auth.py), so a
 *        misconfiguration cannot silently produce an unauthenticated listener.
 *
 * Secret
 *   Source of truth: Infisical, project "All Infrastructure", env `main`,
 *   /apps/legal-ai/MCP_HTTP_SHARED_SECRET (tag: credentials). The file read
 *   below is a chmod-600 runtime copy, same arrangement as
 *   legal-chat-service.config.cjs. Rotate in Infisical first, then refresh the
 *   file and `pm2 restart legal-mcp-http`.
 *
 * Install (once):
 *     pm2 start /home/chaim/legal-ai/scripts/legal-mcp-http.config.cjs
 *     pm2 save
 *
 * Smoke test — expect 401 without the token, 200 with it:
 *     curl -s -o /dev/null -w '%{http_code}\n' -X POST http://127.0.0.1:8790/mcp \
 *       -H 'Content-Type: application/json' \
 *       -H 'Accept: application/json, text/event-stream' \
 *       -d '{"jsonrpc":"2.0","id":1,"method":"initialize","params":{"protocolVersion":"2024-11-05","capabilities":{},"clientInfo":{"name":"probe","version":"1"}}}'
 *
 * Update:  pm2 restart legal-mcp-http --update-env
 * Stop:    pm2 stop legal-mcp-http
 */
const fs = require("fs");

const ENV_FILE = "/home/chaim/.legal-mcp-http.env";
const env = {
  HOME: "/home/chaim",
  PATH: "/home/chaim/.local/bin:/usr/local/bin:/usr/bin:/bin",
  PYTHONUNBUFFERED: "1",
  // Same DB/data wiring the stdio server gets from ~/.claude.json, so both
  // transports read exactly the same corpus.
  DOTENV_PATH: "/home/chaim/.env",
  DATA_DIR: "/home/chaim/legal-ai/data",
  // Retrieval flags must match the container's, or the two doors into the same
  // corpus rank differently (G2 — a parallel path that drifts). The container
  // runs MULTIMODAL_ENABLED=true; without this the MCP door skipped the
  // page-image merge entirely, so an agent and the web UI could answer the same
  // question from different result sets. ~/.env sets neither, so both fell to
  // the code defaults (false) — the drift was silent.
  //
  // Blob storage must match the container too, for the same reason: a document
  // an agent writes through MCP has to be the one the web reads back. The MinIO
  // credentials now live in Infisical (/apps/legal-ai) and are loaded from the
  // runtime file below, exactly like MCP_HTTP_SHARED_SECRET.
  //
  // Verified from the host before enabling: put/get/delete round-trip against
  // https://s3.nautilus.marcusgroup.org, plus a read of an existing production
  // blob out of 2,283 objects. Note the S3 path imports aioboto3 LAZILY, so a
  // missing dependency does not fail at boot — it fails on the first blob
  // operation. It is declared in mcp-server/pyproject.toml; make sure the venv
  // actually has it (`.venv/bin/pip install -e mcp-server`).
  STORAGE_BACKEND: "s3",
  MULTIMODAL_ENABLED: "true",
  MCP_TRANSPORT: "streamable-http",
  MCP_HTTP_HOST: "127.0.0.1",
  MCP_HTTP_PORT: "8790",
};

try {
  const text = fs.readFileSync(ENV_FILE, "utf8");
  for (const line of text.split("\n")) {
    if (!line || line.trim().startsWith("#")) continue;
    const m = line.match(/^\s*([A-Z_][A-Z0-9_]*)\s*=\s*(.*?)\s*$/);
    if (m) env[m[1]] = m[2];
  }
} catch (e) {
  // Warn, but do not fabricate a token. The server's own gate turns a missing
  // secret into a refusal to boot, which is the outcome we want — pm2 will
  // surface it as a crash loop rather than serve unauthenticated traffic.
  console.error(`legal-mcp-http: failed to load ${ENV_FILE}: ${e.message}`);
  console.error("Service will refuse to start without MCP_HTTP_SHARED_SECRET.");
}

module.exports = {
  apps: [
    {
      name: "legal-mcp-http",
      cwd: "/home/chaim/legal-ai/mcp-server",
      script: "/home/chaim/legal-ai/mcp-server/.venv/bin/python",
      args: "-m legal_mcp.server",
      env,
      restart_delay: 5000,
      // Low ceiling on purpose: if the token is missing the process exits
      // immediately, and we want pm2 to stop retrying and leave an obvious
      // errored entry rather than loop forever on a config mistake.
      max_restarts: 10,
      autorestart: true,
      max_memory_restart: "800M",
    },
  ],
};
