//! Bridge command — relay messages between Brain and an external gateway.

pub(crate) async fn cmd_bridge(
    config: &brain_core::BrainConfig,
    gateway_url: &str,
    api_key: Option<&str>,
) -> anyhow::Result<()> {
    use bridge::{BridgeClient, BridgeConfig, BridgeMessage};
    use futures_util::{SinkExt, StreamExt};
    use tokio_tungstenite::tungstenite::Message;

    let api_key = api_key
        .map(String::from)
        .or_else(|| config.access.api_keys.first().map(|k| k.key.clone()))
        .ok_or_else(|| anyhow::anyhow!("No API key configured. Add one in ~/.brain/config.yaml"))?;

    let brain_ws_url = format!(
        "ws://{}:{}",
        config.adapters.http.host, config.adapters.ws.port
    );

    println!("Brain Bridge");
    println!("  → Brain:   {}", brain_ws_url);
    println!("  → Gateway: {}", gateway_url);
    println!();

    let bridge_client = BridgeClient::new(gateway_url, BridgeConfig::default());

    bridge_client
        .connect_and_relay(move |msg: BridgeMessage| {
            let brain_ws_url = brain_ws_url.clone();
            let api_key = api_key.clone();
            async move {
                let ws = match tokio_tungstenite::connect_async(&brain_ws_url).await {
                    Ok((ws, _)) => ws,
                    Err(e) => {
                        tracing::error!("Bridge connect failed: {}", e);
                        return BridgeMessage::reply(&msg, "Bridge connection failed");
                    }
                };

                let (mut sink, mut stream) = ws.split();

                // Phase 1: Send auth frame first, await acknowledgment
                let auth_frame = serde_json::json!({
                    "api_key": api_key,
                });
                if let Err(e) = sink
                    .send(Message::Text(auth_frame.to_string().into()))
                    .await
                {
                    tracing::error!("Bridge auth send failed: {}", e);
                    return BridgeMessage::reply(&msg, "Bridge auth failed");
                }

                // Wait for auth acknowledgment
                let auth_response = match stream.next().await {
                    Some(Ok(response)) => response,
                    Some(Err(e)) => {
                        tracing::error!("Bridge auth stream error: {}", e);
                        return BridgeMessage::reply(&msg, "Bridge auth failed");
                    }
                    None => return BridgeMessage::reply(&msg, "No auth response from Brain"),
                };

                let auth_text = match auth_response {
                    Message::Text(t) => t.to_string(),
                    _ => "{}".to_string(),
                };

                let auth_json: serde_json::Value =
                    serde_json::from_str(&auth_text).unwrap_or_default();

                if auth_json.get("status").and_then(|s| s.as_str()) != Some("authenticated") {
                    let error = auth_json
                        .get("message")
                        .and_then(|m| m.as_str())
                        .unwrap_or("Authentication failed");
                    return BridgeMessage::reply(&msg, format!("Bridge auth error: {error}"));
                }

                // Phase 2: Send signal frame after successful auth
                let signal = serde_json::json!({
                    "content": msg.content,
                    "source": msg.source.clone().unwrap_or_else(|| "bridge".to_string()),
                    "metadata": msg.metadata.clone(),
                });

                if let Err(e) = sink.send(Message::Text(signal.to_string().into())).await {
                    tracing::error!("Bridge signal send failed: {}", e);
                    return BridgeMessage::reply(&msg, "Bridge send failed");
                };

                let response = match stream.next().await {
                    Some(Ok(response)) => response,
                    Some(Err(e)) => {
                        tracing::error!("Bridge stream error: {}", e);
                        return BridgeMessage::reply(&msg, "Bridge stream error");
                    }
                    None => return BridgeMessage::reply(&msg, "No response from Brain"),
                };

                let response_text = match response {
                    Message::Text(t) => t.to_string(),
                    _ => "{}".to_string(),
                };

                let response_json: serde_json::Value =
                    serde_json::from_str(&response_text).unwrap_or_default();

                let content = response_json
                    .get("response")
                    .and_then(|r| r.as_str())
                    .unwrap_or("Bridge: parse error");

                BridgeMessage::reply(&msg, content)
            }
        })
        .await?;

    Ok(())
}
