#!/usr/bin/env node
/**
 * postinstall.js — Auto-install Python MCP servers after npm install -g
 *
 * Goals
 * -----
 *   1. Always finish with a working `qa-stlc-apply-cost` on PATH (or in a
 *      well-known location like ~/.local/bin), without ever surfacing raw
 *      pip / PEP 668 traceback output to the user's terminal.
 *   2. Auto-install pipx when missing (brew on macOS, pip --user elsewhere).
 *   3. Never run the cost-tracking patch when the Python package isn't
 *      actually installed — that produces a misleading ModuleNotFoundError.
 *
 * npm 7+ swallows stdout/stderr from global lifecycle scripts, so all
 * user-facing writes go straight to /dev/tty (with stderr as a fallback).
 */
"use strict";

const fs   = require("fs");
const os   = require("os");
const path = require("path");
const { spawnSync } = require("child_process");
const pkg = require("../package.json");
const { formatNextSteps } = require("../src/cli/next-steps");

// ── Output: write to /dev/tty so npm 7+ doesn't swallow our messages ─────────
let _tty = null;
try { _tty = fs.openSync("/dev/tty", "w"); } catch (_) { /* Windows / CI */ }
const _write = (msg) => {
  const line = msg + "\n";
  if (_tty !== null) {
    try { fs.writeSync(_tty, line); return; } catch (_) {}
  }
  process.stderr.write(line);
};
console.log = console.info = console.warn = console.error = _write;

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

const ENTRY = "qa-stlc-apply-cost";

// Walk PATH plus the well-known pipx / pip --user dirs so we still find
// scripts even when the shell hasn't refreshed PATH since `pipx install`.
const findCommand = (cmd) => {
  const exts = process.platform === "win32" ? [".cmd", ".exe", ".bat", ""] : [""];
  const dirs = [...(process.env.PATH || "").split(path.delimiter)];
  dirs.push(path.join(os.homedir(), ".local", "bin"));
  if (process.platform === "darwin") {
    dirs.push("/opt/homebrew/bin", "/usr/local/bin");
  }
  for (const dir of dirs) {
    if (!dir) continue;
    for (const ext of exts) {
      const p = path.join(dir, cmd + ext);
      try { if (fs.existsSync(p)) return p; } catch (_) {}
    }
  }
  return null;
};

// Fully silent spawn — captures stdout+stderr, returns combined output.
const trySpawn = (cmd, args) => {
  const r = spawnSync(cmd, args, {
    stdio: ["ignore", "pipe", "pipe"],
    encoding: "utf8",
  });
  return { status: r.status, output: `${r.stdout || ""}${r.stderr || ""}` };
};

console.log(`
${b("QA STLC Agents")} v${pkg.version} — post-install

${d("This npm package includes:")}
  • Six Python MCP servers for Azure DevOps + Jira Cloud (incl. framework migration)
  • Skill files for AI coding agents (Claude Code, Copilot, Cursor, Windsurf)
  • ORCHESTRATION_RULES.md — reference guide for multi-step QA workflows
  • Command-line tools: qa-stlc init, qa-stlc scaffold, qa-stlc skills, etc.
`);

// ── 1. Find Python ───────────────────────────────────────────────────────────
let python = null;
for (const candidate of ["python3", "python"]) {
  const r = spawnSync(candidate, ["--version"], { encoding: "utf8" });
  if (r.status === 0) { python = candidate; break; }
}

// Quick PEP 668 detector — short-circuits plain `pip install` on Homebrew /
// Debian Python so its traceback never reaches the terminal.
const isPep668 = (() => {
  if (!python) return false;
  const r = trySpawn(python, ["-m", "pip", "install", "--dry-run", "pip"]);
  return /externally-managed-environment/i.test(r.output);
})();

// ── 2. Make sure pipx is available (pipx handles PEP 668 cleanly) ────────────
const ensurePipx = () => {
  if (findCommand("pipx")) return true;

  // macOS — prefer brew (matches Homebrew Python's expectations)
  if (process.platform === "darwin" && findCommand("brew")) {
    info("Installing pipx via Homebrew…");
    const r = trySpawn("brew", ["install", "pipx"]);
    if (r.status === 0) {
      trySpawn("pipx", ["ensurepath"]);
      if (findCommand("pipx")) { ok("pipx installed."); return true; }
    }
  }

  // Fallback — pip --user (works on Linux, Windows, and PEP 668 systems with the flag)
  if (python) {
    info("Installing pipx via pip --user…");
    const args = ["-m", "pip", "install", "--user", "--quiet", "pipx"];
    if (isPep668) args.splice(4, 0, "--break-system-packages");
    const r = trySpawn(python, args);
    if (r.status === 0) {
      trySpawn(python, ["-m", "pipx", "ensurepath"]);
      if (findCommand("pipx")) { ok("pipx installed."); return true; }
    }
  }
  return false;
};

