use chrono::{DateTime, Utc};
use serde::{Deserialize, Serialize};
use uuid::Uuid;

use crate::agent::AgentId;

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Message {
    pub id: Uuid,
    pub kind: MessageKind,
    pub from: AgentId,
    pub to: Option<AgentId>,
    pub content: String,
    pub tool_calls: Vec<ToolCall>,
    pub tool_results: Vec<ToolResult>,
    pub metadata: serde_json::Value,
    pub timestamp: DateTime<Utc>,
}

#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
#[serde(rename_all = "snake_case")]
pub enum MessageKind {
    User,
    Assistant,
    System,
    ToolUse,
    ToolResult,
    AgentToAgent,
    Broadcast,
}

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ToolCall {
    pub id: String,
    pub name: String,
    pub arguments: serde_json::Value,
}

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ToolResult {
    pub tool_call_id: String,
    pub content: String,
    pub is_error: bool,
}

impl Message {
    pub fn user(from: AgentId, content: impl Into<String>) -> Self {
        Self {
            id: Uuid::new_v4(),
            kind: MessageKind::User,
            from,
            to: None,
            content: content.into(),
            tool_calls: vec![],
            tool_results: vec![],
            metadata: serde_json::Value::Null,
            timestamp: Utc::now(),
        }
    }

    pub fn assistant(from: AgentId, content: impl Into<String>) -> Self {
        Self {
            id: Uuid::new_v4(),
            kind: MessageKind::Assistant,
            from,
            to: None,
            content: content.into(),
            tool_calls: vec![],
            tool_results: vec![],
            metadata: serde_json::Value::Null,
            timestamp: Utc::now(),
        }
    }

    pub fn system(content: impl Into<String>) -> Self {
        Self {
            id: Uuid::new_v4(),
            kind: MessageKind::System,
            from: AgentId::system(),
            to: None,
            content: content.into(),
            tool_calls: vec![],
            tool_results: vec![],
            metadata: serde_json::Value::Null,
            timestamp: Utc::now(),
        }
    }

    pub fn agent_to_agent(
        from: AgentId,
        to: AgentId,
        content: impl Into<String>,
    ) -> Self {
        Self {
            id: Uuid::new_v4(),
            kind: MessageKind::AgentToAgent,
            from,
            to: Some(to),
            content: content.into(),
            tool_calls: vec![],
            tool_results: vec![],
            metadata: serde_json::Value::Null,
            timestamp: Utc::now(),
        }
    }
}
