use axum::{
    extract::{
        ws::{Message, WebSocket, WebSocketUpgrade},
        Query, State,
    },
    http::HeaderMap,
    response::Response,
};
use serde::{Deserialize, Serialize};
use std::{
    collections::HashMap,
    sync::Arc,
    time::{Duration, SystemTime},
};
use tokio::sync::{broadcast, RwLock};
// tokio_stream::StreamExt not needed here, using futures_util::StreamExt
// Note: Use tracing::info! macro directly instead of importing
use futures_util::{SinkExt, StreamExt as FuturesStreamExt};
use uuid::Uuid;

#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(tag = "type")]
pub enum WebSocketEvent {
    /// Événements de lecture
    PlaybackStarted {
        track_id: String,
        user_id: String,
        timestamp: u64,
    },
    PlaybackPaused {
        track_id: String,
        user_id: String,
        position_ms: u64,
    },
    PlaybackResumed {
        track_id: String,
        user_id: String,
        position_ms: u64,
    },
    PlaybackStopped {
        track_id: String,
        user_id: String,
        total_played_ms: u64,
    },
    PlaybackProgress {
        track_id: String,
        user_id: String,
        position_ms: u64,
        buffer_percentage: f32,
    },

    /// Événements de playlist
    PlaylistUpdated {
        playlist_id: String,
        action: PlaylistAction,
        track_id: Option<String>,
        position: Option<usize>,
    },
    PlaylistShared {
        playlist_id: String,
        from_user: String,
        to_users: Vec<String>,
    },

    /// Événements sociaux
    TrackLiked {
        track_id: String,
        user_id: String,
        total_likes: u64,
    },
    TrackShared {
        track_id: String,
        from_user: String,
        to_users: Vec<String>,
        message: Option<String>,
    },
    UserFollowed {
        follower_id: String,
        followed_id: String,
    },

    /// Événements système
    ServerMessage {
        message: String,
        level: MessageLevel,
    },
    RateLimitWarning {
        remaining_requests: u32,
        reset_time_seconds: u64,
    },

    /// Réponses aux commandes
    CommandResponse {
        command_id: String,
        success: bool,
        data: Option<serde_json::Value>,
        error: Option<String>,
    },

    /// Statistiques en temps réel
    LiveStats {
        concurrent_listeners: u32,
        top_tracks: Vec<LiveTrackStats>,
        server_load: f32,
    },

    /// Événements de synchronisation audio (P0-2)
    SyncAdjustment {
        client_id: String,
        timestamp_offset_ms: i64,
        playback_rate: f64,
        target_buffer_ms: u32,
        sync_point_ms: u64,
    },
    SyncPing {
        ping_id: String,
        server_timestamp: u64,
    },
    SyncInit {
        session_id: String,
        track_id: String,
        server_timestamp_ms: u64,
        position_ms: u64,
    },
    SyncStable {
        session_id: String,
    },
}

#[derive(Debug, Clone, Serialize, Deserialize)]
pub enum PlaylistAction {
    Added,
    Removed,
    Reordered,
    Cleared,
}

#[derive(Debug, Clone, Serialize, Deserialize)]
pub enum MessageLevel {
    Info,
    Warning,
    Error,
}

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct LiveTrackStats {
    pub track_id: String,
    pub title: String,
    pub artist: String,
    pub current_listeners: u32,
}

#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(tag = "type")]
pub enum WebSocketCommand {
    /// Commandes de lecture
    Play {
        command_id: String,
        track_id: String,
        start_position_ms: Option<u64>,
    },
    Pause {
        command_id: String,
        track_id: String,
    },
    Stop {
        command_id: String,
        track_id: String,
    },
    Seek {
        command_id: String,
        track_id: String,
        position_ms: u64,
    },

    /// Commandes de playlist
    AddToPlaylist {
        command_id: String,
        playlist_id: String,
        track_id: String,
        position: Option<usize>,
    },
    RemoveFromPlaylist {
        command_id: String,
        playlist_id: String,
        track_id: String,
    },

