use criterion::{black_box, criterion_group, criterion_main, Criterion, BenchmarkId};
use veza_chat_server::*;
use veza_stream_server::*;
use tokio::runtime::Runtime;
use uuid::Uuid;
use std::time::Duration;
use std::collections::HashMap;

// Benchmarks pour le Chat Server
fn benchmark_auth_token_generation(c: &mut Criterion) {
    let rt = Runtime::new().unwrap();
    let config = Config::default();
    let auth_manager = AuthManager::new(config);
    
    c.bench_function("auth_token_generation", |b| {
        b.iter(|| {
            let user_id = Uuid::new_v4().to_string();
            rt.block_on(async {
                let result = auth_manager.generate_token(&user_id).await;
                black_box(result)
            })
        })
    });
}

fn benchmark_auth_token_validation(c: &mut Criterion) {
    let rt = Runtime::new().unwrap();
    let config = Config::default();
    let auth_manager = AuthManager::new(config);
    let user_id = Uuid::new_v4().to_string();
    
    // Générer un token pour le benchmark
    let token = rt.block_on(async {
        auth_manager.generate_token(&user_id).await.unwrap()
    });
    
    c.bench_function("auth_token_validation", |b| {
        b.iter(|| {
            rt.block_on(async {
                let result = auth_manager.validate_token(&token).await;
                black_box(result)
            })
        })
    });
}

fn benchmark_rate_limiting(c: &mut Criterion) {
    let rt = Runtime::new().unwrap();
    let rate_limiter = RateLimiter::new(1000, Duration::from_secs(60));
    let user_id = Uuid::new_v4().to_string();
    
    c.bench_function("rate_limiting_check", |b| {
        b.iter(|| {
            rt.block_on(async {
                let result = rate_limiter.check_rate_limit(&user_id).await;
                black_box(result)
            })
        })
    });
}

fn benchmark_message_save(c: &mut Criterion) {
    let rt = Runtime::new().unwrap();
    let message_store = MessageStore::new();
    
    c.bench_function("message_save", |b| {
        b.iter(|| {
            let message = Message {
                id: Uuid::new_v4().to_string(),
                conversation_id: Uuid::new_v4().to_string(),
                sender_id: Uuid::new_v4().to_string(),
                content: "Test message content".to_string(),
                created_at: std::time::SystemTime::now(),
            };
            
            rt.block_on(async {
                let result = message_store.save_message(&message).await;
                black_box(result)
            })
        })
    });
}

fn benchmark_message_retrieval(c: &mut Criterion) {
    let rt = Runtime::new().unwrap();
    let message_store = MessageStore::new();
    let conversation_id = Uuid::new_v4().to_string();
    
    // Pré-remplir avec des messages
    rt.block_on(async {
        for i in 0..100 {
            let message = Message {
                id: Uuid::new_v4().to_string(),
                conversation_id: conversation_id.clone(),
                sender_id: Uuid::new_v4().to_string(),
                content: format!("Message {}", i),
                created_at: std::time::SystemTime::now(),
            };
            message_store.save_message(&message).await.unwrap();
        }
    });
    
    c.bench_function("message_retrieval", |b| {
        b.iter(|| {
            rt.block_on(async {
                let result = message_store.get_messages(&conversation_id, 0, 10).await;
                black_box(result)
            })
        })
    });
}

fn benchmark_concurrent_auth_operations(c: &mut Criterion) {
    let rt = Runtime::new().unwrap();
    let config = Config::default();
    let auth_manager = AuthManager::new(config);
    
    c.bench_function("concurrent_auth_operations", |b| {
        b.iter(|| {
            rt.block_on(async {
                let mut handles = vec![];
                
                for i in 0..10 {
                    let auth_manager_clone = auth_manager.clone();
                    let handle = tokio::spawn(async move {
                        let user_id = format!("user_{}", i);
                        let token = auth_manager_clone.generate_token(&user_id).await.unwrap();
                        let validation = auth_manager_clone.validate_token(&token).await.unwrap();
                        black_box(validation)
                    });
                    handles.push(handle);
                }
                
                for handle in handles {
                    handle.await.unwrap();
                }
            })
        })
    });
}

// Benchmarks pour le Stream Server
fn benchmark_stream_token_generation(c: &mut Criterion) {
    let rt = Runtime::new().unwrap();
    let config = Config::default();
    let token_validator = TokenValidator::new(config);
    
    c.bench_function("stream_token_generation", |b| {
        b.iter(|| {
            let track_id = Uuid::new_v4().to_string();
            let user_id = Uuid::new_v4().to_string();
            
            rt.block_on(async {
                let result = token_validator.generate_token(&track_id, &user_id).await;
                black_box(result)
            })
        })
    });
}

fn benchmark_stream_token_validation(c: &mut Criterion) {
    let rt = Runtime::new().unwrap();
    let config = Config::default();
    let token_validator = TokenValidator::new(config);
    let track_id = Uuid::new_v4().to_string();
    let user_id = Uuid::new_v4().to_string();
    
    // Générer un token pour le benchmark
    let token = rt.block_on(async {
        token_validator.generate_token(&track_id, &user_id).await.unwrap()
    });
    
    c.bench_function("stream_token_validation", |b| {
        b.iter(|| {
            rt.block_on(async {
                let result = token_validator.validate_token(&token, &track_id, &user_id).await;
                black_box(result)
            })
        })
    });
}

