// Integration tests for SwarmCoordinator integration with AgentCoordinator
// Tests verify swarm task assignment, profile synchronization, and metrics
// integration

use std::sync::Arc;
use std::time::Duration;

use vapora_agents::registry::AgentMetadata;
use vapora_agents::{AgentCoordinator, AgentRegistry, ProfileAdapter};

/// Helper to create a test agent
fn create_test_agent(id: &str, role: &str) -> AgentMetadata {
    AgentMetadata::new(
        role.to_string(),
        format!("Agent {}", id),
        "claude".to_string(),
        "claude-sonnet-4".to_string(),
        vec!["coding".to_string(), "testing".to_string()],
    )
}

#[tokio::test]
async fn test_swarm_coordinator_integration_with_registry() {
    // Setup: Create registry and coordinator
    let registry = Arc::new(AgentRegistry::new(10));

    // Register multiple agents
    let agent1 = create_test_agent("1", "developer");
    let agent2 = create_test_agent("2", "developer");
    registry.register_agent(agent1).unwrap();
    registry.register_agent(agent2).unwrap();

    // Create coordinator (internally creates and initializes SwarmCoordinator)
    let coordinator = AgentCoordinator::with_registry(Arc::clone(&registry));

    // Assign a task - should use swarm coordinator
    let result = coordinator
        .assign_task(
            "developer",
            "Test task".to_string(),
            "Implement a feature".to_string(),
            "{}".to_string(),
            80,
        )
        .await;

    assert!(result.is_ok(), "Task assignment should succeed");
    let assigned_agent_id = result.unwrap();
    assert!(
        !assigned_agent_id.is_empty(),
        "Agent ID should not be empty"
    );
}

#[tokio::test]
async fn test_profile_adapter_creates_valid_profiles() {
    // Setup: Create agents and adapter
    let agent1 = create_test_agent("1", "developer");
    let agent2 = create_test_agent("2", "reviewer");

    // Create profiles from agents
    let profile1 = ProfileAdapter::create_profile(&agent1);
    let profile2 = ProfileAdapter::create_profile(&agent2);

    // Verify profile structure - ID is UUID mapped from agent.id
    assert_eq!(profile1.id, agent1.id);
    assert_eq!(profile2.id, agent2.id);

    // Verify capabilities are mapped
    assert!(!profile1.capabilities.is_empty());
    assert!(!profile2.capabilities.is_empty());

    // Verify default success rate is neutral
    assert_eq!(profile1.success_rate, 0.5);
    assert_eq!(profile2.success_rate, 0.5);

    // Verify availability is based on agent status
    assert!(profile1.availability);
    assert!(profile2.availability);
}

#[tokio::test]
async fn test_batch_profile_creation() {
    // Setup: Create multiple agents
    let agents = vec![
        create_test_agent("1", "developer"),
        create_test_agent("2", "reviewer"),
        create_test_agent("3", "tester"),
    ];

    // Batch create profiles
    let profiles = ProfileAdapter::batch_create_profiles(agents);

    // Verify all profiles created
    assert_eq!(profiles.len(), 3);

    // Verify each profile has correct properties
    for (_i, profile) in profiles.iter().enumerate() {
        assert!(!profile.id.is_empty());
        assert!(!profile.capabilities.is_empty());
        assert!(profile.success_rate >= 0.0 && profile.success_rate <= 1.0);
    }
}

#[tokio::test]
async fn test_task_assignment_selects_available_agent() {
    // Setup: Create registry with agents
    let registry = Arc::new(AgentRegistry::new(10));

    let agent1 = create_test_agent("1", "developer");
    let agent2 = create_test_agent("2", "developer");

    registry.register_agent(agent1).unwrap();
    registry.register_agent(agent2).unwrap();

    let coordinator = AgentCoordinator::with_registry(Arc::clone(&registry));

    // Assign multiple tasks
    let result1 = coordinator
        .assign_task(
            "developer",
            "Task 1".to_string(),
            "Description".to_string(),
            "{}".to_string(),
            80,
        )
        .await;

    let result2 = coordinator
        .assign_task(
            "developer",
            "Task 2".to_string(),
            "Description".to_string(),
            "{}".to_string(),
            80,
        )
        .await;

    // Both should succeed
    assert!(result1.is_ok());
    assert!(result2.is_ok());

    // Both should have assigned agents
    assert!(!result1.unwrap().is_empty());
    assert!(!result2.unwrap().is_empty());
}

#[tokio::test]
async fn test_coordinator_without_agent_fails() {
    // Setup: Create registry and coordinator with no agents
    let registry = Arc::new(AgentRegistry::new(10));
    let coordinator = AgentCoordinator::with_registry(registry);

    // Try to assign task with no available agents
    let result = coordinator
        .assign_task(
            "nonexistent",
            "Task".to_string(),
            "Description".to_string(),
            "{}".to_string(),
            80,
        )
        .await;

    // Should fail
    assert!(result.is_err());
}

#[tokio::test]
async fn test_profile_sync_task_spawns() {
    // Setup: Create registry and coordinator
    let registry = Arc::new(AgentRegistry::new(10));

    let agent = create_test_agent("1", "developer");
    registry.register_agent(agent).unwrap();

    // Create coordinator (spawns background profile sync task)
    let _coordinator = AgentCoordinator::with_registry(Arc::clone(&registry));

    // Give background task time to initialize
    tokio::time::sleep(Duration::from_millis(100)).await;

    // Registry should still have agents
    let agents = registry.list_all();
    assert_eq!(agents.len(), 1);
}

#[tokio::test]
async fn test_profile_load_calculation() {
    // Setup: Create agent with known task count
    let agent = create_test_agent("1", "developer");

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

    // Verify load is normalized (0.0-1.0)
    assert!(profile.current_load >= 0.0 && profile.current_load <= 1.0);
}

#[tokio::test]
async fn test_multiple_role_assignment() {
    // Setup: Create registry with agents of different roles
    let registry = Arc::new(AgentRegistry::new(10));

    let developer = create_test_agent("dev", "developer");
    let reviewer = create_test_agent("rev", "reviewer");

    registry.register_agent(developer).unwrap();
    registry.register_agent(reviewer).unwrap();

    let coordinator = AgentCoordinator::with_registry(Arc::clone(&registry));

    // Assign task for developer
    let dev_result = coordinator
        .assign_task(
            "developer",
            "Code task".to_string(),
            "Write code".to_string(),
            "{}".to_string(),
            80,
        )
        .await;

    // Assign task for reviewer
    let rev_result = coordinator
        .assign_task(
            "reviewer",
            "Review task".to_string(),
            "Review code".to_string(),
            "{}".to_string(),
            80,
        )
        .await;

    // Both should succeed
    assert!(dev_result.is_ok());
    assert!(rev_result.is_ok());
}

#[tokio::test]
async fn test_swarm_statistics_available() {
    // Setup: Create registry and coordinator with agents
    let registry = Arc::new(AgentRegistry::new(10));

    let agent1 = create_test_agent("1", "developer");
    let agent2 = create_test_agent("2", "developer");

    registry.register_agent(agent1).unwrap();
    registry.register_agent(agent2).unwrap();

    let coordinator = AgentCoordinator::with_registry(Arc::clone(&registry));

    // Give swarm time to initialize
    tokio::time::sleep(Duration::from_millis(100)).await;

    // Coordinator should have functioning swarm coordinator
    let result = coordinator
        .assign_task(
            "developer",
            "Task".to_string(),
            "Description".to_string(),
            "{}".to_string(),
            80,
        )
        .await;

    // Should successfully assign task (verifies swarm is functional)
    assert!(result.is_ok());
}