    /// Commandes d'abonnement
    Subscribe {
        command_id: String,
        events: Vec<String>,
        filters: Option<HashMap<String, String>>,
    },
    Unsubscribe {
        command_id: String,
        events: Vec<String>,
    },

    /// Commandes de statut
    GetStatus {
        command_id: String,
    },
    Ping {
        command_id: String,
    },
    SyncPong {
        ping_id: String,
        client_timestamp: u64,
    },
}

#[derive(Debug, Clone)]
pub struct WebSocketConnection {
    pub id: Uuid,
    pub user_id: Option<String>,
    pub ip_address: String,
    pub connected_at: SystemTime,
    pub last_activity: SystemTime,
    pub subscribed_events: Vec<String>,
    pub sender: broadcast::Sender<WebSocketEvent>,
    
    // Latency metrics
    pub last_ping_sent_at: Option<SystemTime>,
    pub latency_rtt: Option<Duration>,
    pub clock_offset_ms: Option<i64>, // Signed offset in milliseconds
    pub last_sync_measurement: Option<SystemTime>,
}

#[derive(Debug)]
pub struct WebSocketManager {
    connections: Arc<RwLock<HashMap<Uuid, WebSocketConnection>>>,
    global_sender: broadcast::Sender<WebSocketEvent>,
    stats: Arc<RwLock<WebSocketStats>>,
}

#[derive(Debug, Default)]
struct WebSocketStats {
    total_connections: u64,
    current_connections: u32,
    messages_sent: u64,
    messages_received: u64,
    events_broadcasted: u64,
}

impl WebSocketManager {
    pub fn new() -> Self {
        let (global_sender, _) = broadcast::channel(1000);

        Self {
            connections: Arc::new(RwLock::new(HashMap::new())),
            global_sender,
            stats: Arc::new(RwLock::new(WebSocketStats::default())),
        }
    }

    /// Gère une nouvelle connexion WebSocket
    pub async fn handle_websocket(
        &self,
        ws: WebSocketUpgrade,
        user_id: Option<String>,
        ip_address: String,
    ) -> Response {
        let manager = self.clone();

        ws.on_upgrade(move |socket| async move {
            manager.handle_socket(socket, user_id, ip_address).await;
        })
    }

