//! # Agent Selection Example
//!
//! Demonstrates how agents are ranked and selected based on expertise and load.
//!
//! ## What This Example Shows
//! - Comparing multiple agents for a task
//! - Understanding the scoring formula: 0.3*load + 0.5*expertise +
//!   0.2*confidence
//! - How load balancing prevents over-allocation
//! - Real-world selection decisions
//!
//! ## Run
//! ```bash
//! cargo run --example 03-agent-selection -p vapora-agents
//! ```

fn main() {
    println!("=== Agent Selection Example ===\n");

    // Step 1: Define agent profiles with different characteristics
    #[derive(Debug, Clone)]
    struct AgentProfile {
        name: String,
        expertise: f64,    // 0.0 to 1.0
        confidence: f64,   // 0.0 to 1.0 (based on sample size)
        current_load: f64, // 0.0 to 1.0
    }

    let agents = vec![
        AgentProfile {
            name: "alice".to_string(),
            expertise: 0.92,
            confidence: 0.95,
            current_load: 0.30, // Moderately busy
        },
        AgentProfile {
            name: "bob".to_string(),
            expertise: 0.78,
            confidence: 0.85,
            current_load: 0.05, // Very available
        },
        AgentProfile {
            name: "carol".to_string(),
            expertise: 0.88,
            confidence: 0.70,
            current_load: 0.50, // Quite busy
        },
    ];

    println!("Available agents for 'coding' task:\n");
    for agent in &agents {
        println!(
            "  {}: expertise={:.0}%, confidence={:.0}%, load={:.0}%",
            agent.name,
            agent.expertise * 100.0,
            agent.confidence * 100.0,
            agent.current_load * 100.0
        );
    }

    // Step 2: Apply scoring formula
    println!("\n=== Scoring Formula ===");
    println!("score = (1 - 0.3*load) + 0.5*expertise + 0.2*confidence");
    println!("            ↓                ↓                ↓");
    println!("       availability   expertise   confidence/trust\n");

    // Normalize load contribution (lower load = higher score)
    let scores: Vec<_> = agents
        .iter()
        .map(|agent| {
            let availability = 1.0 - (0.3 * agent.current_load);
            let expertise_score = 0.5 * agent.expertise;
            let confidence_score = 0.2 * agent.confidence;
            let total = availability + expertise_score + confidence_score;
            (
                agent,
                availability,
                expertise_score,
                confidence_score,
                total,
            )
        })
        .collect();

    println!("Agent Scores:");
    for (agent, avail, exp, conf, total) in &scores {
        println!(
            "\n  {}: {:.3} (avail={:.3}, exp={:.3}, conf={:.3})",
            agent.name, total, avail, exp, conf
        );
    }

    // Step 3: Rank agents
    let mut sorted_scores = scores.clone();
    sorted_scores.sort_by(|a, b| b.4.partial_cmp(&a.4).unwrap_or(std::cmp::Ordering::Equal));

    println!("\n=== Ranking (Best → Worst) ===");
    for (rank, (agent, _, _, _, total)) in sorted_scores.iter().enumerate() {
        let medal = match rank {
            0 => "🥇",
            1 => "🥈",
            2 => "🥉",
            _ => "  ",
        };
        println!(
            "{} {}. {} (score: {:.3})",
            medal,
            rank + 1,
            agent.name,
            total
        );
    }

    // Step 4: Selection decision
    let best_agent = sorted_scores[0].0;
    println!("\n=== Selection Decision ===");
    println!("Assigned to: {}", best_agent.name);
    println!(
        "Reason: Best balance of expertise ({:.0}%), availability ({:.0}%), and confidence \
         ({:.0}%)",
        best_agent.expertise * 100.0,
        (1.0 - (0.3 * best_agent.current_load)) * 100.0,
        best_agent.confidence * 100.0
    );

    // Step 5: Demonstrate impact of load balancing
    println!("\n=== Load Balancing Impact ===");
    println!("If alice wasn't available (hypothetical):");

    let mut remaining = sorted_scores.clone();
    remaining.remove(0);

    let second_best = &remaining[0].0;
    println!(
        "  → Would select: {} (score: {:.3})",
        second_best.name, remaining[0].4
    );

    println!("\nWithout load balancing, carol would be selected despite:");
    println!("  - Lower expertise (88% vs 92%)");
    println!("  - Same recent success rate");
    println!("  BUT: It's already running at 50% capacity!");
}