fn benchmark_audio_compression(c: &mut Criterion) {
    let rt = Runtime::new().unwrap();
    let compression = AdaptiveCompression::new();
    let audio_data = vec![0u8; 1024 * 1024]; // 1MB de données audio
    
    let mut group = c.benchmark_group("audio_compression");
    
    for quality in ["low", "medium", "high"].iter() {
        group.bench_with_input(BenchmarkId::new("quality", quality), quality, |b, quality| {
            b.iter(|| {
                rt.block_on(async {
                    let result = compression.compress_audio(&audio_data, quality).await;
                    black_box(result)
                })
            })
        });
    }
    
    group.finish();
}

fn benchmark_audio_cache_operations(c: &mut Criterion) {
    let rt = Runtime::new().unwrap();
    let audio_cache = AudioCache::new(1024 * 1024 * 10); // 10MB cache
    let audio_data = vec![0u8; 1024]; // 1KB de données audio
    
    c.bench_function("audio_cache_put", |b| {
        b.iter(|| {
            let track_id = Uuid::new_v4().to_string();
            rt.block_on(async {
                let result = audio_cache.put(&track_id, audio_data.clone()).await;
                black_box(result)
            })
        })
    });
    
    c.bench_function("audio_cache_get", |b| {
        // Pré-remplir le cache
        rt.block_on(async {
            for i in 0..100 {
                let track_id = format!("track_{}", i);
                audio_cache.put(&track_id, audio_data.clone()).await;
            }
        });
        
        b.iter(|| {
            let track_id = format!("track_{}", 50); // Track qui existe
            rt.block_on(async {
                let result = audio_cache.get(&track_id).await;
                black_box(result)
            })
        })
    });
}

fn benchmark_adaptive_compression_bandwidth_detection(c: &mut Criterion) {
    let rt = Runtime::new().unwrap();
    let compression = AdaptiveCompression::new();
    
    let mut group = c.benchmark_group("bandwidth_detection");
    
    for bandwidth in [100000, 500000, 1000000, 5000000].iter() {
        group.bench_with_input(BenchmarkId::new("bandwidth", bandwidth), bandwidth, |b, bandwidth| {
            b.iter(|| {
                rt.block_on(async {
                    let result = compression.detect_quality(*bandwidth).await;
                    black_box(result)
                })
            })
        });
    }
    
    group.finish();
}

fn benchmark_concurrent_stream_operations(c: &mut Criterion) {
    let rt = Runtime::new().unwrap();
    let config = Config::default();
    let token_validator = TokenValidator::new(config);
    let audio_cache = AudioCache::new(1024 * 1024 * 10);
    let compression = AdaptiveCompression::new();
    
    c.bench_function("concurrent_stream_operations", |b| {
        b.iter(|| {
            rt.block_on(async {
                let mut handles = vec![];
                
                for i in 0..10 {
                    let token_validator_clone = token_validator.clone();
                    let audio_cache_clone = audio_cache.clone();
                    let compression_clone = compression.clone();
                    
                    let handle = tokio::spawn(async move {
                        let track_id = format!("track_{}", i);
                        let user_id = format!("user_{}", i);
                        
                        // 1. Générer token
                        let token = token_validator_clone.generate_token(&track_id, &user_id).await.unwrap();
                        
                        // 2. Valider token
                        let is_valid = token_validator_clone.validate_token(&token, &track_id, &user_id).await.unwrap();
                        
                        // 3. Compresser audio
                        let audio_data = vec![0u8; 1024];
                        let compressed_data = compression_clone.compress_audio(&audio_data, "high").await.unwrap();
                        
                        // 4. Mettre en cache
                        audio_cache_clone.put(&track_id, compressed_data).await;
                        
                        black_box(is_valid)
                    });
                    handles.push(handle);
                }
                
                for handle in handles {
                    handle.await.unwrap();
                }
            })
        })
    });
}

// Benchmarks de performance système
fn benchmark_memory_allocation(c: &mut Criterion) {
    c.bench_function("memory_allocation", |b| {
        b.iter(|| {
            let mut data = Vec::with_capacity(1024);
            for i in 0..1024 {
                data.push(i as u8);
            }
            black_box(data)
        })
    });
}

fn benchmark_string_operations(c: &mut Criterion) {
    c.bench_function("string_operations", |b| {
        b.iter(|| {
            let mut s = String::new();
            for i in 0..100 {
                s.push_str(&format!("item_{}", i));
            }
            black_box(s)
        })
    });
}

fn benchmark_hashmap_operations(c: &mut Criterion) {
    c.bench_function("hashmap_operations", |b| {
        b.iter(|| {
            let mut map = HashMap::new();
            for i in 0..100 {
                map.insert(i, format!("value_{}", i));
            }
            black_box(map)
        })
    });
}