    async fn handle_socket(&self, socket: WebSocket, user_id: Option<String>, ip_address: String) {
        let connection_id = Uuid::new_v4();
        let (sender, mut receiver) = broadcast::channel(100);

        let connection = WebSocketConnection {
            id: connection_id,
            user_id: user_id.clone(),
            ip_address: ip_address.clone(),
            connected_at: SystemTime::now(),
            last_activity: SystemTime::now(),
            subscribed_events: vec!["*".to_string()], // Abonné à tous les événements par défaut
            sender: sender.clone(),
            last_ping_sent_at: None,
            latency_rtt: None,
            clock_offset_ms: None,
            last_sync_measurement: None,
        };

        // Ajouter la connexion
        {
            let mut connections = self.connections.write().await;
            connections.insert(connection_id, connection);

            let mut stats = self.stats.write().await;
            stats.current_connections += 1;
            stats.total_connections += 1;
        }

        tracing::info!(
            "WebSocket connecté: {} depuis {} (user: {:?})",
            connection_id,
            ip_address,
            user_id
        );

        // Split socket en sender et receiver
        let (mut sender_ws, mut receiver_ws) = socket.split();

        // Envoyer un message de bienvenue
        let welcome_event = WebSocketEvent::ServerMessage {
            message: "Connexion WebSocket établie".to_string(),
            level: MessageLevel::Info,
        };

        if let Ok(json) = serde_json::to_string(&welcome_event) {
            if let Err(e) = sender_ws.send(Message::Text(json)).await {
                tracing::warn!("Erreur envoi message bienvenue: {}", e);
            }
        }

        // Tâche pour recevoir les messages du client
        let connections_clone = self.connections.clone();
        let manager_clone = self.clone();
        let stats_clone = self.stats.clone();
        let connection_id_clone = connection_id;
        let global_sender_clone = self.global_sender.clone();

        let mut receive_task = tokio::spawn(async move {
            use futures_util::StreamExt;
            while let Some(result) = receiver_ws.next().await {
                match result {
                    Ok(msg) => {
                        // Mettre à jour la dernière activité
                        {
                            let mut conns = connections_clone.write().await;
                            if let Some(conn) = conns.get_mut(&connection_id_clone) {
                                conn.last_activity = SystemTime::now();
                            }
                        }

                        match msg {
                            Message::Text(text) => {
                                tracing::debug!(
                                    "Message reçu de {}: {}",
                                    connection_id_clone,
                                    text
                                );

                                // Parser la commande
                                if let Ok(command) = serde_json::from_str::<WebSocketCommand>(&text)
                                {
                                    manager_clone
                                        .handle_command(connection_id_clone, command)
                                        .await;

                                    // Mettre à jour les stats
                                    {
                                        let mut stats = stats_clone.write().await;
                                        stats.messages_received += 1;
                                    }
                                } else {
                                    tracing::warn!(
                                        "Message invalide reçu de {}: {}",
                                        connection_id_clone,
                                        text
                                    );
                                }
                            }
                            Message::Binary(_) => {
                                tracing::debug!("Message binaire reçu de {}", connection_id_clone);
                            }
                            Message::Ping(data) => {
                                // Répondre au ping automatiquement
                                if let Some(conn) =
                                    connections_clone.read().await.get(&connection_id_clone)
                                {
                                    // Le ping sera géré par axum automatiquement
                                }
                            }
                            Message::Pong(_) => {
                                tracing::debug!("Pong reçu de {}", connection_id_clone);
                            }
                            Message::Close(_) => {
                                tracing::info!(
                                    "Fermeture demandée par le client {}",
                                    connection_id_clone
                                );
                                break;
                            }
                        }
                    }
                    Err(e) => {
                        tracing::error!(
                            "Erreur de réception WebSocket pour {}: {}",
                            connection_id_clone,
                            e
                        );
                        break;
                    }
                }
            }
        });

        // Tâche pour envoyer les événements au client
        let connections_clone_send = self.connections.clone();
        let stats_clone_send = self.stats.clone();
        let mut send_task = tokio::spawn(async move {
            while let Ok(event) = receiver.recv().await {
                // Vérifier si la connexion doit recevoir cet événement
                let should_send = Self::should_receive_event(
                    &connections_clone_send,
                    connection_id_clone,
                    &event,
                )
                .await;

                if should_send {
                    if let Ok(json) = serde_json::to_string(&event) {
                        if let Err(e) = sender_ws.send(Message::Text(json)).await {
                            tracing::warn!(
                                "Erreur envoi événement à {}: {}",
                                connection_id_clone,
                                e
                            );
                            break;
                        }

                        // Mettre à jour les stats
                        {
                            let mut stats = stats_clone_send.write().await;
                            stats.messages_sent += 1;
                        }
                    }
                }
            }
        });

        // Attendre que l'une des tâches se termine
        tokio::select! {
            _ = &mut receive_task => {
                tracing::info!("Tâche de réception terminée pour {}", connection_id);
            }
            _ = &mut send_task => {
                tracing::info!("Tâche d'envoi terminée pour {}", connection_id);
            }
        }

        // Nettoyage à la déconnexion
        {
            let mut connections = self.connections.write().await;
            connections.remove(&connection_id);

            let mut stats = self.stats.write().await;
            stats.current_connections = stats.current_connections.saturating_sub(1);
        }

        tracing::info!("WebSocket déconnecté: {}", connection_id);
    }

