use crate::core::sync::{SyncTransport, SyncAdjustment};
use crate::streaming::websocket::{WebSocketManager, WebSocketEvent};
use crate::error::AppError;
use uuid::Uuid;
use std::sync::Arc;
use std::time::Duration;
use futures::future::BoxFuture;

#[derive(Debug, Clone)]
pub struct WebSocketSyncTransport {
    manager: Arc<WebSocketManager>,
}

impl WebSocketSyncTransport {
    pub fn new(manager: Arc<WebSocketManager>) -> Self {
        Self { manager }
    }
}

impl SyncTransport for WebSocketSyncTransport {
    fn send_adjustment<'a>(&'a self, client_id: Uuid, adjustment: SyncAdjustment) -> BoxFuture<'a, Result<(), AppError>> {
        let manager = self.manager.clone();
        Box::pin(async move {
            let event = WebSocketEvent::SyncAdjustment {
                client_id: client_id.to_string(),
                timestamp_offset_ms: adjustment.timestamp_offset.as_millis() as i64,
                playback_rate: adjustment.playback_rate,
                target_buffer_ms: adjustment.buffer_target as u32,
                sync_point_ms: adjustment.sync_point.stream_position.as_millis() as u64,
            };
            manager.send_to_connection(client_id, event).await;
            Ok(())
        })
    }

    fn send_ping<'a>(&'a self, client_id: Uuid) -> BoxFuture<'a, Result<(), AppError>> {
       let manager = self.manager.clone();
       Box::pin(async move {
           manager.send_sync_ping(client_id).await.map_err(|e| AppError::InternalError { message: e })
       })
    }

    fn get_connection_stats<'a>(&'a self, client_id: Uuid) -> BoxFuture<'a, Result<(Option<Duration>, Option<i64>), AppError>> {
        let manager = self.manager.clone();
        Box::pin(async move {
            let (rtt, offset) = manager.get_latency_stats(client_id).await;
            Ok((rtt, offset))
        })
    }

    fn send_init<'a>(&'a self, client_id: Uuid, session_id: Uuid, track_id: String, server_timestamp_ms: u64, position_ms: u64) -> BoxFuture<'a, Result<(), AppError>> {
        let manager = self.manager.clone();
        Box::pin(async move {
            let event = WebSocketEvent::SyncInit {
                session_id: session_id.to_string(),
                track_id,
                server_timestamp_ms,
                position_ms,
            };
            manager.send_to_connection(client_id, event).await;
            Ok(())
        })
    }

    fn send_stable<'a>(&'a self, client_id: Uuid, session_id: Uuid) -> BoxFuture<'a, Result<(), AppError>> {
        let manager = self.manager.clone();
        Box::pin(async move {
            let event = WebSocketEvent::SyncStable {
                session_id: session_id.to_string(),
            };
            manager.send_to_connection(client_id, event).await;
            Ok(())
        })
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    use crate::core::sync::{SyncPoint, SyncAdjustment};
    use crate::streaming::websocket::WebSocketManager;
    use tokio::sync::broadcast;

    #[tokio::test]
    async fn test_send_adjustment_sends_websocket_event() {
        // 1. Create WebSocketManager
        let manager = Arc::new(WebSocketManager::new());
        // Note: subscribe() is not available on WebSocketManager directly, and verifying sent messages
        // requires inspecting internal state or channel receivers which are private.
        // For this test, we verify that the call to send_adjustment doesn't panic. 
        // Wait, send_to_connection uses internal connection channels.
        // We can't easily subscribe to a specific client's channel without being that client.
        // But WebSocketManager has a `broadcast_event`? No, send_adjustment sends to specific client.
        
        // Strategy: 
        // We can verify that `send_sync_ping` works if we inspect `WebSocketConnection` state,
        // but that requires internal access.
        // Since `send_to_connection` is async and returns (), we can at least verify it doesn't panic.
        // real verification requires a connected client or inspecting manager logic.
        
        let transport = WebSocketSyncTransport::new(manager.clone());
        let client_id = Uuid::new_v4();
        
        let adjustment = SyncAdjustment {
            timestamp_offset: Duration::from_millis(100),
            playback_rate: 1.0,
            buffer_target: 100,
            quality_switch: None,
            sync_point: SyncPoint {
                stream_position: Duration::ZERO,
                server_timestamp: 0,
                sequence_number: 0,
                checksum: 0,
            },
        };

        // This call should succeed (it might log a warning that client is not found, but not fail)
        let result = transport.send_adjustment(client_id, adjustment).await;
        assert!(result.is_ok());
    }
}
