//! stdout is the ACP JSON-RPC channel — any stray byte there corrupts the
//! stream. This drives the built binary with a canned `initialize` +
//! `session/new` exchange (no server needed) and asserts every stdout line is a
//! well-formed JSON-RPC message, while logs land only on stderr.

use std::io::{BufRead, BufReader, Write};
use std::process::{Command, Stdio};

#[test]
fn stdout_is_pure_jsonrpc() {
    let mut child = Command::new(env!("CARGO_BIN_EXE_hagent-acp"))
        .args(["--no-bootstrap", "--no-log-conversations"])
        .stdin(Stdio::piped())
        .stdout(Stdio::piped())
        .stderr(Stdio::piped())
        .spawn()
        .expect("spawn hagent-acp");

    let mut stdin = child.stdin.take().unwrap();
    let requests = concat!(
        r#"{"jsonrpc":"2.0","id":1,"method":"initialize","params":{"protocolVersion":1,"clientCapabilities":{}}}"#,
        "\n",
        r#"{"jsonrpc":"2.0","id":2,"method":"session/new","params":{"cwd":"/tmp","mcpServers":[]}}"#,
        "\n",
    );
    stdin.write_all(requests.as_bytes()).unwrap();
    stdin.flush().unwrap();

    // Read the two responses, validating each stdout line is JSON-RPC. The agent
    // keeps running after stdin (its stdin reader doesn't observe our EOF), so we
    // stop once both responses are in and then kill it.
    let stdout = child.stdout.take().unwrap();
    let mut reader = BufReader::new(stdout);
    let mut ids = Vec::new();
    let mut line = String::new();
    while ids.len() < 2 {
        line.clear();
        let n = reader.read_line(&mut line).expect("read stdout");
        if n == 0 {
            break; // EOF — agent exited early
        }
        let trimmed = line.trim();
        if trimmed.is_empty() {
            continue;
        }
        let value: serde_json::Value = serde_json::from_str(trimmed)
            .unwrap_or_else(|e| panic!("non-JSON-RPC line on stdout: {trimmed:?} ({e})"));
        assert_eq!(
            value["jsonrpc"], "2.0",
            "missing jsonrpc version: {trimmed}"
        );
        if let Some(id) = value.get("id").and_then(serde_json::Value::as_u64) {
            ids.push(id);
        }
    }

    let _ = child.kill();
    let _ = child.wait();

    assert!(
        ids.contains(&1) && ids.contains(&2),
        "expected JSON-RPC responses to ids 1 and 2, got {ids:?}"
    );
}
