//! Integration tests for `mcptest discover <server>`.
//!
//! The MCP streamable HTTP transport is end-to-end exercised in
//! `mcptest-core`; here we focus on the CLI surface and on the scaffolded
//! YAML format. A wiremock-backed probe stands up an HTTP endpoint that
//! responds with a JSON-RPC error, which the discover command interprets
//! as "no tools advertised" rather than a hard failure.

use assert_cmd::Command;
use predicates::prelude::*;
use tempfile::tempdir;
use wiremock::matchers::method;
use wiremock::{Mock, MockServer, ResponseTemplate};

fn mcptest() -> Command {
    Command::cargo_bin("mcptest").expect("binary builds")
}

#[tokio::test(flavor = "current_thread")]
async fn discover_against_unreachable_server_exits_one() {
    // Pick a port nothing is listening on. wiremock's MockServer hands us a
    // free port we can grab and immediately drop so the listener is gone by
    // the time the binary runs.
    let server = MockServer::start().await;
    let url = server.uri();
    drop(server);

    let dir = tempdir().unwrap();
    let out = dir.path().join("tests.yaml");
    mcptest()
        .args(["discover", &url, "--output", out.to_str().unwrap()])
        .assert()
        .code(1);
}

#[tokio::test(flavor = "current_thread")]
async fn discover_writes_servers_block_when_initialize_fails() {
    // Stand up a wiremock that 500s every request. The discover probe will
    // fail its handshake and exit 1, but the test pins that the CLI surface
    // routes the URL through (path-parsing, --output) without panic.
    let server = MockServer::start().await;
    Mock::given(method("POST"))
        .respond_with(ResponseTemplate::new(500))
        .mount(&server)
        .await;
    let url = server.uri();

    let dir = tempdir().unwrap();
    let out = dir.path().join("tests.yaml");
    mcptest()
        .args(["discover", &url, "--output", out.to_str().unwrap()])
        .assert()
        // The probe fails the handshake against a 500-returning server, so
        // we expect a non-zero exit. The CLI prints the error to stderr.
        .failure()
        .stderr(predicate::str::contains("mcptest discover"));
}

#[test]
fn discover_help_lists_output_and_bearer_token_env() {
    let assertion = mcptest().args(["discover", "--help"]).assert().success();
    let stdout = String::from_utf8(assertion.get_output().stdout.clone()).unwrap();
    assert!(
        stdout.contains("--output"),
        "expected --output flag in help"
    );
    assert!(
        stdout.contains("--bearer-token-env"),
        "expected --bearer-token-env flag in help"
    );
}

#[test]
fn discover_help_lists_graph_flag() {
    let assertion = mcptest().args(["discover", "--help"]).assert().success();
    let stdout = String::from_utf8(assertion.get_output().stdout.clone()).unwrap();
    assert!(stdout.contains("--graph"), "expected --graph flag in help");
}

#[tokio::test(flavor = "current_thread")]
async fn discover_graph_against_unreachable_server_exits_one() {
    // The --graph flag must parse and route through the probe path; an
    // unreachable endpoint still exits 1 (the probe fails before any graph
    // render). This pins the CLI surface without needing a live catalog.
    let server = MockServer::start().await;
    let url = server.uri();
    drop(server);

    mcptest()
        .args(["discover", &url, "--graph"])
        .assert()
        .code(1);
}
