//! Agent Card for A2A protocol discovery
//!
//! Implements the .well-known/agent.json discovery endpoint per A2A spec.

use serde::{Deserialize, Serialize};
use std::collections::HashMap;

/// Agent Card for A2A protocol discovery
/// Served at /.well-known/agent.json
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct AgentCard {
    pub name: String,
    pub description: String,
    pub version: String,
    pub protocol_version: String,
    pub capabilities: AgentCapabilities,
    pub endpoints: AgentEndpoints,
    #[serde(skip_serializing_if = "Option::is_none")]
    pub metadata: Option<HashMap<String, serde_json::Value>>,
}

impl AgentCard {
    /// Create a new AgentCard with default Enact configuration
    pub fn new(name: impl Into<String>, description: impl Into<String>) -> Self {
        Self {
            name: name.into(),
            description: description.into(),
            version: env!("CARGO_PKG_VERSION").to_string(),
            protocol_version: "1.0".to_string(),
            capabilities: AgentCapabilities::default(),
            endpoints: AgentEndpoints::default(),
            metadata: None,
        }
    }

    /// Builder: set capabilities
    pub fn with_capabilities(mut self, capabilities: AgentCapabilities) -> Self {
        self.capabilities = capabilities;
        self
    }

    /// Builder: set endpoints
    pub fn with_endpoints(mut self, endpoints: AgentEndpoints) -> Self {
        self.endpoints = endpoints;
        self
    }

    /// Builder: set metadata
    pub fn with_metadata(mut self, metadata: HashMap<String, serde_json::Value>) -> Self {
        self.metadata = Some(metadata);
        self
    }
}

/// Agent capabilities exposed via discovery
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct AgentCapabilities {
    pub streaming: bool,
    pub tools: Vec<String>,
    pub input_types: Vec<String>,
    pub output_types: Vec<String>,
}

impl Default for AgentCapabilities {
    fn default() -> Self {
        Self {
            streaming: true,
            tools: vec![],
            input_types: vec!["text".to_string()],
            output_types: vec!["text".to_string()],
        }
    }
}

/// A2A API endpoints
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct AgentEndpoints {
    pub invoke: String,
    pub stream: String,
    pub status: String,
    pub cancel: String,
}

impl Default for AgentEndpoints {
    fn default() -> Self {
        Self {
            invoke: "/api/a2a/invoke".to_string(),
            stream: "/api/a2a/stream".to_string(),
            status: "/api/a2a/status/{task_id}".to_string(),
            cancel: "/api/a2a/cancel/{task_id}".to_string(),
        }
    }
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn test_agent_card_creation() {
        let card = AgentCard::new("test-agent", "A test agent");
        assert_eq!(card.name, "test-agent");
        assert_eq!(card.protocol_version, "1.0");
        assert!(card.capabilities.streaming);
    }

    #[test]
    fn test_agent_card_serialization() {
        let card = AgentCard::new("test-agent", "A test agent");
        let json = serde_json::to_string(&card).unwrap();
        assert!(json.contains("test-agent"));
        assert!(json.contains("protocol_version"));
    }

    #[test]
    fn test_agent_card_deserialization() {
        let json = r#"{
            "name": "test",
            "description": "Test agent",
            "version": "1.0.0",
            "protocol_version": "1.0",
            "capabilities": {
                "streaming": true,
                "tools": [],
                "input_types": ["text"],
                "output_types": ["text"]
            },
            "endpoints": {
                "invoke": "/api/a2a/invoke",
                "stream": "/api/a2a/stream",
                "status": "/api/a2a/status/{task_id}",
                "cancel": "/api/a2a/cancel/{task_id}"
            }
        }"#;
        let card: AgentCard = serde_json::from_str(json).unwrap();
        assert_eq!(card.name, "test");
    }
}
