//! Handler for `mcptest mcp-server`.
//!
//! Wraps the `mcptest-mcp-server` library's stdio loop so users only
//! install one CLI binary. Agent configs reference
//! `command: "mcptest"`, `args: ["mcp-server", "--workspace", "."]`.

use std::io::{stdin, stdout, BufReader};

use anyhow::{Context, Result};
use mcptest_core::discovery::clients::install::{register_mcptest, InstallSpec};
use mcptest_mcp_server::{workspace::Workspace, Capabilities, Server};

use crate::cli::args::McpServerArgs;

/// Drive the stdio MCP server. Blocks on the JSON-RPC loop until the
/// agent closes stdin or sends `shutdown`.
pub(crate) fn mcp_server_command(args: McpServerArgs) -> Result<i32> {
    let root = match &args.workspace {
        Some(p) => p.clone(),
        None => std::env::current_dir().context("failed to read current directory")?,
    };
    if args.install {
        return install_registration(&args, &root);
    }
    let workspace = Workspace::from_root(&root);
    let capabilities = Capabilities {
        enable_writes: args.enable_writes,
        binary_override: args.mcptest_bin,
    };
    tracing::info!(
        ?root,
        enable_writes = args.enable_writes,
        "mcptest mcp-server starting"
    );
    let server = Server::new(workspace, capabilities);
    server.serve(BufReader::new(stdin()), stdout())?;
    Ok(0)
}

/// Write the mcptest registration into an agent config and report where it
/// landed. The default target is `.claude/mcp.json` under the workspace, the
/// project-local Claude Code config the discovery walk already reads.
fn install_registration(args: &McpServerArgs, root: &std::path::Path) -> Result<i32> {
    let path = match &args.install_path {
        Some(p) => p.clone(),
        None => root.join(".claude").join("mcp.json"),
    };
    // Register the absolute path to this binary so the agent launches the same
    // mcptest the user just ran, regardless of PATH.
    let binary = std::env::current_exe()
        .map(|p| p.to_string_lossy().into_owned())
        .unwrap_or_else(|_| "mcptest".to_string());
    let spec = InstallSpec::for_mcp_server(binary, args.enable_writes);
    let outcome = register_mcptest(&path, &spec)
        .with_context(|| format!("failed to register mcptest in {}", path.display()))?;
    let verb = match outcome {
        mcptest_core::discovery::clients::install::InstallOutcome::Added => "registered",
        mcptest_core::discovery::clients::install::InstallOutcome::Replaced => "updated",
    };
    println!(
        "mcptest {verb} as an MCP server in {} ({}writes).\nRestart your agent to pick it up.",
        path.display(),
        if args.enable_writes {
            "with "
        } else {
            "read-only, no "
        },
    );
    Ok(0)
}