    pub async fn handle_command(&self, connection_id: Uuid, command: WebSocketCommand) {
        let connections = &self.connections;
        let sender = &self.global_sender;
        let response = match command {
            WebSocketCommand::Subscribe {
                command_id,
                events,
                filters: _,
            } => {
                {
                    let mut conns = connections.write().await;
                    if let Some(conn) = conns.get_mut(&connection_id) {
                        conn.subscribed_events = events.clone();
                    }
                }

                WebSocketEvent::CommandResponse {
                    command_id,
                    success: true,
                    data: Some(serde_json::json!({
                        "subscribed_events": events
                    })),
                    error: None,
                }
            }

            WebSocketCommand::Unsubscribe { command_id, events } => {
                {
                    let mut conns = connections.write().await;
                    if let Some(conn) = conns.get_mut(&connection_id) {
                        conn.subscribed_events.retain(|e| !events.contains(e));
                    }
                }

                WebSocketEvent::CommandResponse {
                    command_id,
                    success: true,
                    data: Some(serde_json::json!({
                        "unsubscribed_events": events
                    })),
                    error: None,
                }
            }

            WebSocketCommand::GetStatus { command_id } => {
                let conn_info = {
                    let conns = connections.read().await;
                    conns.get(&connection_id).cloned()
                };

                if let Some(conn) = conn_info {
                    WebSocketEvent::CommandResponse {
                        command_id,
                        success: true,
                        data: Some(serde_json::json!({
                            "connection_id": conn.id,
                            "user_id": conn.user_id,
                            "connected_at": conn.connected_at
                                .duration_since(SystemTime::UNIX_EPOCH)
                                .map(|d| d.as_secs())
                                .unwrap_or(0),
                            "subscribed_events": conn.subscribed_events
                        })),
                        error: None,
                    }
                } else {
                    WebSocketEvent::CommandResponse {
                        command_id,
                        success: false,
                        data: None,
                        error: Some("Connexion non trouvée".to_string()),
                    }
                }
            }

            WebSocketCommand::Ping { command_id } => WebSocketEvent::CommandResponse {
                command_id,
                success: true,
                data: Some(serde_json::json!({
                    "timestamp": SystemTime::now()
                        .duration_since(SystemTime::UNIX_EPOCH)
                        .map(|d| d.as_secs())
                        .unwrap_or(0)
                })),
                error: None,
            },

            WebSocketCommand::SyncPong { ping_id, client_timestamp } => {
                let mut conns = connections.write().await;
                if let Some(conn) = conns.get_mut(&connection_id) {
                    if let Some(sent_at) = conn.last_ping_sent_at {
                        if let Ok(elapsed) = sent_at.elapsed() {
                            // RTT = now - sent_time
                            let rtt_ms = elapsed.as_millis() as u64;
                            
                            // Offset = client_ts - (server_sent_ts + RTT/2)
                            // server_sent_ts is approximated by sent_at
                            let sent_at_ms = sent_at
                                .duration_since(SystemTime::UNIX_EPOCH)
                                .unwrap_or(Duration::ZERO)
                                .as_millis() as u64;
                            let server_estimated_arrival_ts = sent_at_ms + (rtt_ms / 2);
                            
                            // Offset positif = Client est en avance (son horloge est plus grande)
                            // Offset négatif = Client est en retard
                            let offset_ms = client_timestamp as i64 - server_estimated_arrival_ts as i64;

                            conn.latency_rtt = Some(Duration::from_millis(rtt_ms));
                            conn.clock_offset_ms = Some(offset_ms);
                            conn.last_sync_measurement = Some(SystemTime::now());
                            conn.last_ping_sent_at = None; // Reset ping sent time

                            tracing::debug!(
                                "Sync Pong from {}: RTT={}ms, Offset={}ms (Client TS: {}, Server Est TS: {})",
                                connection_id,
                                rtt_ms,
                                offset_ms,
                                client_timestamp,
                                server_estimated_arrival_ts
                            );
                        }
                    } else {
                        tracing::warn!("Received SyncPong from {} without active Ping", connection_id);
                    }
                }
                
                 WebSocketEvent::CommandResponse {
                    command_id: "sync_pong".to_string(), // internal
                    success: true,
                    data: None,
                    error: None,
                }
            },

            _ => WebSocketEvent::CommandResponse {
                command_id: "unknown".to_string(),
                success: false,
                data: None,
                error: Some("Commande non implémentée".to_string()),
            },
        };

        let _ = sender.send(response);
    }

