/**
 * cmd-mcp-config.js — `qa-stlc mcp-config`
 *
 * Generates Claude Code and VS Code MCP config from one code path.
 * Both outputs carry the same cost-tracking env passthrough so model detection
 * stays consistent across coding agents.
 */

"use strict";

const path        = require("path");
const fs          = require("fs");
const os          = require("os");
const { spawnSync } = require("child_process");

const C = {
  reset: "\x1b[0m", bold: "\x1b[1m",
  green: "\x1b[32m", cyan: "\x1b[36m",
  yellow: "\x1b[33m", red: "\x1b[31m", dim: "\x1b[2m",
};
const ok   = (m) => console.log(`${C.green}✓${C.reset}  ${m}`);
const warn = (m) => console.log(`${C.yellow}⚠${C.reset}  ${m}`);

const PREF_FILE_MCP = path.join(os.homedir(), ".qa-stlc", "integration");

function readIntegrationPref() {
  try {
    if (fs.existsSync(PREF_FILE_MCP))
      return fs.readFileSync(PREF_FILE_MCP, "utf8").trim();
  } catch (_) {}
  return "ado";
}

const CWD    = process.cwd();
const IS_WIN = process.platform === "win32";
const EXT    = IS_WIN ? ".exe" : "";

const AGENT_NAMES    = [
  "qa-test-case-manager",
  "qa-gherkin-generator",
  "qa-playwright-generator",
  "qa-helix-writer",
  "qa-migration",
];
const JIRA_AGENT_NAME = "qa-jira-manager";

// ── Cost tracking env vars injected into every server entry ───────────────
//
// These are passed as env block items in both .mcp.json and .vscode/mcp.json.
// The "${env:X}" syntax is evaluated by Claude Code / VS Code at server start,
// substituting the actual value from the coding agent's own environment.
//
// ANTHROPIC_MODEL is the key one: Claude Code sets it automatically, so
// Claude Code users get correct pricing with zero manual configuration.
const COST_ENV = {
  // Carry the coding agent's model ID into the MCP subprocess
  "ANTHROPIC_MODEL":          "${env:ANTHROPIC_MODEL}",
  "GITHUB_COPILOT_MODEL":     "${env:GITHUB_COPILOT_MODEL}",
  // Explicit override — user sets this in shell profile if auto-detect is wrong
  "STLC_CODING_AGENT_MODEL":  "${env:STLC_CODING_AGENT_MODEL}",
  // Opt-out flag — user sets STLC_COST_TRACKING=false in their shell to silence output
  "STLC_COST_TRACKING":       "${env:STLC_COST_TRACKING}",
};

const JIRA_ENV_VARS = {
  JIRA_CLIENT_ID:     "${env:JIRA_CLIENT_ID}",
  JIRA_CLIENT_SECRET: "${env:JIRA_CLIENT_SECRET}",
  JIRA_CLOUD_ID:      "${env:JIRA_CLOUD_ID}",
};

function findBinary(name, pythonBin) {
  // 1. .venv in cwd
  const venvBin = IS_WIN
    ? path.join(CWD, ".venv", "Scripts", name + EXT)
    : path.join(CWD, ".venv", "bin", name);
  if (fs.existsSync(venvBin)) return venvBin;

  // 2. dir of --python flag binary
  if (pythonBin && pythonBin !== "python3" && pythonBin !== "python") {
    const candidate = path.join(path.dirname(pythonBin), name + EXT);
    if (fs.existsSync(candidate)) return candidate;
  }

  // 3. system PATH
  const which = spawnSync(IS_WIN ? "where" : "which", [name], { encoding: "utf8" });
  if (which.status === 0 && which.stdout.trim())
    return which.stdout.trim().split("\n")[0].trim();

  // 4. Python's own bin dir (framework installs not on PATH)
  for (const py of ["python3", "python"]) {
    const r = spawnSync(py, ["-c", "import sys,os;print(os.path.dirname(sys.executable))"], { encoding: "utf8" });
    if (r.status === 0 && r.stdout.trim()) {
      const candidate = path.join(r.stdout.trim(), name + EXT);
      if (fs.existsSync(candidate)) return candidate;
    }
  }

  // 5. macOS framework fallback
  if (!IS_WIN) {
    for (const v of ["3.13", "3.12", "3.11", "3.10"]) {
      const candidate = `/Library/Frameworks/Python.framework/Versions/${v}/bin/${name}`;
      if (fs.existsSync(candidate)) return candidate;
    }
  }
  return null;
}

// ── Claude Code config (.mcp.json) ────────────────────────────────────────

function buildClaudeConfig(pythonBin, playwrightPort, integration) {
  const servers = {};
  const missing = [];
  const needsAdo  = !integration || integration === "ado"  || integration === "both";
  const needsJira = integration === "jira" || integration === "both";
  const activeNames = (needsAdo || needsJira) ? AGENT_NAMES : [];

  for (const name of activeNames) {
    const bin = findBinary(name, pythonBin);
    if (bin) {
      // Every server gets the cost tracking env block
      servers[name] = { command: bin, env: { ...COST_ENV } };
    } else {
      missing.push(name);
      servers[name] = {
        command: `/path/to/.venv/bin/${name}`,
        env: { ...COST_ENV },
        "_comment": "NOT FOUND — run: pip install qa-gentic-stlc-agents",
      };
    }
  }

  if (needsJira) {
    const jiraBin = findBinary(JIRA_AGENT_NAME, pythonBin);
    if (jiraBin) {
      servers[JIRA_AGENT_NAME] = {
        command: jiraBin,
        env: { ...COST_ENV, ...JIRA_ENV_VARS },
      };
    } else {
      missing.push(JIRA_AGENT_NAME);
      servers[JIRA_AGENT_NAME] = {
        command: `/path/to/.venv/bin/${JIRA_AGENT_NAME}`,
        env: { ...COST_ENV, ...JIRA_ENV_VARS },
        "_comment": "NOT FOUND — run: pip install qa-gentic-stlc-agents",
      };
    }
  }

  servers["playwright"] = {
    command: "npx",
    args: ["@playwright/mcp@latest", "--isolated"],
  };

  return { config: { mcpServers: servers }, missing };
}

