// Profile adapter: AgentMetadata + KG metrics → Swarm AgentProfile

use vapora_swarm::messages::AgentProfile;

use crate::learning_profile::{LearningProfile, TaskTypeExpertise};
use crate::registry::AgentMetadata;

/// Adapter that converts AgentMetadata to SwarmCoordinator AgentProfile
pub struct ProfileAdapter;

impl ProfileAdapter {
    /// Create a swarm profile from agent metadata
    pub fn create_profile(agent: &AgentMetadata) -> AgentProfile {
        // Extract roles from capabilities (simplistic mapping)
        let roles = agent.capabilities.iter().take(1).cloned().collect();

        AgentProfile {
            id: agent.id.clone(),
            roles,
            capabilities: agent.capabilities.clone(),
            current_load: agent.current_tasks as f64 / agent.max_concurrent_tasks as f64,
            success_rate: 0.5, // Default: neutral until KG metrics available
            availability: agent.status == crate::registry::AgentStatus::Active,
        }
    }

    /// Create profiles for multiple agents
    pub fn batch_create_profiles(agents: Vec<AgentMetadata>) -> Vec<AgentProfile> {
        agents
            .into_iter()
            .map(|agent| Self::create_profile(&agent))
            .collect()
    }

    /// Update profile from KG success rate (Phase 5.5 integration)
    pub fn update_with_kg_metrics(mut profile: AgentProfile, success_rate: f64) -> AgentProfile {
        profile.success_rate = success_rate;
        profile
    }

    /// Create a learning profile with the given ID.
    ///
    /// Callers should pass `agent.stable_id_or_role()` (not `agent.id`) so
    /// that the profile survives hot-reloads. The coordinator already enforces
    /// this; use this function for constructing profiles that will be inserted
    /// via `AgentCoordinator::update_learning_profile`.
    pub fn create_learning_profile(agent_id: String) -> LearningProfile {
        LearningProfile::new(agent_id)
    }

    /// Enhance learning profile with task-type expertise from KG data.
    /// Updates the profile with calculated expertise for specific task type.
    pub fn add_task_type_expertise(
        mut profile: LearningProfile,
        task_type: String,
        expertise: TaskTypeExpertise,
    ) -> LearningProfile {
        profile.set_task_type_expertise(task_type, expertise);
        profile
    }

