//! Agent bridge for VAPORA multi-agent orchestration
//!
//! Allows lifecycle manager to work with VAPORA agents for distributed task execution.

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

/// Agent roles supported by VAPORA
#[derive(Debug, Clone, Copy, Eq, PartialEq, Hash, Serialize, Deserialize)]
pub enum AgentRole {
    /// Architect - system design
    Architect,
    /// Developer - code implementation
    Developer,
    /// Code reviewer - quality assurance
    CodeReviewer,
    /// Tester - testing and validation
    Tester,
    /// Documenter - documentation
    Documenter,
    /// Marketer - marketing content
    Marketer,
    /// Presenter - presentations
    Presenter,
    /// DevOps - deployment and infrastructure
    DevOps,
    /// Monitor - health monitoring
    Monitor,
    /// Security - security audits
    Security,
    /// Project Manager - tracking and management
    ProjectManager,
    /// Decision Maker - conflict resolution
    DecisionMaker,
}

impl AgentRole {
    /// Get role name
    pub fn name(&self) -> &'static str {
        match self {
            Self::Architect => "architect",
            Self::Developer => "developer",
            Self::CodeReviewer => "code_reviewer",
            Self::Tester => "tester",
            Self::Documenter => "documenter",
            Self::Marketer => "marketer",
            Self::Presenter => "presenter",
            Self::DevOps => "devops",
            Self::Monitor => "monitor",
            Self::Security => "security",
            Self::ProjectManager => "project_manager",
            Self::DecisionMaker => "decision_maker",
        }
    }

    /// Get role description
    pub fn description(&self) -> &'static str {
        match self {
            Self::Architect => "System design and architecture",
            Self::Developer => "Code implementation",
            Self::CodeReviewer => "Code quality assurance",
            Self::Tester => "Testing and validation",
            Self::Documenter => "Documentation and guides",
            Self::Marketer => "Marketing and promotion",
            Self::Presenter => "Presentations and slides",
            Self::DevOps => "Deployment and infrastructure",
            Self::Monitor => "Health and performance monitoring",
            Self::Security => "Security assessment and hardening",
            Self::ProjectManager => "Project tracking and management",
            Self::DecisionMaker => "Conflict resolution and decisions",
        }
    }
}

/// Task for an agent
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct AgentTask {
    /// Task ID
    pub id: String,
    /// Task title
    pub title: String,
    /// Task description
    pub description: String,
    /// Target agent role
    pub agent_role: String,
    /// Task priority (1-5)
    pub priority: u32,
    /// Task context/input
    pub context: HashMap<String, String>,
    /// Task output
    #[serde(skip_serializing_if = "Option::is_none")]
    pub output: Option<String>,
    /// Task status
    pub status: TaskStatus,
}

/// Task status
#[derive(Debug, Clone, Copy, Eq, PartialEq, Serialize, Deserialize)]
pub enum TaskStatus {
    /// Pending execution
    Pending,
    /// Currently executing
    Running,
    /// Successfully completed
    Completed,
    /// Failed execution
    Failed,
    /// Task blocked or cancelled
    Cancelled,
}

impl TaskStatus {
    /// Get status name
    pub fn name(&self) -> &'static str {
        match self {
            Self::Pending => "pending",
            Self::Running => "running",
            Self::Completed => "completed",
            Self::Failed => "failed",
            Self::Cancelled => "cancelled",
        }
    }
}

/// Agent bridge for task coordination
#[derive(Debug, Clone)]
pub struct AgentBridge {
    /// API URL for VAPORA agent service
    #[allow(dead_code)]
    api_url: String,
}

impl AgentBridge {
    /// Create a new agent bridge
    pub fn new(api_url: impl Into<String>) -> Self {
        Self {
            api_url: api_url.into(),
        }
    }

    /// Submit task to agent
    pub async fn submit_task(&self, task: &AgentTask) -> anyhow::Result<String> {
        // In production, this would call VAPORA API to submit task
        // The VAPORA agent pool would pick up the task based on role
        Ok(task.id.clone())
    }

    /// Get task status
    pub async fn get_task_status(&self, _task_id: &str) -> anyhow::Result<TaskStatus> {
        // In production, call VAPORA API for task status
        Ok(TaskStatus::Pending)
    }

    /// Get task result
    pub async fn get_task_result(&self, _task_id: &str) -> anyhow::Result<String> {
        // In production, call VAPORA API for task result
        Ok(String::new())
    }

