// Simple in-memory demo without database for testing

use crate::demo::{self, Player, MatchType};
use crate::glicko::{Glicko2Calculator, calculate_weighted_score};
use rand::Rng;

pub async fn run_simple_demo() {
    println!("🏓 Pickleball ELO Tracker v2.0 - Simple Demo");
    println!("==========================================\n");
    
    // Generate 20 players
    println!("👥 Generating 20 players...");
    let mut players: Vec<Player> = (0..20)
        .map(|_| Player::new_random())
        .collect();
    println!("✅ Players generated\n");
    
    println!("Session 1: Opening Tournament");
    println!("=============================\n");
    
    run_session(&mut players, 1, 50);
    
    println!("\nSession 2: Mid-Tournament");
    println!("========================\n");
    
    run_session(&mut players, 2, 55);
    
    println!("\nSession 3: Finals");
    println!("================\n");
    
    run_session(&mut players, 3, 52);
    
    // Print final leaderboards
    println!("\n📧 Final Leaderboards:\n");
    print_leaderboard(&players);
    
    println!("\n✅ Demo Complete!");
    println!("\nTotal Players: {}", players.len());
    println!("Total Matches Across 3 Sessions: {}", 50 + 55 + 52);
}

fn run_session(players: &mut [Player], session_num: usize, num_matches: usize) {
    println!("Starting session {}...", session_num);
    let mut rng = rand::thread_rng();
    let calc = Glicko2Calculator::new();
    
    for i in 0..num_matches {
        if i % 20 == 0 && i > 0 {
            println!("  {} matches completed...", i);
        }
        
        // Randomly choose singles or doubles
        let match_type = if rng.gen_bool(0.5) {
            MatchType::Singles
        } else {
            MatchType::Doubles
        };
        
        match match_type {
            MatchType::Singles => {
                // Pick 2 random players
                let p1_idx = rng.gen_range(0..players.len());
                let mut p2_idx = rng.gen_range(0..players.len());
                while p2_idx == p1_idx {
                    p2_idx = rng.gen_range(0..players.len());
                }
                
                let (team1_score, team2_score) = demo::simulate_match(
                    &[players[p1_idx].true_skill],
                    &[players[p2_idx].true_skill],
                );
                
                // Calculate outcomes with performance-based weighting
                let p1_outcome = if team1_score > team2_score {
                    calculate_weighted_score(players[p1_idx].singles.rating, players[p2_idx].singles.rating, team1_score, team2_score)
                } else {
                    calculate_weighted_score(players[p1_idx].singles.rating, players[p2_idx].singles.rating, team1_score, team2_score)
                };
                
                let p2_outcome = if team1_score > team2_score {
                    calculate_weighted_score(players[p2_idx].singles.rating, players[p1_idx].singles.rating, team2_score, team1_score)
                } else {
                    calculate_weighted_score(players[p2_idx].singles.rating, players[p1_idx].singles.rating, team2_score, team1_score)
                };
                
                // Update ratings
                players[p1_idx].singles = calc.update_rating(
                    &players[p1_idx].singles,
                    &[(players[p2_idx].singles, p1_outcome)],
                );
                
                players[p2_idx].singles = calc.update_rating(
                    &players[p2_idx].singles,
                    &[(players[p1_idx].singles, p2_outcome)],
                );
            }
            MatchType::Doubles => {
                // Pick 4 random players
                let mut indices: Vec<usize> = (0..players.len()).collect();
                use rand::seq::SliceRandom;
                indices[..].shuffle(&mut rng);
                let team1_indices = vec![indices[0], indices[1]];
                let team2_indices = vec![indices[2], indices[3]];
                
                let team1_skills: Vec<f64> = team1_indices.iter()
                    .map(|&i| players[i].true_skill)
                    .collect();
                let team2_skills: Vec<f64> = team2_indices.iter()
                    .map(|&i| players[i].true_skill)
                    .collect();
                
                let (team1_score, team2_score) = demo::simulate_match(&team1_skills, &team2_skills);
                let team1_won = team1_score > team2_score;
                
                // Update team 1
                for &idx in &team1_indices {
                    let outcome = if team1_won {
                        calculate_weighted_score(players[idx].doubles.rating, team2_indices.iter().map(|&i| players[i].doubles.rating).sum::<f64>() / 2.0, team1_score, team2_score)
                    } else {
                        calculate_weighted_score(players[idx].doubles.rating, team2_indices.iter().map(|&i| players[i].doubles.rating).sum::<f64>() / 2.0, team1_score, team2_score)
                    };
                    
                    let avg_opponent = crate::glicko::GlickoRating {
                        rating: team2_indices.iter().map(|&i| players[i].doubles.rating).sum::<f64>() / 2.0,
                        rd: team2_indices.iter().map(|&i| players[i].doubles.rd).sum::<f64>() / 2.0,
                        volatility: 0.06,
                    };
                    
                    players[idx].doubles = calc.update_rating(
                        &players[idx].doubles,
                        &[(avg_opponent, outcome)],
                    );
                }
                
                // Update team 2
                for &idx in &team2_indices {
                    let outcome = if !team1_won {
                        calculate_weighted_score(players[idx].doubles.rating, team1_indices.iter().map(|&i| players[i].doubles.rating).sum::<f64>() / 2.0, team2_score, team1_score)
                    } else {
                        calculate_weighted_score(players[idx].doubles.rating, team1_indices.iter().map(|&i| players[i].doubles.rating).sum::<f64>() / 2.0, team2_score, team1_score)
                    };
                    
                    let avg_opponent = crate::glicko::GlickoRating {
                        rating: team1_indices.iter().map(|&i| players[i].doubles.rating).sum::<f64>() / 2.0,
                        rd: team1_indices.iter().map(|&i| players[i].doubles.rd).sum::<f64>() / 2.0,
                        volatility: 0.06,
                    };
                    
                    players[idx].doubles = calc.update_rating(
                        &players[idx].doubles,
                        &[(avg_opponent, outcome)],
                    );
                }
            }
        }
    }
    
    println!("✅ Completed {} matches", num_matches);
    print_leaderboard(players);
}

fn print_leaderboard(players: &[Player]) {
    println!("\n📊 Top 5 Singles:");
    let mut singles_sorted = players.to_vec();
    singles_sorted.sort_by(|a, b| b.singles.rating.partial_cmp(&a.singles.rating).unwrap());
    for (i, p) in singles_sorted.iter().take(5).enumerate() {
        println!(
            "  {}. {} - {:.1} (RD: {:.1})",
            i + 1,
            p.name,
            p.singles.rating,
            p.singles.rd,
        );
    }
    
    println!("\n📊 Top 5 Doubles:");
    let mut doubles_sorted = players.to_vec();
    doubles_sorted.sort_by(|a, b| b.doubles.rating.partial_cmp(&a.doubles.rating).unwrap());
    for (i, p) in doubles_sorted.iter().take(5).enumerate() {
        println!(
            "  {}. {} - {:.1} (RD: {:.1})",
            i + 1,
            p.name,
            p.doubles.rating,
            p.doubles.rd,
        );
    }
}