// ── 3. Install qa-gentic-stlc-agents ─────────────────────────────────────────
let entryPath = findCommand(ENTRY);
let pipOk     = entryPath !== null;
let viaTag    = null;

if (pipOk) {
  // Already installed — best-effort silent upgrade via pipx if it manages this.
  if (findCommand("pipx")) {
    const list = spawnSync("pipx", ["list", "--short"], { encoding: "utf8" });
    if ((list.stdout || "").includes("qa-gentic-stlc-agents")) {
      spawnSync("pipx", ["upgrade", "qa-gentic-stlc-agents"], { stdio: "ignore" });
      entryPath = findCommand(ENTRY) || entryPath;
    }
  }
  ok("qa-gentic-stlc-agents already installed.");
} else {
  info("Installing qa-gentic-stlc-agents…");

  // Attempt A — pipx (auto-installed above if missing)
  if (ensurePipx()) {
    const r = trySpawn("pipx", ["install", "--force", "--quiet", "qa-gentic-stlc-agents"]);
    if (r.status === 0) { pipOk = true; viaTag = "pipx"; }
  }

  // Attempt B — plain pip (only when NOT a PEP 668 environment)
  if (!pipOk && python && !isPep668) {
    const r = trySpawn(python, ["-m", "pip", "install", "--upgrade", "--quiet", "qa-gentic-stlc-agents"]);
    if (r.status === 0) { pipOk = true; viaTag = "pip"; }
  }

  // Attempt C — pip --user --break-system-packages (PEP 668 fallback)
  if (!pipOk && python) {
    const r = trySpawn(python, [
      "-m", "pip", "install",
      "--user", "--break-system-packages",
      "--upgrade", "--quiet", "qa-gentic-stlc-agents",
    ]);
    if (r.status === 0) { pipOk = true; viaTag = "pip --user"; }
  }

  if (pipOk) {
    ok(`qa-gentic-stlc-agents installed ${d(`(via ${viaTag})`)}`);
    entryPath = findCommand(ENTRY);
  } else {
    warn("Could not auto-install qa-gentic-stlc-agents. Run one of:");
    console.log(`  ${C.cyan}pipx install qa-gentic-stlc-agents${C.reset}                                         ${d("# recommended")}`);
    console.log(`  ${C.cyan}python3 -m pip install --user --break-system-packages qa-gentic-stlc-agents${C.reset}`);
  }
}

// ── 4. Activate cost tracking — only when the package is actually present ────
if (pipOk) {
  info("Activating cost tracking on MCP servers…");
  let costPatch;
  if (entryPath) {
    costPatch = spawnSync(entryPath, [], {
      stdio: ["ignore", "pipe", "pipe"],
      encoding: "utf8",
      shell: process.platform === "win32",
    });
  } else if (findCommand("pipx")) {
    // pipx-installed entry points may not yet be on this process's PATH —
    // `pipx run` resolves them directly from pipx's venv.
    costPatch = spawnSync("pipx", ["run", "--spec", "qa-gentic-stlc-agents", ENTRY], {
      stdio: ["ignore", "pipe", "pipe"],
      encoding: "utf8",
    });
  } else if (python) {
    costPatch = spawnSync(python, ["-m", "stlc_agents.shared.install_hook"], {
      stdio: ["ignore", "pipe", "pipe"],
      encoding: "utf8",
    });
  }

  if (costPatch && costPatch.status === 0) {
    (costPatch.stdout || "").split("\n").filter(Boolean).forEach((l) => console.log(l));
    ok("Cost tracking active — every tool call will log tokens + cost");
  } else {
    // Silent — the patch is opt-in instrumentation and not load-bearing.
    warn(`Cost tracking patch skipped — run later with: ${C.cyan}${ENTRY}${C.reset}`);
  }
}

// ── 5. Next-step instructions ────────────────────────────────────────────────
console.log(formatNextSteps({ version: pkg.version, includeFallbackHint: true }));
