// US-010: Transparent ping/pong handler
//
// tokio-tungstenite does NOT automatically send pong frames for received pings.
// The receive loop in client.rs handles Message::Ping explicitly and replies
// with Message::Pong. These helpers exist for testability and clarity.

use tokio_tungstenite::tungstenite::Message;

/// Returns `true` if the message is a WebSocket ping frame.
// Used in ws/client.rs run_*_loop — clippy false positive for pub(crate) helpers
#[allow(dead_code)]
pub(crate) fn is_server_ping(msg: &Message) -> bool {
    matches!(msg, Message::Ping(_))
}

/// Creates a pong response for a ping message, or `None` if it is not a ping.
// Used in ws/client.rs run_*_loop — clippy false positive for pub(crate) helpers
#[allow(dead_code)]
pub(crate) fn pong_for(msg: &Message) -> Option<Message> {
    if let Message::Ping(data) = msg {
        Some(Message::Pong(data.clone()))
    } else {
        None
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    use tokio_tungstenite::tungstenite::Message;

    // US-010: is_server_ping correctly identifies ping frames
    #[test]
    fn is_server_ping_returns_true_for_ping() {
        let ping = Message::Ping(vec![1, 2, 3]);
        assert!(is_server_ping(&ping));
    }

    #[test]
    fn is_server_ping_returns_false_for_text() {
        let text = Message::Text("hello".to_string());
        assert!(!is_server_ping(&text));
    }

    // US-010: pong_for creates matching pong for a ping
    #[test]
    fn pong_for_returns_pong_with_same_data() {
        let ping = Message::Ping(vec![42, 99]);
        let pong = pong_for(&ping);
        assert_eq!(pong, Some(Message::Pong(vec![42, 99])));
    }

    #[test]
    fn pong_for_returns_none_for_non_ping() {
        let text = Message::Text("not a ping".to_string());
        assert_eq!(pong_for(&text), None);
    }
}
