//! ACP Client Example
//!
//! Spawns `goose acp` as a child process and sends it a completion request
//! using the Agent Client Protocol over stdio.
//!
//! # Prerequisites
//!
//! You must have goose built and a provider configured (`goose configure`).
//!
//! # Usage
//!
//! ```bash
//! cargo run -p goose-sdk --example acp_client -- "What is 2 + 2?"
//! ```
//!
//! Or with a custom goose binary path:
//!
//! ```bash
//! cargo run -p goose-sdk --example acp_client -- --goose-bin ./target/debug/goose "Explain Rust's ownership model in one sentence"
//! ```

use agent_client_protocol::schema::{
    ContentBlock, InitializeRequest, ProtocolVersion, RequestPermissionOutcome,
    RequestPermissionRequest, RequestPermissionResponse, SelectedPermissionOutcome,
    SessionNotification, SessionUpdate,
};
use agent_client_protocol::{Client, ConnectionTo};
use goose_sdk::custom_requests::GetExtensionsRequest;
use std::path::PathBuf;
use tokio_util::compat::{TokioAsyncReadCompatExt, TokioAsyncWriteCompatExt};

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    // Parse args: [--goose-bin PATH] PROMPT
    let args: Vec<String> = std::env::args().skip(1).collect();
    let (goose_bin, prompt) = parse_args(&args)?;

    eprintln!("🚀 Spawning: {} acp", goose_bin.display());

    let mut child = tokio::process::Command::new(&goose_bin)
        .arg("acp")
        .stdin(std::process::Stdio::piped())
        .stdout(std::process::Stdio::piped())
        .stderr(std::process::Stdio::inherit())
        .spawn()
        .map_err(|e| format!("Failed to spawn '{}': {e}", goose_bin.display()))?;

    let child_stdin = child.stdin.take().expect("stdin should be piped");
    let child_stdout = child.stdout.take().expect("stdout should be piped");

    let transport =
        agent_client_protocol::ByteStreams::new(child_stdin.compat_write(), child_stdout.compat());

    let prompt_clone = prompt.clone();

    Client
        .builder()
        .name("acp-client-example")
        // Print session notifications (agent text, tool calls, etc.)
        .on_receive_notification(
            async move |notification: SessionNotification, _cx| {
                match &notification.update {
                    SessionUpdate::AgentMessageChunk(chunk) => {
                        if let ContentBlock::Text(text) = &chunk.content {
                            print!("{}", text.text);
                        }
                    }
                    SessionUpdate::ToolCall(tool_call) => {
                        eprintln!("🔧 Tool call: {}", tool_call.title);
                    }
                    SessionUpdate::ToolCallUpdate(update) => {
                        if let Some(status) = &update.fields.status {
                            eprintln!("   Tool status: {:?}", status);
                        }
                    }
                    _ => {}
                }
                Ok(())
            },
            agent_client_protocol::on_receive_notification!(),
        )
        // Auto-approve all permission requests
        .on_receive_request(
            async move |request: RequestPermissionRequest, responder, _cx| {
                eprintln!("✅ Auto-approving permission request");
                let option_id = request.options.first().map(|opt| opt.option_id.clone());
                match option_id {
                    Some(id) => responder.respond(RequestPermissionResponse::new(
                        RequestPermissionOutcome::Selected(SelectedPermissionOutcome::new(id)),
                    )),
                    None => responder.respond(RequestPermissionResponse::new(
                        RequestPermissionOutcome::Cancelled,
                    )),
                }
            },
            agent_client_protocol::on_receive_request!(),
        )
        .connect_with(
            transport,
            async move |cx: ConnectionTo<agent_client_protocol::Agent>| {
                // Step 1: Initialize
                eprintln!("🤝 Initializing...");
                let init_response = cx
                    .send_request(InitializeRequest::new(ProtocolVersion::LATEST))
                    .block_task()
                    .await?;
                eprintln!("✓ Agent initialized: {:?}", init_response.agent_info);

                let response = cx
                    .send_request(GetExtensionsRequest {})
                    .block_task()
                    .await?;
                eprintln!("Extensions: {:?}", response.extensions);

                // Step 2: Create a session and send the prompt
                eprintln!("💬 Sending prompt: \"{}\"", prompt_clone);
                cx.build_session_cwd()?
                    .block_task()
                    .run_until(async |mut session| {
                        session.send_prompt(&prompt_clone)?;
                        let response = session.read_to_string().await?;

                        // read_to_string collects text; we already printed chunks above,
                        // so just print a newline to finish.
                        println!();
                        eprintln!("✅ Done ({} chars)", response.len());
                        Ok(())
                    })
                    .await
            },
        )
        .await?;

    let _ = child.kill().await;
    Ok(())
}

fn parse_args(args: &[String]) -> Result<(PathBuf, String), String> {
    let mut goose_bin = PathBuf::from("goose");
    let mut i = 0;

    while i < args.len() {
        match args[i].as_str() {
            "--goose-bin" => {
                i += 1;
                goose_bin = PathBuf::from(args.get(i).ok_or("--goose-bin requires a value")?);
            }
            _ => break,
        }
        i += 1;
    }

    let prompt = args[i..].join(" ");

    if prompt.is_empty() {
        return Err("Usage: acp_client [--goose-bin PATH] PROMPT".into());
    }

    Ok((goose_bin, prompt))
}
