//! Live-target connection plumbing shared by the cassette refresher
//! (`mcptest run --update-cassettes`) and the proxy recorder
//! (`mcptest record`).
//!
//! Both features open the same two kinds of transport from a
//! [`LiveTarget`] (spawn a stdio command, or connect streamable HTTP)
//! and need the same shutdown handle afterwards. Keeping the connect
//! step here means a transport added later (or a connect bugfix) lands
//! in both code paths at once.

use crate::network::ProxyConfig;
use crate::protocol::Transport;
use crate::transport::{StdioConfig, StdioTransport, StreamableHttp, StreamableHttpConfig};

use super::LiveTarget;

/// Open the live transport for a [`LiveTarget`].
///
/// The error is the human-readable connect detail; each caller wraps it
/// in its own typed variant (`UpdateError::Connect`, `ProxyError::Connect`)
/// with its own context attached.
pub(crate) fn connect_live(
    target: LiveTarget,
    proxy: &ProxyConfig,
) -> Result<(Transport, LiveGuard), String> {
    match target {
        LiveTarget::Command(argv) => {
            let cfg = StdioConfig {
                command: argv[0].clone(),
                args: argv[1..].to_vec(),
                ..StdioConfig::default()
            };
            let (transport, handle) = StdioTransport::spawn(cfg).map_err(|e| e.to_string())?;
            Ok((transport, LiveGuard::Stdio(handle)))
        }
        LiveTarget::Url(url) => {
            let cfg = StreamableHttpConfig {
                url,
                proxy: proxy.clone(),
                ..StreamableHttpConfig::default()
            };
            let (transport, handle) = StreamableHttp::connect(cfg).map_err(|e| e.to_string())?;
            Ok((transport, LiveGuard::Http(handle)))
        }
    }
}

/// Transport shutdown handle for a live recording session. Mirrors the
/// connector's `Shutdown` enum but stays crate-private: the refresher and
/// the proxy recorder are the only callers and each owns its whole
/// connect-drive-shutdown lifecycle.
pub(crate) enum LiveGuard {
    /// Spawned stdio child.
    Stdio(StdioTransport),
    /// Streamable HTTP reader tasks.
    Http(StreamableHttp),
}

impl LiveGuard {
    /// Tear the live transport down once the recording is captured.
    pub(crate) async fn shutdown(self) {
        match self {
            LiveGuard::Stdio(handle) => {
                // Best effort: the recording is already captured, and the
                // child dies on drop anyway (kill_on_drop), so a failed
                // graceful shutdown must not fail the caller.
                let _ = handle.shutdown().await;
            }
            LiveGuard::Http(handle) => handle.shutdown().await,
        }
    }
}