    /// List available agents
    pub async fn list_agents(&self) -> anyhow::Result<Vec<AgentInfo>> {
        let agents = vec![
            AgentInfo {
                role: "architect".to_string(),
                description: AgentRole::Architect.description().to_string(),
                available: true,
                current_tasks: 0,
                max_capacity: 5,
            },
            AgentInfo {
                role: "developer".to_string(),
                description: AgentRole::Developer.description().to_string(),
                available: true,
                current_tasks: 2,
                max_capacity: 10,
            },
            AgentInfo {
                role: "security".to_string(),
                description: AgentRole::Security.description().to_string(),
                available: true,
                current_tasks: 0,
                max_capacity: 3,
            },
        ];
        Ok(agents)
    }

    /// Execute task synchronously
    pub async fn execute_task(&self, task: &AgentTask) -> anyhow::Result<String> {
        self.submit_task(task).await?;

        // Poll for completion
        for _ in 0..30 {
            let status = self.get_task_status(&task.id).await?;
            if status == TaskStatus::Completed {
                return self.get_task_result(&task.id).await;
            }
            tokio::time::sleep(tokio::time::Duration::from_secs(1)).await;
        }

        Err(anyhow::anyhow!("Task execution timeout"))
    }

    /// Delegate phase transition to agents
    pub async fn delegate_phase_transition(
        &self,
        project_id: &str,
        from_phase: &str,
        to_phase: &str,
    ) -> anyhow::Result<()> {
        // Create tasks for relevant agents based on phase transition
        let _task = AgentTask {
            id: uuid::Uuid::new_v4().to_string(),
            title: format!("Phase transition: {} -> {}", from_phase, to_phase),
            description: format!("Execute transition for project {}", project_id),
            agent_role: "project_manager".to_string(),
            priority: 4,
            context: {
                let mut ctx = HashMap::new();
                ctx.insert("project_id".to_string(), project_id.to_string());
                ctx.insert("from_phase".to_string(), from_phase.to_string());
                ctx.insert("to_phase".to_string(), to_phase.to_string());
                ctx
            },
            output: None,
            status: TaskStatus::Pending,
        };

        Ok(())
    }
}

/// Agent information
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct AgentInfo {
    /// Agent role
    pub role: String,
    /// Agent description
    pub description: String,
    /// Whether agent is available
    pub available: bool,
    /// Current task count
    pub current_tasks: usize,
    /// Maximum capacity
    pub max_capacity: usize,
}

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

    #[test]
    fn test_agent_role_names() {
        assert_eq!(AgentRole::Architect.name(), "architect");
        assert_eq!(AgentRole::Developer.name(), "developer");
        assert_eq!(AgentRole::Security.name(), "security");
    }

    #[test]
    fn test_agent_role_descriptions() {
        assert!(!AgentRole::Architect.description().is_empty());
        assert!(!AgentRole::Developer.description().is_empty());
    }

    #[test]
    fn test_task_status_names() {
        assert_eq!(TaskStatus::Pending.name(), "pending");
        assert_eq!(TaskStatus::Running.name(), "running");
        assert_eq!(TaskStatus::Completed.name(), "completed");
    }

    #[test]
    fn test_agent_task_creation() {
        let task = AgentTask {
            id: "task1".to_string(),
            title: "Test Task".to_string(),
            description: "Test description".to_string(),
            agent_role: "developer".to_string(),
            priority: 3,
            context: HashMap::new(),
            output: None,
            status: TaskStatus::Pending,
        };

        assert_eq!(task.title, "Test Task");
        assert_eq!(task.status, TaskStatus::Pending);
    }

    #[test]
    fn test_agent_bridge_creation() {
        let bridge = AgentBridge::new("http://localhost:8000");
        assert_eq!(bridge.api_url, "http://localhost:8000");
    }

    #[tokio::test]
    async fn test_list_agents() {
        let bridge = AgentBridge::new("http://localhost:8000");
        let agents = bridge.list_agents().await.unwrap();
        assert!(!agents.is_empty());
        assert!(agents.iter().any(|a| a.role == "architect"));
    }

    #[test]
    fn test_agent_info() {
        let info = AgentInfo {
            role: "developer".to_string(),
            description: "Code implementation".to_string(),
            available: true,
            current_tasks: 2,
            max_capacity: 10,
        };

        assert!(info.available);
        assert_eq!(info.current_tasks, 2);
    }
}
