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

/// Message type for agent-to-agent communication
#[derive(Debug, Clone, Serialize, Deserialize)]
pub enum SwarmMessage {
    TaskProposal {
        task_id: String,
        proposed_by: String,
        task_description: String,
        required_capabilities: Vec<String>,
    },
    BidRequest {
        task_id: String,
        task_description: String,
    },
    BidSubmission {
        task_id: String,
        bidder_id: String,
        bid_value: f64,
        estimated_duration_ms: u64,
    },
    TaskAssignment {
        task_id: String,
        assigned_to: String,
        priority: u32,
    },
    ConsensusVote {
        proposal_id: String,
        voter_id: String,
        vote: Vote,
        reasoning: String,
    },
    CoalitionInvite {
        coalition_id: String,
        coordinator_id: String,
        required_roles: Vec<String>,
    },
    CoalitionAccept {
        coalition_id: String,
        agent_id: String,
    },
    StatusUpdate {
        agent_id: String,
        current_load: f64,
        available: bool,
    },
}

/// Vote in consensus mechanism
#[derive(Debug, Clone, Copy, Serialize, Deserialize, PartialEq, Eq)]
pub enum Vote {
    Agree,
    Disagree,
    Abstain,
}

/// Bid for task execution
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Bid {
    pub task_id: String,
    pub bidder_id: String,
    pub bid_value: f64,
    pub estimated_duration_ms: u64,
    pub submitted_at: DateTime<Utc>,
}

/// Coalition of agents working together
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Coalition {
    pub id: String,
    pub coordinator_id: String,
    pub members: Vec<String>,
    pub required_roles: Vec<String>,
    pub status: CoalitionStatus,
    pub created_at: DateTime<Utc>,
}

/// Coalition status
#[derive(Debug, Clone, Copy, Serialize, Deserialize, PartialEq, Eq)]
pub enum CoalitionStatus {
    Forming,
    Active,
    Executing,
    Completed,
    Failed,
}

/// Agent capability profile in swarm
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct AgentProfile {
    pub id: String,
    pub roles: Vec<String>,
    pub capabilities: Vec<String>,
    pub current_load: f64,
    pub success_rate: f64,
    pub availability: bool,
}

impl Bid {
    pub fn new(task_id: String, bidder_id: String, bid_value: f64, duration_ms: u64) -> Self {
        Self {
            task_id,
            bidder_id,
            bid_value,
            estimated_duration_ms: duration_ms,
            submitted_at: Utc::now(),
        }
    }
}

impl Coalition {
    pub fn new(coordinator_id: String, required_roles: Vec<String>) -> Self {
        Self {
            id: format!("coal_{}", uuid::Uuid::new_v4()),
            coordinator_id,
            members: Vec::new(),
            required_roles,
            status: CoalitionStatus::Forming,
            created_at: Utc::now(),
        }
    }
}

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

    #[test]
    fn test_bid_creation() {
        let bid = Bid::new("task-1".to_string(), "agent-1".to_string(), 0.8, 5000);
        assert_eq!(bid.task_id, "task-1");
        assert_eq!(bid.bid_value, 0.8);
    }

    #[test]
    fn test_coalition_creation() {
        let coal = Coalition::new("agent-1".to_string(), vec!["developer".to_string()]);
        assert_eq!(coal.coordinator_id, "agent-1");
        assert_eq!(coal.status, CoalitionStatus::Forming);
    }
}
