//! SIP UDP transport — owns the main SIP socket.
//!
//! Binds a UDP socket, receives SIP messages, and provides a send method.

use std::net::SocketAddr;
use std::sync::Arc;
use tokio::net::UdpSocket;

/// The SIP UDP transport layer.
pub struct SipTransport {
    socket: Arc<UdpSocket>,
}

impl SipTransport {
    /// Bind a UDP socket on the given address (e.g. "0.0.0.0:5070").
    pub async fn bind(bind_addr: &str) -> Result<Self, String> {
        let socket = UdpSocket::bind(bind_addr)
            .await
            .map_err(|e| format!("bind {bind_addr}: {e}"))?;
        Ok(Self {
            socket: Arc::new(socket),
        })
    }

    /// Get a clone of the socket Arc for the receiver task.
    pub fn socket(&self) -> Arc<UdpSocket> {
        self.socket.clone()
    }

    /// Spawn the UDP receive loop. Calls the handler for every received packet.
    pub fn spawn_receiver<F>(&self, handler: F)
    where
        F: Fn(&[u8], SocketAddr) + Send + 'static,
    {
        let socket = self.socket.clone();
        tokio::spawn(async move {
            let mut buf = vec![0u8; 65535];
            loop {
                match socket.recv_from(&mut buf).await {
                    Ok((n, addr)) => handler(&buf[..n], addr),
                    Err(e) => {
                        eprintln!("[sip_transport] recv error: {e}");
                        tokio::time::sleep(std::time::Duration::from_millis(100)).await;
                    }
                }
            }
        });
    }
}
