use crate::error::{AppError, Result};
use crate::transport::CustomHttpClient;
use rmcp::{ClientHandler, ServiceExt};
use rmcp::model::CallToolRequestParam;
use rmcp::transport::StreamableHttpClientTransport;
use rmcp::transport::streamable_http_client::StreamableHttpClientTransportConfig;
use serde_json::{Map, Value};

#[derive(Debug, Clone, Default)]
struct DummyClientHandler;

impl ClientHandler for DummyClientHandler {
    fn get_info(&self) -> rmcp::model::ClientInfo {
        rmcp::model::ClientInfo::default()
    }
}

// 不需要 Clone，由外部用 Arc 包裹
pub struct AvClient {
    service: rmcp::service::RunningService<rmcp::RoleClient, DummyClientHandler>,
}

impl AvClient {
    pub async fn connect(mcp_endpoint_url: &str) -> Result<Self> {
        let config = StreamableHttpClientTransportConfig::with_uri(mcp_endpoint_url.to_string());
        let transport = StreamableHttpClientTransport::with_client(CustomHttpClient::new(), config);
        let running = DummyClientHandler
            ::default()
            .serve(transport)
            .await
            .map_err(|e| AppError::Configuration(format!("Fail to init MCP service: {e:?}")))?;
        Ok(Self { service: running })
    }

    pub async fn query(&self, function: &str, params: &[(&str, &str)]) -> Result<Value> {
        let mut args = Map::new();
        for (k, v) in params {
            args.insert((*k).to_string(), Value::String((*v).to_string()));
        }
        let result = self
            .service
            .call_tool(CallToolRequestParam {
                name: function.to_string().into(),
                arguments: Some(args),
            })
            .await
            .map_err(|e| AppError::Configuration(format!("MCP call_tool error: {e:?}")))?;
        if let Some(v) = result.structured_content {
            return Ok(v);
        }
        // fallback: try parse first text content as json
        if let Some(text) = result.content.first().and_then(|c| c.raw.as_text()).map(|t| t.text.clone()) {
            if let Ok(v) = serde_json::from_str::<Value>(&text) {
                return Ok(v);
            }
            return Ok(Value::String(text));
        }
        Ok(Value::Null)
    }

    pub async fn list_tools(&self) -> Result<Vec<rmcp::model::Tool>> {
        let result = self.service.list_tools(None).await
            .map_err(|e| AppError::Configuration(format!("MCP list_tools error: {e:?}")))?;
        Ok(result.tools)
    }
}