    /// Update agent profile success rate from learning profile task-type score.
    /// Uses learned expertise for the specified task type, with fallback to
    /// default.
    pub fn update_profile_with_learning(
        mut profile: AgentProfile,
        learning_profile: &LearningProfile,
        task_type: &str,
    ) -> AgentProfile {
        profile.success_rate = learning_profile.get_task_type_score(task_type);
        profile
    }
}

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

    #[test]
    fn test_profile_creation_from_metadata() {
        let agent = AgentMetadata {
            id: "agent-1".to_string(),
            stable_id: "developer".to_string(),
            role: "developer".to_string(),
            name: "Dev Agent 1".to_string(),
            version: "0.1.0".to_string(),
            status: crate::registry::AgentStatus::Active,
            capabilities: vec!["coding".to_string(), "review".to_string()],
            llm_provider: "claude".to_string(),
            llm_model: "claude-sonnet-4".to_string(),
            max_concurrent_tasks: 5,
            current_tasks: 2,
            created_at: chrono::Utc::now(),
            last_heartbeat: chrono::Utc::now(),
            uptime_percentage: 99.5,
            total_tasks_completed: 10,
            system_prompt: None,
        };

        let profile = ProfileAdapter::create_profile(&agent);

        assert_eq!(profile.id, "agent-1");
        assert_eq!(profile.capabilities.len(), 2);
        assert!((profile.current_load - 0.4).abs() < 0.01); // 2/5 = 0.4
        assert_eq!(profile.success_rate, 0.5); // Default
        assert!(profile.availability);
    }

    #[test]
    fn test_batch_create_profiles() {
        let agents = vec![
            AgentMetadata {
                id: "agent-1".to_string(),
                stable_id: "developer".to_string(),
                role: "developer".to_string(),
                name: "Dev 1".to_string(),
                version: "0.1.0".to_string(),
                status: crate::registry::AgentStatus::Active,
                capabilities: vec!["coding".to_string()],
                llm_provider: "claude".to_string(),
                llm_model: "claude-sonnet-4".to_string(),
                max_concurrent_tasks: 5,
                current_tasks: 1,
                created_at: chrono::Utc::now(),
                last_heartbeat: chrono::Utc::now(),
                uptime_percentage: 99.0,
                total_tasks_completed: 5,
                system_prompt: None,
            },
            AgentMetadata {
                id: "agent-2".to_string(),
                stable_id: "reviewer".to_string(),
                role: "reviewer".to_string(),
                name: "Reviewer 1".to_string(),
                version: "0.1.0".to_string(),
                status: crate::registry::AgentStatus::Active,
                capabilities: vec!["review".to_string()],
                llm_provider: "gpt4".to_string(),
                llm_model: "gpt-4".to_string(),
                max_concurrent_tasks: 3,
                current_tasks: 0,
                created_at: chrono::Utc::now(),
                last_heartbeat: chrono::Utc::now(),
                uptime_percentage: 98.5,
                total_tasks_completed: 3,
                system_prompt: None,
            },
        ];

        let profiles = ProfileAdapter::batch_create_profiles(agents);

        assert_eq!(profiles.len(), 2);
        assert_eq!(profiles[0].id, "agent-1");
        assert_eq!(profiles[1].id, "agent-2");
    }

    #[test]
    fn test_update_with_kg_metrics() {
        let profile = AgentProfile {
            id: "agent-1".to_string(),
            roles: vec!["developer".to_string()],
            capabilities: vec!["coding".to_string()],
            current_load: 0.4,
            success_rate: 0.5,
            availability: true,
        };

        let updated = ProfileAdapter::update_with_kg_metrics(profile, 0.85);
        assert_eq!(updated.success_rate, 0.85);
        assert_eq!(updated.id, "agent-1"); // Other fields unchanged
    }

    #[test]
    fn test_create_learning_profile() {
        let learning = ProfileAdapter::create_learning_profile("agent-1".to_string());
        assert_eq!(learning.agent_id, "agent-1");
        assert_eq!(learning.task_type_expertise.len(), 0);
    }

    #[test]
    fn test_add_task_type_expertise() {
        let learning = ProfileAdapter::create_learning_profile("agent-1".to_string());
        let expertise = TaskTypeExpertise {
            success_rate: 0.85,
            total_executions: 20,
            recent_success_rate: 0.90,
            avg_duration_ms: 150.0,
            learning_curve: Vec::new(),
            confidence: 1.0,
        };

        let updated =
            ProfileAdapter::add_task_type_expertise(learning, "coding".to_string(), expertise);
        assert_eq!(updated.get_task_type_score("coding"), 0.85);
        assert_eq!(updated.get_confidence("coding"), 1.0);
    }

    #[test]
    fn test_update_profile_with_learning() {
        let profile = AgentProfile {
            id: "agent-1".to_string(),
            roles: vec!["developer".to_string()],
            capabilities: vec!["coding".to_string()],
            current_load: 0.4,
            success_rate: 0.5,
            availability: true,
        };

        let mut learning = ProfileAdapter::create_learning_profile("agent-1".to_string());
        let expertise = TaskTypeExpertise {
            success_rate: 0.85,
            total_executions: 20,
            recent_success_rate: 0.90,
            avg_duration_ms: 150.0,
            learning_curve: Vec::new(),
            confidence: 1.0,
        };
        learning =
            ProfileAdapter::add_task_type_expertise(learning, "coding".to_string(), expertise);

        let updated = ProfileAdapter::update_profile_with_learning(profile, &learning, "coding");
        assert_eq!(updated.success_rate, 0.85);

        let unknown_updated =
            ProfileAdapter::update_profile_with_learning(updated, &learning, "unknown");
        assert_eq!(unknown_updated.success_rate, 0.5); // Falls back to default
    }
}