// ── VS Code config (.vscode/mcp.json) ─────────────────────────────────────

function buildVscodeConfig(pythonBin, playwrightPort, integration) {
  const servers = {};
  const missing = [];
  const needsAdo  = !integration || integration === "ado"  || integration === "both";
  const needsJira = integration === "jira" || integration === "both";
  const activeNames = (needsAdo || needsJira) ? AGENT_NAMES : [];

  for (const name of activeNames) {
    const bin = findBinary(name, pythonBin);
    if (bin) {
      servers[name] = {
        type: "stdio",
        command: bin,
        env: { ...COST_ENV },
      };
    } else {
      missing.push(name);
      servers[name] = {
        type: "stdio",
        command: `/path/to/.venv/bin/${name}`,
        env: { ...COST_ENV },
        "_comment": "NOT FOUND — run: pip install qa-gentic-stlc-agents",
      };
    }
  }

  if (needsJira) {
    const jiraBin = findBinary(JIRA_AGENT_NAME, pythonBin);
    if (jiraBin) {
      servers[JIRA_AGENT_NAME] = {
        type: "stdio",
        command: jiraBin,
        env: { ...COST_ENV, ...JIRA_ENV_VARS },
      };
    } else {
      missing.push(JIRA_AGENT_NAME);
      servers[JIRA_AGENT_NAME] = {
        type: "stdio",
        command: `/path/to/.venv/bin/${JIRA_AGENT_NAME}`,
        env: { ...COST_ENV, ...JIRA_ENV_VARS },
        "_comment": "NOT FOUND — run: pip install qa-gentic-stlc-agents",
      };
    }
  }

  servers["playwright"] = {
    type: "stdio",
    command: "npx",
    args: ["@playwright/mcp@latest", "--isolated"],
  };

  return { config: { servers }, missing };
}

function printNextSteps(mode, playwrightPort) {
  const isVscode = mode === "vscode";
  console.log(`
  ${C.dim}Playwright MCP is auto-started by the MCP framework (--isolated, no manual start needed).
  For CI/headless: set PLAYWRIGHT_MCP_URL or start manually with --headless --isolated --port ${playwrightPort}${C.reset}

  ${isVscode
    ? `Reload VS Code window — all MCP servers will appear in the MCP panel.`
    : `In Claude Code, run /mcp to verify all servers are loaded.`
  }

  ${C.dim}Cost tracking is active on all servers.
  Each tool call logs tokens + cost to ~/.qa-stlc/cost-<session>.jsonl
  View reports: qa-stlc cost${C.reset}
`);
}

module.exports = async function mcpConfig(opts) {
  const useVscode      = opts.vscode || false;
  const printOnly      = opts.print  || false;
  const pythonBin      = opts.python || "python3";
  const playwrightPort = opts.playwrightPort || "8931";
  const integration    = (opts.integration || readIntegrationPref() || "ado").toLowerCase();

  if (printOnly) {
    const { config: claudeCfg } = buildClaudeConfig(pythonBin, playwrightPort, integration);
    const { config: vscodeCfg } = buildVscodeConfig(pythonBin, playwrightPort, integration);
    console.log("\n=== Claude Code (.mcp.json) ===");
    console.log(JSON.stringify(claudeCfg, null, 2));
    console.log("\n=== VS Code (.vscode/mcp.json) ===");
    console.log(JSON.stringify(vscodeCfg, null, 2));
    printNextSteps("both", playwrightPort);
    return;
  }

  if (useVscode) {
    const { config, missing } = buildVscodeConfig(pythonBin, playwrightPort, integration);
    const dir = path.join(CWD, ".vscode");
    fs.mkdirSync(dir, { recursive: true });
    const out = path.join(dir, "mcp.json");
    fs.writeFileSync(out, JSON.stringify(config, null, 2) + "\n", "utf8");
    ok(`Written → .vscode/mcp.json  (cost tracking env vars included)`);
    if (missing.length) {
      warn(`${missing.length} agent(s) not found — run: pip install qa-gentic-stlc-agents`);
      missing.forEach((m) => warn(`  missing: ${m}`));
    }
    printNextSteps("vscode", playwrightPort);
  } else {
    const { config, missing } = buildClaudeConfig(pythonBin, playwrightPort, integration);
    const out = path.join(CWD, ".mcp.json");
    fs.writeFileSync(out, JSON.stringify(config, null, 2) + "\n", "utf8");
    ok(`Written → .mcp.json  (cost tracking env vars included)`);
    if (missing.length) {
      warn(`${missing.length} agent(s) not found — run: pip install qa-gentic-stlc-agents`);
      missing.forEach((m) => warn(`  missing: ${m}`));
    }
    printNextSteps("claude", playwrightPort);
  }
};