// packages/plugin-awf/src/commands/hsa.ts
// AWF HSA Command - Manage HSA MCP server (npx-based, replaces Python daemon)
import { execSync, spawn } from "node:child_process";
import path from "node:path";
import { existsSync, readdirSync } from "node:fs";
import pc from "picocolors";
import * as prompts from "@clack/prompts";
import { HSA_PORT, EXEC_TIMEOUT } from "../constants.js";
import { getMCPServerCommand } from "./mcp-registry.js";
import { validatePort } from "../utils/port-validator.js";
export const hsaFlags = {
    verbose: {
        type: "boolean",
        description: "Show verbose output",
        alias: "V",
        default: false,
    },
};
export async function hsaCommand(args, flags) {
    const [subcommand] = args;
    const verbose = flags.verbose;
    switch (subcommand) {
        case "start":
            await startHSA(verbose);
            break;
        case "stop":
            await stopHSA();
            break;
        case "status":
            await statusHSA();
            break;
        case "restart":
            await stopHSA();
            await startHSA(verbose);
            break;
        case "install":
            await installHSA();
            break;
        case undefined:
        case "help":
            showHSAHelp();
            break;
        default:
            console.log(pc.yellow(`Unknown subcommand: ${subcommand}`));
            showHSAHelp();
    }
}
async function startHSA(verbose) {
    const spinner = prompts.spinner();
    spinner.start("Starting HSA MCP server...");
    // Check if already running
    if (await isHSARunning()) {
        spinner.stop(pc.yellow("HSA is already running"));
        return;
    }
    try {
        // Start HSA via npx — cli.ts detects PORT/HSA_DAEMON_MODE and auto-switches to HTTP
        const { command, args } = getMCPServerCommand();
        // Detect workspace root (traverse up from CWD to find .git, rush.json, etc.)
        const projectRoot = findWorkspaceRoot(process.cwd());
        const child = spawn(command, args, {
            detached: true,
            stdio: verbose ? "inherit" : "ignore",
            env: {
                ...process.env,
                HSA_PROJECT_PATH: projectRoot,
                PORT: HSA_PORT.toString(),
                HSA_DAEMON_PORT: HSA_PORT.toString(),
                HSA_DAEMON_MODE: "true", // Triggers HTTP mode in cli.ts
            },
            shell: true,
        });
        child.unref();
        // Health-check retry loop (max 10 retries × 500ms = 5s)
        let healthy = false;
        for (let i = 0; i < 10; i++) {
            await new Promise((resolve) => setTimeout(resolve, 500));
            if (await isHSARunning()) {
                healthy = true;
                break;
            }
        }
        if (healthy) {
            spinner.stop(pc.green(`HSA MCP server started on port ${HSA_PORT}`));
            if (projectRoot !== process.cwd()) {
                console.log(pc.dim(`  Workspace root: ${projectRoot}`));
            }
        }
        else {
            spinner.stop(pc.yellow("HSA may not have started correctly"));
            console.log(pc.dim("  Try: npx -y @nockdev/hsa@latest"));
        }
    }
    catch (error) {
        spinner.stop(pc.red("Failed to start HSA"));
        console.error(pc.dim(error.message));
    }
}
/**
 * Find workspace root by traversing up from startDir.
 * Looks for VCS markers (.git), monorepo tools (rush.json, nx.json, etc.),
 * and IDE workspace files (*.sln, *.code-workspace).
 */
