//! WebSocket transport abstractions.
//!
//! This module defines the WebSocket transport layer used by the Tenbin SDK.
//! It provides a connector abstraction for establishing WebSocket connections
//! and a concrete implementation backed by `tokio-tungstenite`.
//!
//! The transport layer is responsible only for connection establishment and
//! yielding a sink/stream pair; protocol handling is implemented elsewhere.

use async_trait::async_trait;
use futures::{
    Sink, Stream, StreamExt as _,
    stream::{SplitSink, SplitStream},
};
use tokio::net::TcpStream;
use tokio_tungstenite::{
    MaybeTlsStream, WebSocketStream, connect_async,
    tungstenite::{Error, Message},
};
use url::Url;

/// WebSocket connection factory.
///
/// Implementations of this trait are responsible for establishing a WebSocket
/// connection and returning a `(Sink, Stream)` pair for sending and receiving
/// raw WebSocket messages.
///
/// This abstraction allows the SDK to remain agnostic to the underlying
/// WebSocket implementation and enables mocking in tests.
#[async_trait]
pub trait WsConnector: Send + Sync + Clone + 'static {
    /// Sink used to send WebSocket messages to the server.
    type Sink: Sink<Message, Error = Error> + Unpin + Send + 'static;
    /// Stream used to receive WebSocket messages from the server.
    type Stream: Stream<Item = Result<Message, Error>> + Unpin + Send + 'static;

    /// Establish a WebSocket connection.
    ///
    /// Returns a sink/stream pair representing the active connection.
    async fn connect(&self) -> Result<(Self::Sink, Self::Stream), Error>;
}

/// `tokio-tungstenite`-based WebSocket connector.
///
/// This is the default WebSocket transport used by the SDK.
#[derive(Clone)]
pub struct TungsteniteConnector {
    /// WebSocket endpoint URL.
    url: Url,
}

impl TungsteniteConnector {
    /// Construct a new WebSocket connector for the given endpoint URL.
    pub fn new(url: Url) -> Self {
        Self { url }
    }
}

/// WebSocket connector implementation backed by `tokio-tungstenite`.
#[async_trait]
impl WsConnector for TungsteniteConnector {
    type Sink = SplitSink<WebSocketStream<MaybeTlsStream<TcpStream>>, Message>;
    type Stream = SplitStream<WebSocketStream<MaybeTlsStream<TcpStream>>>;

    /// Establish a WebSocket connection using `tokio-tungstenite`.
    async fn connect(&self) -> Result<(Self::Sink, Self::Stream), Error> {
        let (ws, _) = connect_async(self.url.clone()).await?;
        Ok(ws.split())
    }
}