    async fn should_receive_event(
        connections: &Arc<RwLock<HashMap<Uuid, WebSocketConnection>>>,
        connection_id: Uuid,
        event: &WebSocketEvent,
    ) -> bool {
        let conns = connections.read().await;
        if let Some(conn) = conns.get(&connection_id) {
            if conn.subscribed_events.is_empty() {
                return true; // Par défaut, recevoir tous les événements
            }

            let event_type = match event {
                WebSocketEvent::PlaybackStarted { .. } => "playback",
                WebSocketEvent::PlaybackPaused { .. } => "playback",
                WebSocketEvent::PlaybackResumed { .. } => "playback",
                WebSocketEvent::PlaybackStopped { .. } => "playback",
                WebSocketEvent::PlaybackProgress { .. } => "playback_progress",
                WebSocketEvent::PlaylistUpdated { .. } => "playlist",
                WebSocketEvent::TrackLiked { .. } => "social",
                WebSocketEvent::TrackShared { .. } => "social",
                WebSocketEvent::LiveStats { .. } => "stats",
                WebSocketEvent::ServerMessage { .. } => "system",
                _ => "other",
            };

            return conn.subscribed_events.contains(&event_type.to_string());
        }

        false
    }

    /// Diffuse un événement à toutes les connexions
    pub async fn broadcast_event(&self, event: WebSocketEvent) {
        let _ = self.global_sender.send(event);
        self.stats.write().await.events_broadcasted += 1;
    }

    /// Envoie un événement à une connexion spécifique
    pub async fn send_to_connection(&self, connection_id: Uuid, event: WebSocketEvent) {
        let connections = self.connections.read().await;
        if let Some(conn) = connections.get(&connection_id) {
            let _ = conn.sender.send(event);
        }
    }

    /// Envoie un événement à un utilisateur spécifique (toutes ses connexions)
    pub async fn send_to_user(&self, user_id: &str, event: WebSocketEvent) {
        let connections = self.connections.read().await;
        for conn in connections.values() {
            if let Some(ref conn_user_id) = conn.user_id {
                if conn_user_id == user_id {
                    let _ = conn.sender.send(event.clone());
                }
            }
        }
    }

    /// Nettoie les connexions inactives
    pub async fn cleanup_inactive_connections(&self, max_idle_duration: Duration) {
        let cutoff = SystemTime::now() - max_idle_duration;
        let mut connections = self.connections.write().await;
        let before_count = connections.len();

        connections.retain(|_, conn| conn.last_activity > cutoff);

        let removed = before_count - connections.len();
        if removed > 0 {
            tracing::info!(
                "Nettoyage des connexions WebSocket inactives: {} supprimées",
                removed
            );
            self.stats.write().await.current_connections = connections.len() as u32;
        }
    }

    /// Ferme toutes les connexions WebSocket (pour graceful shutdown)
    pub async fn close_all_connections(&self) {
        // Envoyer un message de shutdown à toutes les connexions
        let shutdown_event = WebSocketEvent::ServerMessage {
            message: "Serveur en cours d'arrêt. Connexion fermée.".to_string(),
            level: MessageLevel::Warning,
        };

        // Diffuser l'événement à toutes les connexions
        self.broadcast_event(shutdown_event.clone()).await;

        // Attendre un peu pour que les messages soient envoyés
        tokio::time::sleep(Duration::from_millis(500)).await;

        // Récupérer toutes les connexions et les fermer
        let mut connections = self.connections.write().await;
        let count = connections.len();
        connections.clear();

        // Mettre à jour les statistiques
        self.stats.write().await.current_connections = 0;

        if count > 0 {
            tracing::info!("Fermeture de {} connexions WebSocket pour shutdown", count);
        }
    }