// Benchmarks de latence
fn benchmark_websocket_latency(c: &mut Criterion) {
    let rt = Runtime::new().unwrap();
    let config = Config::default();
    let auth_manager = AuthManager::new(config);
    
    c.bench_function("websocket_latency", |b| {
        b.iter(|| {
            let start = std::time::SystemTime::now();
            
            rt.block_on(async {
                let user_id = Uuid::new_v4().to_string();
                let token = auth_manager.generate_token(&user_id).await.unwrap();
                let validation = auth_manager.validate_token(&token).await.unwrap();
                black_box(validation)
            });
            
            let duration = start.elapsed().unwrap();
            black_box(duration)
        })
    });
}

fn benchmark_streaming_latency(c: &mut Criterion) {
    let rt = Runtime::new().unwrap();
    let config = Config::default();
    let token_validator = TokenValidator::new(config);
    let audio_cache = AudioCache::new(1024 * 1024);
    let compression = AdaptiveCompression::new();
    
    c.bench_function("streaming_latency", |b| {
        b.iter(|| {
            let start = std::time::SystemTime::now();
            
            rt.block_on(async {
                let track_id = Uuid::new_v4().to_string();
                let user_id = Uuid::new_v4().to_string();
                
                // 1. Générer token
                let token = token_validator.generate_token(&track_id, &user_id).await.unwrap();
                
                // 2. Valider token
                let is_valid = token_validator.validate_token(&token, &track_id, &user_id).await.unwrap();
                
                // 3. Compresser audio
                let audio_data = vec![0u8; 1024];
                let compressed_data = compression.compress_audio(&audio_data, "high").await.unwrap();
                
                // 4. Mettre en cache
                audio_cache.put(&track_id, compressed_data).await;
                
                black_box(is_valid)
            });
            
            let duration = start.elapsed().unwrap();
            black_box(duration)
        })
    });
}

// Benchmarks de throughput
fn benchmark_message_throughput(c: &mut Criterion) {
    let rt = Runtime::new().unwrap();
    let message_store = MessageStore::new();
    
    c.bench_function("message_throughput", |b| {
        b.iter(|| {
            rt.block_on(async {
                let mut handles = vec![];
                
                for i in 0..100 {
                    let message_store_clone = message_store.clone();
                    let handle = tokio::spawn(async move {
                        let message = Message {
                            id: Uuid::new_v4().to_string(),
                            conversation_id: Uuid::new_v4().to_string(),
                            sender_id: Uuid::new_v4().to_string(),
                            content: format!("Message {}", i),
                            created_at: std::time::SystemTime::now(),
                        };
                        
                        let result = message_store_clone.save_message(&message).await;
                        black_box(result)
                    });
                    handles.push(handle);
                }
                
                for handle in handles {
                    handle.await.unwrap();
                }
            })
        })
    });
}

fn benchmark_audio_throughput(c: &mut Criterion) {
    let rt = Runtime::new().unwrap();
    let audio_cache = AudioCache::new(1024 * 1024 * 100); // 100MB cache
    let compression = AdaptiveCompression::new();
    
    c.bench_function("audio_throughput", |b| {
        b.iter(|| {
            rt.block_on(async {
                let mut handles = vec![];
                
                for i in 0..100 {
                    let audio_cache_clone = audio_cache.clone();
                    let compression_clone = compression.clone();
                    
                    let handle = tokio::spawn(async move {
                        let track_id = format!("track_{}", i);
                        let audio_data = vec![0u8; 1024];
                        
                        // Compresser audio
                        let compressed_data = compression_clone.compress_audio(&audio_data, "high").await.unwrap();
                        
                        // Mettre en cache
                        audio_cache_clone.put(&track_id, compressed_data).await;
                    });
                    handles.push(handle);
                }
                
                for handle in handles {
                    handle.await.unwrap();
                }
            })
        })
    });
}

// Configuration des groupes de benchmarks
criterion_group!(
    auth_benchmarks,
    benchmark_auth_token_generation,
    benchmark_auth_token_validation,
    benchmark_rate_limiting,
    benchmark_concurrent_auth_operations
);

criterion_group!(
    message_benchmarks,
    benchmark_message_save,
    benchmark_message_retrieval,
    benchmark_message_throughput
);

criterion_group!(
    stream_benchmarks,
    benchmark_stream_token_generation,
    benchmark_stream_token_validation,
    benchmark_audio_compression,
    benchmark_audio_cache_operations,
    benchmark_adaptive_compression_bandwidth_detection,
    benchmark_concurrent_stream_operations
);

criterion_group!(
    system_benchmarks,
    benchmark_memory_allocation,
    benchmark_string_operations,
    benchmark_hashmap_operations
);

criterion_group!(
    latency_benchmarks,
    benchmark_websocket_latency,
    benchmark_streaming_latency
);

criterion_group!(
    throughput_benchmarks,
    benchmark_message_throughput,
    benchmark_audio_throughput
);

criterion_main!(
    auth_benchmarks,
    message_benchmarks,
    stream_benchmarks,
    system_benchmarks,
    latency_benchmarks,
    throughput_benchmarks
);