function findWorkspaceRoot(startDir) {
    const MARKERS = [
        ".git",
        "rush.json",
        "nx.json",
        "turbo.json",
        "lerna.json",
        "pnpm-workspace.yaml",
        ".domyh", // HSA's own marker (breadcrumb from previous runs)
        "deno.json", // Deno workspaces
        "Cargo.toml", // Rust workspaces
    ];
    let current = startDir;
    const root = path.parse(current).root;
    let depth = 0;
    const MAX_DEPTH = 10;
    while (current !== root && depth < MAX_DEPTH) {
        // Check marker files/dirs
        for (const marker of MARKERS) {
            if (existsSync(path.join(current, marker))) {
                return current;
            }
        }
        // Check glob patterns (*.sln, *.code-workspace)
        try {
            const entries = readdirSync(current);
            if (entries.some((e) => e.endsWith(".sln") || e.endsWith(".slnx") || e.endsWith(".code-workspace"))) {
                return current;
            }
        }
        catch (err) {
            // Permission denied — skip this directory level
            if (err.code !== "EACCES") {
                break; // Unexpected error — stop traversal
            }
        }
        current = path.dirname(current);
        depth++;
    }
    return startDir; // fallback: no workspace root found
}
async function stopHSA() {
    const spinner = prompts.spinner();
    spinner.start("Stopping HSA server...");
    try {
        // Validate port before use (security) - Issue #2 fix
        const port = validatePort(HSA_PORT);
        // Strategy 1: Graceful HTTP shutdown (preferred)
        let stopped = false;
        try {
            const res = await fetch(`http://localhost:${port}/shutdown`, {
                method: "POST",
                signal: AbortSignal.timeout(3000),
            });
            if (res.ok) {
                stopped = true;
            }
        }
        catch {
            // Server may not support /shutdown — fall back to process kill
        }
        // Strategy 2: Process kill via port (fallback)
        if (!stopped) {
            if (process.platform === "win32") {
                execSync(`for /f "tokens=5" %a in ('netstat -aon ^| find ":${port}"') do @taskkill /F /PID %a 2>nul`, {
                    shell: "cmd.exe",
                    stdio: "ignore",
                    timeout: EXEC_TIMEOUT,
                });
            }
            else {
                execSync(`lsof -ti:${port} | xargs kill -9 2>/dev/null || true`, {
                    stdio: "ignore",
                    shell: "/bin/sh",
                    timeout: EXEC_TIMEOUT,
                });
            }
        }
        // Verify it's actually stopped
        await new Promise((resolve) => setTimeout(resolve, 500));
        const stillRunning = await isHSARunning();
        if (!stillRunning) {
            spinner.stop(pc.green("HSA stopped"));
        }
        else {
            spinner.stop(pc.yellow("HSA may still be running"));
        }
    }
    catch {
        spinner.stop(pc.dim("HSA was not running"));
    }
}
async function statusHSA() {
    console.log(pc.bold("\n🧠 HSA Status"));
    console.log(pc.gray("─".repeat(40)));
    const running = await isHSARunning();
    console.log(`  Server: ${running ? pc.green("Running") : pc.yellow("Stopped")}`);
    console.log(`  Port: ${pc.cyan(HSA_PORT.toString())}`);
    console.log(`  Engine: ${pc.cyan("TypeScript (npx @nockdev/hsa)")}`);
    // Get version from npm
    try {
        const version = execSync("npm view @nockdev/hsa version", {
            encoding: "utf-8",
            timeout: EXEC_TIMEOUT,
            stdio: ["pipe", "pipe", "pipe"],
        }).trim();
        console.log(`  Version: ${pc.cyan(version || "latest")}`);
    }
    catch {
        console.log(`  Version: ${pc.cyan("latest")}`);
    }
    console.log();
}
async function installHSA() {
    const spinner = prompts.spinner();
    spinner.start("Verifying HSA MCP server...");
    try {
        // Check Node.js
        try {
            const nodeVersion = execSync("node --version", { encoding: "utf-8", timeout: EXEC_TIMEOUT }).trim();
            const major = parseInt(nodeVersion.replace("v", ""), 10);
            if (major < 18) {
                spinner.stop(pc.red(`Node.js ${nodeVersion} too old (need >=18)`));
                return;
            }
        }
        catch {
            spinner.stop(pc.red("Node.js not found"));
            console.log(pc.dim("Install Node.js 18+ first"));
            return;
        }
        // Pre-cache the npx package
        execSync("npx -y @nockdev/hsa@latest --version", {
            stdio: "pipe",
            timeout: 60000,
        });
        spinner.stop(pc.green("✔ HSA MCP server ready (npx @nockdev/hsa)"));
        console.log(pc.dim("  No Python required — runs via Node.js"));
    }
    catch (error) {
        spinner.stop(pc.red("Failed to verify HSA"));
        console.error(pc.dim(error.message));
    }
}
function showHSAHelp() {
    console.log(`
${pc.bold(pc.cyan("HSA - Hierarchical Semantic Analysis"))}
AI-powered context management via MCP (npx @nockdev/hsa)

${pc.bold("Commands:")}
  ${pc.green("start")}     Start HSA MCP server
  ${pc.green("stop")}      Stop HSA server
  ${pc.green("status")}    Show HSA status
  ${pc.green("restart")}   Restart HSA server
  ${pc.green("install")}   Verify/pre-cache HSA package

${pc.bold("Examples:")}
  nock awf hsa start
  nock awf hsa status
  nock awf hsa stop
`);
}
async function isHSARunning() {
    // HTTP health check only — no fallback to avoid false positives
    try {
        const port = validatePort(HSA_PORT);
        const response = await fetch(`http://localhost:${port}/health`, {
            signal: AbortSignal.timeout(1000),
        });
        return response.ok;
    }
    catch {
        return false;
    }
}