    /// Obtient les statistiques des WebSockets
    pub async fn get_stats(&self) -> serde_json::Value {
        let stats = self.stats.read().await;
        let connections = self.connections.read().await;

        let user_connections: HashMap<String, u32> = connections
            .values()
            .filter_map(|conn| conn.user_id.as_ref())
            .fold(HashMap::new(), |mut acc, user_id| {
                *acc.entry(user_id.clone()).or_insert(0) += 1;
                acc
            });

        serde_json::json!({
            "total_connections": stats.total_connections,
            "current_connections": stats.current_connections,
            "messages_sent": stats.messages_sent,
            "messages_received": stats.messages_received,
            "events_broadcasted": stats.events_broadcasted,
            "user_connections": user_connections.len(),
            "connections_per_user": user_connections
        })
    }

    /// Envoie un Ping de synchronisation
    pub async fn send_sync_ping(&self, connection_id: Uuid) -> Result<(), String> {
        let mut conns = self.connections.write().await;
        if let Some(conn) = conns.get_mut(&connection_id) {
            let now = SystemTime::now();
            let timestamp = now
                .duration_since(SystemTime::UNIX_EPOCH)
                .map(|d| d.as_millis() as u64)
                .unwrap_or(0);
            let ping_id = Uuid::new_v4().to_string();

            conn.last_ping_sent_at = Some(now);

            let event = WebSocketEvent::SyncPing {
                ping_id,
                server_timestamp: timestamp,
            };

            // Envoyer directement via le sender de la connexion
            let _ = conn.sender.send(event);
            Ok(())
        } else {
            Err("Connexion introuvable".to_string())
        }
    }

    /// Récupère les stats de latence pour une connexion
    pub async fn get_latency_stats(&self, connection_id: Uuid) -> (Option<Duration>, Option<i64>) {
        if let Some(conn) = self.connections.read().await.get(&connection_id) {
            (conn.latency_rtt, conn.clock_offset_ms)
        } else {
            (None, None)
        }
    }
}

impl Clone for WebSocketManager {
    fn clone(&self) -> Self {
        Self {
            connections: self.connections.clone(),
            global_sender: self.global_sender.clone(),
            stats: self.stats.clone(),
        }
    }
}

impl Default for WebSocketManager {
    fn default() -> Self {
        Self::new()
    }
}

/// Query parameters pour les connexions WebSocket
#[derive(Debug, Deserialize)]
pub struct WebSocketQuery {
    pub user_id: Option<String>,
    pub token: Option<String>,
}

/// Handler pour les connexions WebSocket avec authentification JWT
pub async fn websocket_handler(
    ws: WebSocketUpgrade,
    Query(params): Query<WebSocketQuery>,
    headers: HeaderMap,
    State(ws_manager): State<Arc<WebSocketManager>>,
) -> Response {
    // Extraire le token JWT depuis les query params ou headers
    let token = params.token.or_else(|| {
        headers
            .get("authorization")
            .and_then(|h| h.to_str().ok())
            .and_then(|s| s.strip_prefix("Bearer "))
            .map(|s| s.to_string())
    });

    // Extraire l'adresse IP réelle
    let ip_address = headers
        .get("x-forwarded-for")
        .or_else(|| headers.get("x-real-ip"))
        .and_then(|h| h.to_str().ok())
        .unwrap_or("127.0.0.1")
        .to_string();

    // Si un token est fourni, on le valide (pour l'instant, on accepte la connexion)
    // En production, on validerait le token avec AuthManager
    let user_id = params.user_id.or_else(|| {
        // Si un token est fourni, on pourrait extraire user_id du token
        // Pour l'instant, on utilise le user_id fourni dans les params
        None
    });

    tracing::info!(
        "Nouvelle connexion WebSocket demandée pour utilisateur: {:?} depuis {}",
        user_id,
        ip_address
    );

    ws_manager.handle_websocket(ws, user_id, ip_address).await
}

#[cfg(test)]
mod tests {
    use super::*;
    use axum::extract::ws::WebSocketUpgrade;
    use axum::http::HeaderMap;
    use std::sync::Arc;

    #[tokio::test]
    async fn test_websocket_manager_new() {
        let manager = WebSocketManager::new();
        let stats = manager.get_stats().await;

        assert_eq!(stats["total_connections"], 0);
        assert_eq!(stats["current_connections"], 0);
    }

    #[tokio::test]
    async fn test_websocket_manager_broadcast_event() {
        let manager = WebSocketManager::new();

        let event = WebSocketEvent::ServerMessage {
            message: "Test message".to_string(),
            level: MessageLevel::Info,
        };

        manager.broadcast_event(event).await;

        let stats = manager.get_stats().await;
        assert_eq!(stats["events_broadcasted"], 1);
    }

    #[tokio::test]
    async fn test_websocket_manager_cleanup_inactive() {
        let manager = WebSocketManager::new();

        // Nettoyer les connexions inactives (ne devrait rien faire car pas de connexions)
        manager
            .cleanup_inactive_connections(Duration::from_secs(60))
            .await;

        let stats = manager.get_stats().await;
        assert_eq!(stats["current_connections"], 0);
    }

    #[test]
    fn test_websocket_query_deserialize() {
        let json = r#"{"user_id": "123", "token": "test-token"}"#;
        let query: Result<WebSocketQuery, _> = serde_json::from_str(json);

        assert!(query.is_ok());
        let query = query.unwrap();
        assert_eq!(query.user_id, Some("123".to_string()));
        assert_eq!(query.token, Some("test-token".to_string()));
    }

    #[test]
    fn test_websocket_query_empty() {
        let json = r#"{}"#;
        let query: Result<WebSocketQuery, _> = serde_json::from_str(json);

        assert!(query.is_ok());
        let query = query.unwrap();
        assert_eq!(query.user_id, None);
        assert_eq!(query.token, None);
    }

    #[test]
    fn test_websocket_command_serialize() {
        let command = WebSocketCommand::Ping {
            command_id: "test-123".to_string(),
        };

        let json = serde_json::to_string(&command);
        assert!(json.is_ok());
        let json_str = json.unwrap();
        assert!(json_str.contains("test-123"));
        assert!(json_str.contains("Ping"));
    }

    #[test]
    fn test_websocket_event_serialize() {
        let event = WebSocketEvent::ServerMessage {
            message: "Test".to_string(),
            level: MessageLevel::Info,
        };

        let json = serde_json::to_string(&event);
        assert!(json.is_ok());
    }

    #[tokio::test]
    async fn test_websocket_manager_stats() {
        let manager = WebSocketManager::new();
        let stats = manager.get_stats().await;

        // Vérifier que toutes les clés attendues sont présentes
        assert!(stats.get("total_connections").is_some());
        assert!(stats.get("current_connections").is_some());
        assert!(stats.get("messages_sent").is_some());
        assert!(stats.get("messages_received").is_some());
        assert!(stats.get("events_broadcasted").is_some());
        assert!(stats.get("user_connections").is_some());
    }

    #[test]
    fn test_playlist_action_serialize() {
        let actions = vec![
            PlaylistAction::Added,
            PlaylistAction::Removed,
            PlaylistAction::Reordered,
            PlaylistAction::Cleared,
        ];

        for action in actions {
            let json = serde_json::to_string(&action);
            assert!(json.is_ok(), "Failed to serialize {:?}", action);
        }
    }

    #[test]
    fn test_message_level_serialize() {
        let levels = vec![
            MessageLevel::Info,
            MessageLevel::Warning,
            MessageLevel::Error,
        ];

        for level in levels {
            let json = serde_json::to_string(&level);
            assert!(json.is_ok(), "Failed to serialize {:?}", level);
        }
    }
}
