//! TURN Server Implementation
//! RFC 5766 compliant TURN server for NAT traversal relay

use std::collections::HashMap;
use std::net::SocketAddr;
use std::sync::Arc;
use std::time::{Duration, Instant};
use tokio::net::UdpSocket;
use tokio::sync::RwLock;
use tracing::{info, debug, warn};

/// STUN/TURN Message Types
const BINDING_REQUEST: u16 = 0x0001;
const BINDING_RESPONSE: u16 = 0x0101;
const ALLOCATE_REQUEST: u16 = 0x0003;
const ALLOCATE_RESPONSE: u16 = 0x0103;
const ALLOCATE_ERROR_RESPONSE: u16 = 0x0113;
const REFRESH_REQUEST: u16 = 0x0004;
const REFRESH_RESPONSE: u16 = 0x0104;
const SEND_INDICATION: u16 = 0x0016;
const DATA_INDICATION: u16 = 0x0017;
const CREATE_PERMISSION_REQUEST: u16 = 0x0008;
const CREATE_PERMISSION_RESPONSE: u16 = 0x0108;
const CHANNEL_BIND_REQUEST: u16 = 0x0009;
const CHANNEL_BIND_RESPONSE: u16 = 0x0109;

/// STUN/TURN Attribute Types
const ATTR_XOR_MAPPED_ADDRESS: u16 = 0x0020;
const ATTR_XOR_RELAYED_ADDRESS: u16 = 0x0016;
const ATTR_XOR_PEER_ADDRESS: u16 = 0x0012;
const ATTR_USERNAME: u16 = 0x0006;
const ATTR_MESSAGE_INTEGRITY: u16 = 0x0008;
const ATTR_ERROR_CODE: u16 = 0x0009;
const ATTR_REALM: u16 = 0x0014;
const ATTR_NONCE: u16 = 0x0015;
const ATTR_LIFETIME: u16 = 0x000D;
const ATTR_DATA: u16 = 0x0013;
const ATTR_SOFTWARE: u16 = 0x8022;
const ATTR_REQUESTED_TRANSPORT: u16 = 0x0019;
const ATTR_CHANNEL_NUMBER: u16 = 0x000C;

/// STUN Magic Cookie (RFC 5389)
const MAGIC_COOKIE: u32 = 0x2112A442;

/// Error codes
const ERROR_UNAUTHORIZED: u16 = 401;
const ERROR_STALE_NONCE: u16 = 438;
const ERROR_ALLOCATION_MISMATCH: u16 = 437;
const ERROR_INSUFFICIENT_CAPACITY: u16 = 508;

/// Default allocation lifetime (10 minutes)
const DEFAULT_LIFETIME: u32 = 600;

/// Allocation state
#[derive(Debug)]
struct Allocation {
    client_addr: SocketAddr,
    relay_socket: Arc<UdpSocket>,
    relay_addr: SocketAddr,
    username: String,
    permissions: HashMap<String, Instant>, // peer IP -> expiry
    channels: HashMap<u16, SocketAddr>,    // channel number -> peer addr
    created_at: Instant,
    lifetime: Duration,
}

/// TURN Server
pub struct TurnServer {
    port: u16,
    realm: String,
    username: String,
    password: String,
    allocations: Arc<RwLock<HashMap<String, Allocation>>>,
    nonces: Arc<RwLock<HashMap<String, Instant>>>,
}

impl TurnServer {
    pub fn new(port: u16, realm: String, username: String, password: String) -> Self {
        Self {
            port,
            realm,
            username,
            password,
            allocations: Arc::new(RwLock::new(HashMap::new())),
            nonces: Arc::new(RwLock::new(HashMap::new())),
        }
    }

    /// Start the TURN server
    pub async fn start(&self) -> anyhow::Result<()> {
        let addr = format!("0.0.0.0:{}", self.port);
        let socket = UdpSocket::bind(&addr).await?;
        let socket = Arc::new(socket);
        
        info!("TURN Server listening on UDP port {}", self.port);

        // Start cleanup task for expired allocations
        let allocations_clone = self.allocations.clone();
        let nonces_clone = self.nonces.clone();
        tokio::spawn(async move {
            loop {
                tokio::time::sleep(Duration::from_secs(60)).await;
                cleanup_expired(&allocations_clone, &nonces_clone).await;
            }
        });

        loop {
            let mut buf = [0u8; 2048];
            match socket.recv_from(&mut buf).await {
                Ok((len, src_addr)) => {
                    let socket_clone = socket.clone();
                    let data = buf[..len].to_vec();
                    let realm = self.realm.clone();
                    let username = self.username.clone();
                    let password = self.password.clone();
                    let allocations = self.allocations.clone();
                    let nonces = self.nonces.clone();
                    
                    tokio::spawn(async move {
                        if let Err(e) = handle_turn_request(
                            &socket_clone,
                            &data,
                            src_addr,
                            &realm,
                            &username,
                            &password,
                            &allocations,
                            &nonces,
                        ).await {
                            warn!("Failed to handle TURN request: {}", e);
                        }
                    });
                }
                Err(e) => {
                    warn!("TURN recv error: {}", e);
                }
            }
        }
    }
}

/// Cleanup expired allocations and nonces
async fn cleanup_expired(
    allocations: &Arc<RwLock<HashMap<String, Allocation>>>,
    nonces: &Arc<RwLock<HashMap<String, Instant>>>,
) {
    let now = Instant::now();
    
    // Cleanup allocations
    let mut allocs = allocations.write().await;
    allocs.retain(|_, alloc| {
        alloc.created_at.elapsed() < alloc.lifetime
    });
    
    // Cleanup nonces (expire after 1 hour)
    let mut nonce_map = nonces.write().await;
    nonce_map.retain(|_, created| {
        now.duration_since(*created) < Duration::from_secs(3600)
    });
}

/// Handle a TURN request
async fn handle_turn_request(
    socket: &UdpSocket,
    data: &[u8],
    src_addr: SocketAddr,
    realm: &str,
    valid_username: &str,
    valid_password: &str,
    allocations: &Arc<RwLock<HashMap<String, Allocation>>>,
    nonces: &Arc<RwLock<HashMap<String, Instant>>>,
) -> anyhow::Result<()> {
    // Validate minimum STUN header size (20 bytes)
    if data.len() < 20 {
        return Ok(());
    }

    // Parse STUN header
    let msg_type = u16::from_be_bytes([data[0], data[1]]);
    let magic = u32::from_be_bytes([data[4], data[5], data[6], data[7]]);
    let transaction_id = &data[8..20];

    // Verify magic cookie
    if magic != MAGIC_COOKIE {
        debug!("Invalid STUN magic cookie from {}", src_addr);
        return Ok(());
    }

    match msg_type {
        BINDING_REQUEST => {
            // Handle as STUN Binding Request
            let response = build_binding_response(transaction_id, src_addr)?;
            socket.send_to(&response, src_addr).await?;
            debug!("TURN: STUN Binding Response sent to {}", src_addr);
        }
        ALLOCATE_REQUEST => {
            handle_allocate(
                socket, data, src_addr, transaction_id,
                realm, valid_username, valid_password, allocations, nonces
            ).await?;
        }
        REFRESH_REQUEST => {
            handle_refresh(
                socket, data, src_addr, transaction_id, allocations
            ).await?;
        }
        CREATE_PERMISSION_REQUEST => {
            handle_create_permission(
                socket, data, src_addr, transaction_id, allocations
            ).await?;
        }
        SEND_INDICATION => {
            handle_send_indication(data, src_addr, allocations).await?;
        }
        CHANNEL_BIND_REQUEST => {
            handle_channel_bind(
                socket, data, src_addr, transaction_id, allocations
            ).await?;
        }
        _ => {
            debug!("TURN: Unknown message type 0x{:04x} from {}", msg_type, src_addr);
        }
    }

    Ok(())
}

/// Handle Allocate Request
async fn handle_allocate(
    socket: &UdpSocket,
    data: &[u8],
    src_addr: SocketAddr,
    transaction_id: &[u8],
    realm: &str,
    valid_username: &str,
    valid_password: &str,
    allocations: &Arc<RwLock<HashMap<String, Allocation>>>,
    nonces: &Arc<RwLock<HashMap<String, Instant>>>,
) -> anyhow::Result<()> {
    let client_key = src_addr.to_string();
    
    // Check if allocation already exists
    {
        let allocs = allocations.read().await;
        if allocs.contains_key(&client_key) {
            // Allocation already exists
            let response = build_error_response(
                transaction_id,
                ERROR_ALLOCATION_MISMATCH,
                "Allocation already exists"
            );
            socket.send_to(&response, src_addr).await?;
            return Ok(());
        }
    }
    
    // Parse attributes to check authentication
    let attrs = parse_attributes(data)?;
    
    // Check for credentials
    let username = attrs.get(&ATTR_USERNAME);
    let nonce = attrs.get(&ATTR_NONCE);
    let msg_integrity = attrs.get(&ATTR_MESSAGE_INTEGRITY);
    
    if username.is_none() || nonce.is_none() || msg_integrity.is_none() {
        // Send challenge response
        let new_nonce = generate_nonce();
        {
            let mut nonce_map = nonces.write().await;
            nonce_map.insert(new_nonce.clone(), Instant::now());
        }
        
        let response = build_challenge_response(transaction_id, realm, &new_nonce);
        socket.send_to(&response, src_addr).await?;
        debug!("TURN: Sent challenge to {}", src_addr);
        return Ok(());
    }
    
    // Verify credentials
    let username_str = String::from_utf8_lossy(username.unwrap());
    if username_str != valid_username {
        let response = build_error_response(transaction_id, ERROR_UNAUTHORIZED, "Invalid username");
        socket.send_to(&response, src_addr).await?;
        return Ok(());
    }
    
    // Verify nonce
    let nonce_str = String::from_utf8_lossy(nonce.unwrap());
    {
        let nonce_map = nonces.read().await;
        if !nonce_map.contains_key(nonce_str.as_ref()) {
            let response = build_error_response(transaction_id, ERROR_STALE_NONCE, "Stale nonce");
            socket.send_to(&response, src_addr).await?;
            return Ok(());
        }
    }
    
    // TODO: Verify MESSAGE-INTEGRITY with HMAC-SHA1
    // For simplicity, we skip this in the basic implementation
    
    // Create relay socket
    let relay_socket = match UdpSocket::bind("0.0.0.0:0").await {
        Ok(s) => Arc::new(s),
        Err(_) => {
            let response = build_error_response(
                transaction_id,
                ERROR_INSUFFICIENT_CAPACITY,
                "Cannot allocate relay address"
            );
            socket.send_to(&response, src_addr).await?;
            return Ok(());
        }
    };
    
    let relay_addr = relay_socket.local_addr()?;
    
    // Create allocation
    let allocation = Allocation {
        client_addr: src_addr,
        relay_socket: relay_socket.clone(),
        relay_addr,
        username: username_str.to_string(),
        permissions: HashMap::new(),
        channels: HashMap::new(),
        created_at: Instant::now(),
        lifetime: Duration::from_secs(DEFAULT_LIFETIME as u64),
    };
    
    // Store allocation
    {
        let mut allocs = allocations.write().await;
        allocs.insert(client_key.clone(), allocation);
    }
    
    // Start relay task
    let socket_clone = socket.local_addr()?.to_string();
    let client_addr = src_addr;
    let allocations_clone = allocations.clone();
    
    tokio::spawn(async move {
        let main_socket = UdpSocket::bind("0.0.0.0:0").await.ok();
        if let Some(main) = main_socket {
            main.connect(&socket_clone).await.ok();
            relay_incoming_data(relay_socket, main, client_addr, allocations_clone).await;
        }
    });
    
    // Build success response
    let response = build_allocate_response(transaction_id, src_addr, relay_addr)?;
    socket.send_to(&response, src_addr).await?;
    
    info!("TURN: Allocation created for {} -> relay {}", src_addr, relay_addr);
    Ok(())
}

/// Handle Refresh Request
async fn handle_refresh(
    socket: &UdpSocket,
    data: &[u8],
    src_addr: SocketAddr,
    transaction_id: &[u8],
    allocations: &Arc<RwLock<HashMap<String, Allocation>>>,
) -> anyhow::Result<()> {
    let client_key = src_addr.to_string();
    
    // Parse lifetime attribute
    let attrs = parse_attributes(data)?;
    let lifetime = attrs.get(&ATTR_LIFETIME)
        .map(|v| {
            if v.len() >= 4 {
                u32::from_be_bytes([v[0], v[1], v[2], v[3]])
            } else {
                DEFAULT_LIFETIME
            }
        })
        .unwrap_or(DEFAULT_LIFETIME);
    
    let mut allocs = allocations.write().await;
    
    if lifetime == 0 {
        // Delete allocation
        allocs.remove(&client_key);
        info!("TURN: Allocation deleted for {}", src_addr);
    } else if let Some(alloc) = allocs.get_mut(&client_key) {
        // Refresh allocation
        alloc.lifetime = Duration::from_secs(lifetime as u64);
        alloc.created_at = Instant::now();
    }
    
    // Build response
    let response = build_refresh_response(transaction_id, lifetime);
    socket.send_to(&response, src_addr).await?;
    
    Ok(())
}

/// Handle Create Permission Request
async fn handle_create_permission(
    socket: &UdpSocket,
    data: &[u8],
    src_addr: SocketAddr,
    transaction_id: &[u8],
    allocations: &Arc<RwLock<HashMap<String, Allocation>>>,
) -> anyhow::Result<()> {
    let client_key = src_addr.to_string();
    
    // Parse peer address
    let attrs = parse_attributes(data)?;
    let peer_addr = attrs.get(&ATTR_XOR_PEER_ADDRESS);
    
    if peer_addr.is_none() {
        return Ok(());
    }
    
    let peer_ip = parse_xor_address(peer_addr.unwrap(), &data[8..20])?;
    
    let mut allocs = allocations.write().await;
    if let Some(alloc) = allocs.get_mut(&client_key) {
        // Add permission (expires in 5 minutes)
        alloc.permissions.insert(
            peer_ip.ip().to_string(),
            Instant::now() + Duration::from_secs(300)
        );
        
        // Build success response
        let response = build_create_permission_response(transaction_id);
        socket.send_to(&response, src_addr).await?;
        
        debug!("TURN: Permission created for {} -> {}", src_addr, peer_ip);
    }
    
    Ok(())
}

/// Handle Send Indication
async fn handle_send_indication(
    data: &[u8],
    src_addr: SocketAddr,
    allocations: &Arc<RwLock<HashMap<String, Allocation>>>,
) -> anyhow::Result<()> {
    let client_key = src_addr.to_string();
    
    // Parse attributes
    let attrs = parse_attributes(data)?;
    let peer_addr = attrs.get(&ATTR_XOR_PEER_ADDRESS);
    let send_data = attrs.get(&ATTR_DATA);
    
    if peer_addr.is_none() || send_data.is_none() {
        return Ok(());
    }
    
    let peer = parse_xor_address(peer_addr.unwrap(), &data[8..20])?;
    
    let allocs = allocations.read().await;
    if let Some(alloc) = allocs.get(&client_key) {
        // Check permission
        if let Some(expiry) = alloc.permissions.get(&peer.ip().to_string()) {
            if Instant::now() < *expiry {
                // Send data to peer
                alloc.relay_socket.send_to(send_data.unwrap(), peer).await?;
                debug!("TURN: Relayed data from {} to {}", src_addr, peer);
            }
        }
    }
    
    Ok(())
}

/// Handle Channel Bind Request
async fn handle_channel_bind(
    socket: &UdpSocket,
    data: &[u8],
    src_addr: SocketAddr,
    transaction_id: &[u8],
    allocations: &Arc<RwLock<HashMap<String, Allocation>>>,
) -> anyhow::Result<()> {
    let client_key = src_addr.to_string();
    
    // Parse attributes
    let attrs = parse_attributes(data)?;
    let channel_num = attrs.get(&ATTR_CHANNEL_NUMBER);
    let peer_addr = attrs.get(&ATTR_XOR_PEER_ADDRESS);
    
    if channel_num.is_none() || peer_addr.is_none() {
        return Ok(());
    }
    
    let channel = u16::from_be_bytes([channel_num.unwrap()[0], channel_num.unwrap()[1]]);
    let peer = parse_xor_address(peer_addr.unwrap(), &data[8..20])?;
    
    let mut allocs = allocations.write().await;
    if let Some(alloc) = allocs.get_mut(&client_key) {
        alloc.channels.insert(channel, peer);
        
        // Build success response
        let response = build_channel_bind_response(transaction_id);
        socket.send_to(&response, src_addr).await?;
        
        debug!("TURN: Channel {} bound to {} for {}", channel, peer, src_addr);
    }
    
    Ok(())
}

/// Relay incoming data from peers to client
async fn relay_incoming_data(
    relay_socket: Arc<UdpSocket>,
    main_socket: UdpSocket,
    client_addr: SocketAddr,
    allocations: Arc<RwLock<HashMap<String, Allocation>>>,
) {
    let mut buf = [0u8; 2048];
    let client_key = client_addr.to_string();
    
    loop {
        match relay_socket.recv_from(&mut buf).await {
            Ok((len, peer_addr)) => {
                // Check if allocation still exists
                let allocs = allocations.read().await;
                if let Some(alloc) = allocs.get(&client_key) {
                    // Check permission
                    if let Some(expiry) = alloc.permissions.get(&peer_addr.ip().to_string()) {
                        if Instant::now() < *expiry {
                            // Build Data Indication
                            let indication = build_data_indication(peer_addr, &buf[..len]);
                            if let Ok(ind) = indication {
                                let _ = main_socket.send_to(&ind, client_addr).await;
                            }
                        }
                    }
                } else {
                    // Allocation expired
                    break;
                }
            }
            Err(_) => break,
        }
    }
}

/// Parse STUN attributes
fn parse_attributes(data: &[u8]) -> anyhow::Result<HashMap<u16, Vec<u8>>> {
    let mut attrs = HashMap::new();
    
    if data.len() < 20 {
        return Ok(attrs);
    }
    
    let msg_len = u16::from_be_bytes([data[2], data[3]]) as usize;
    let mut offset = 20;
    
    while offset + 4 <= 20 + msg_len && offset + 4 <= data.len() {
        let attr_type = u16::from_be_bytes([data[offset], data[offset + 1]]);
        let attr_len = u16::from_be_bytes([data[offset + 2], data[offset + 3]]) as usize;
        
        if offset + 4 + attr_len > data.len() {
            break;
        }
        
        let value = data[offset + 4..offset + 4 + attr_len].to_vec();
        attrs.insert(attr_type, value);
        
        // 4-byte alignment
        offset += 4 + attr_len + (4 - (attr_len % 4)) % 4;
    }
    
    Ok(attrs)
}

/// Parse XOR-MAPPED-ADDRESS or XOR-PEER-ADDRESS
fn parse_xor_address(data: &[u8], transaction_id: &[u8]) -> anyhow::Result<SocketAddr> {
    if data.len() < 8 {
        anyhow::bail!("Invalid XOR address");
    }
    
    let family = data[1];
    let xor_port = u16::from_be_bytes([data[2], data[3]]);
    let port = xor_port ^ ((MAGIC_COOKIE >> 16) as u16);
    
    match family {
        0x01 => {
            // IPv4
            let magic_bytes = MAGIC_COOKIE.to_be_bytes();
            let ip = std::net::Ipv4Addr::new(
                data[4] ^ magic_bytes[0],
                data[5] ^ magic_bytes[1],
                data[6] ^ magic_bytes[2],
                data[7] ^ magic_bytes[3],
            );
            Ok(SocketAddr::new(std::net::IpAddr::V4(ip), port))
        }
        0x02 => {
            // IPv6
            if data.len() < 20 {
                anyhow::bail!("Invalid IPv6 XOR address");
            }
            let magic_bytes = MAGIC_COOKIE.to_be_bytes();
            let mut ip_bytes = [0u8; 16];
            for i in 0..4 {
                ip_bytes[i] = data[4 + i] ^ magic_bytes[i];
            }
            for i in 4..16 {
                ip_bytes[i] = data[4 + i] ^ transaction_id[i - 4];
            }
            let ip = std::net::Ipv6Addr::from(ip_bytes);
            Ok(SocketAddr::new(std::net::IpAddr::V6(ip), port))
        }
        _ => anyhow::bail!("Unknown address family"),
    }
}

/// Generate a random nonce
fn generate_nonce() -> String {
    use rand::Rng;
    let mut rng = rand::thread_rng();
    let bytes: [u8; 16] = rng.gen();
    hex::encode(bytes)
}

/// Build STUN Binding Response (same as STUN server)
fn build_binding_response(transaction_id: &[u8], mapped_addr: SocketAddr) -> anyhow::Result<Vec<u8>> {
    let mut response = Vec::with_capacity(64);
    
    let xor_mapped_attr = build_xor_mapped_address(mapped_addr, transaction_id);
    let software_attr = build_software_attribute();
    let attrs_len = xor_mapped_attr.len() + software_attr.len();

    response.extend_from_slice(&BINDING_RESPONSE.to_be_bytes());
    response.extend_from_slice(&(attrs_len as u16).to_be_bytes());
    response.extend_from_slice(&MAGIC_COOKIE.to_be_bytes());
    response.extend_from_slice(transaction_id);
    response.extend_from_slice(&xor_mapped_attr);
    response.extend_from_slice(&software_attr);

    Ok(response)
}

/// Build Allocate Response
fn build_allocate_response(
    transaction_id: &[u8],
    mapped_addr: SocketAddr,
    relay_addr: SocketAddr,
) -> anyhow::Result<Vec<u8>> {
    let mut response = Vec::with_capacity(128);
    
    let xor_mapped = build_xor_mapped_address(mapped_addr, transaction_id);
    let xor_relayed = build_xor_relayed_address(relay_addr, transaction_id);
    let lifetime = build_lifetime_attribute(DEFAULT_LIFETIME);
    let software = build_software_attribute();
    
    let attrs_len = xor_mapped.len() + xor_relayed.len() + lifetime.len() + software.len();

    response.extend_from_slice(&ALLOCATE_RESPONSE.to_be_bytes());
    response.extend_from_slice(&(attrs_len as u16).to_be_bytes());
    response.extend_from_slice(&MAGIC_COOKIE.to_be_bytes());
    response.extend_from_slice(transaction_id);
    response.extend_from_slice(&xor_mapped);
    response.extend_from_slice(&xor_relayed);
    response.extend_from_slice(&lifetime);
    response.extend_from_slice(&software);

    Ok(response)
}

/// Build Challenge Response (401)
fn build_challenge_response(transaction_id: &[u8], realm: &str, nonce: &str) -> Vec<u8> {
    let mut response = Vec::with_capacity(128);
    
    let error_attr = build_error_attribute(ERROR_UNAUTHORIZED, "Unauthorized");
    let realm_attr = build_realm_attribute(realm);
    let nonce_attr = build_nonce_attribute(nonce);
    
    let attrs_len = error_attr.len() + realm_attr.len() + nonce_attr.len();

    response.extend_from_slice(&ALLOCATE_ERROR_RESPONSE.to_be_bytes());
    response.extend_from_slice(&(attrs_len as u16).to_be_bytes());
    response.extend_from_slice(&MAGIC_COOKIE.to_be_bytes());
    response.extend_from_slice(transaction_id);
    response.extend_from_slice(&error_attr);
    response.extend_from_slice(&realm_attr);
    response.extend_from_slice(&nonce_attr);

    response
}

/// Build Error Response
fn build_error_response(transaction_id: &[u8], code: u16, reason: &str) -> Vec<u8> {
    let mut response = Vec::with_capacity(64);
    
    let error_attr = build_error_attribute(code, reason);
    let attrs_len = error_attr.len();

    response.extend_from_slice(&ALLOCATE_ERROR_RESPONSE.to_be_bytes());
    response.extend_from_slice(&(attrs_len as u16).to_be_bytes());
    response.extend_from_slice(&MAGIC_COOKIE.to_be_bytes());
    response.extend_from_slice(transaction_id);
    response.extend_from_slice(&error_attr);

    response
}

/// Build Refresh Response
fn build_refresh_response(transaction_id: &[u8], lifetime: u32) -> Vec<u8> {
    let mut response = Vec::with_capacity(64);
    
    let lifetime_attr = build_lifetime_attribute(lifetime);
    let attrs_len = lifetime_attr.len();

    response.extend_from_slice(&REFRESH_RESPONSE.to_be_bytes());
    response.extend_from_slice(&(attrs_len as u16).to_be_bytes());
    response.extend_from_slice(&MAGIC_COOKIE.to_be_bytes());
    response.extend_from_slice(transaction_id);
    response.extend_from_slice(&lifetime_attr);

    response
}

/// Build Create Permission Response
fn build_create_permission_response(transaction_id: &[u8]) -> Vec<u8> {
    let mut response = Vec::with_capacity(32);

    response.extend_from_slice(&CREATE_PERMISSION_RESPONSE.to_be_bytes());
    response.extend_from_slice(&0u16.to_be_bytes()); // No attributes
    response.extend_from_slice(&MAGIC_COOKIE.to_be_bytes());
    response.extend_from_slice(transaction_id);

    response
}

/// Build Channel Bind Response
fn build_channel_bind_response(transaction_id: &[u8]) -> Vec<u8> {
    let mut response = Vec::with_capacity(32);

    response.extend_from_slice(&CHANNEL_BIND_RESPONSE.to_be_bytes());
    response.extend_from_slice(&0u16.to_be_bytes()); // No attributes
    response.extend_from_slice(&MAGIC_COOKIE.to_be_bytes());
    response.extend_from_slice(transaction_id);

    response
}

/// Build Data Indication
fn build_data_indication(peer_addr: SocketAddr, data: &[u8]) -> anyhow::Result<Vec<u8>> {
    use rand::Rng;
    
    let mut indication = Vec::with_capacity(32 + data.len());
    
    // Generate random transaction ID
    let mut rng = rand::thread_rng();
    let transaction_id: [u8; 12] = rng.gen();
    
    let peer_attr = build_xor_peer_address(peer_addr, &transaction_id);
    let data_attr = build_data_attribute(data);
    
    let attrs_len = peer_attr.len() + data_attr.len();

    indication.extend_from_slice(&DATA_INDICATION.to_be_bytes());
    indication.extend_from_slice(&(attrs_len as u16).to_be_bytes());
    indication.extend_from_slice(&MAGIC_COOKIE.to_be_bytes());
    indication.extend_from_slice(&transaction_id);
    indication.extend_from_slice(&peer_attr);
    indication.extend_from_slice(&data_attr);

    Ok(indication)
}

/// Build XOR-MAPPED-ADDRESS attribute
fn build_xor_mapped_address(addr: SocketAddr, transaction_id: &[u8]) -> Vec<u8> {
    build_xor_address_attribute(ATTR_XOR_MAPPED_ADDRESS, addr, transaction_id)
}

/// Build XOR-RELAYED-ADDRESS attribute
fn build_xor_relayed_address(addr: SocketAddr, transaction_id: &[u8]) -> Vec<u8> {
    build_xor_address_attribute(ATTR_XOR_RELAYED_ADDRESS, addr, transaction_id)
}

/// Build XOR-PEER-ADDRESS attribute
fn build_xor_peer_address(addr: SocketAddr, transaction_id: &[u8]) -> Vec<u8> {
    build_xor_address_attribute(ATTR_XOR_PEER_ADDRESS, addr, transaction_id)
}

/// Build XOR address attribute
fn build_xor_address_attribute(attr_type: u16, addr: SocketAddr, transaction_id: &[u8]) -> Vec<u8> {
    let mut attr = Vec::with_capacity(12);

    match addr {
        SocketAddr::V4(v4) => {
            attr.extend_from_slice(&attr_type.to_be_bytes());
            attr.extend_from_slice(&8u16.to_be_bytes()); // Length
            attr.push(0x00); // Reserved
            attr.push(0x01); // IPv4
            
            let port = v4.port() ^ ((MAGIC_COOKIE >> 16) as u16);
            attr.extend_from_slice(&port.to_be_bytes());
            
            let ip_bytes = v4.ip().octets();
            let magic_bytes = MAGIC_COOKIE.to_be_bytes();
            for i in 0..4 {
                attr.push(ip_bytes[i] ^ magic_bytes[i]);
            }
        }
        SocketAddr::V6(v6) => {
            attr.extend_from_slice(&attr_type.to_be_bytes());
            attr.extend_from_slice(&20u16.to_be_bytes()); // Length
            attr.push(0x00); // Reserved
            attr.push(0x02); // IPv6
            
            let port = v6.port() ^ ((MAGIC_COOKIE >> 16) as u16);
            attr.extend_from_slice(&port.to_be_bytes());
            
            let ip_bytes = v6.ip().octets();
            let magic_bytes = MAGIC_COOKIE.to_be_bytes();
            for i in 0..4 {
                attr.push(ip_bytes[i] ^ magic_bytes[i]);
            }
            for i in 4..16 {
                attr.push(ip_bytes[i] ^ transaction_id[i - 4]);
            }
        }
    }

    attr
}

/// Build SOFTWARE attribute
fn build_software_attribute() -> Vec<u8> {
    let software = b"EasyRemote TURN Server";
    let mut attr = Vec::with_capacity(4 + software.len() + 4);

    attr.extend_from_slice(&ATTR_SOFTWARE.to_be_bytes());
    attr.extend_from_slice(&(software.len() as u16).to_be_bytes());
    attr.extend_from_slice(software);
    
    // Padding
    let padding = (4 - (software.len() % 4)) % 4;
    for _ in 0..padding {
        attr.push(0x00);
    }

    attr
}

/// Build LIFETIME attribute
fn build_lifetime_attribute(lifetime: u32) -> Vec<u8> {
    let mut attr = Vec::with_capacity(8);
    attr.extend_from_slice(&ATTR_LIFETIME.to_be_bytes());
    attr.extend_from_slice(&4u16.to_be_bytes());
    attr.extend_from_slice(&lifetime.to_be_bytes());
    attr
}

/// Build ERROR-CODE attribute
fn build_error_attribute(code: u16, reason: &str) -> Vec<u8> {
    let reason_bytes = reason.as_bytes();
    let value_len = 4 + reason_bytes.len();
    let padded_len = value_len + (4 - (value_len % 4)) % 4;
    
    let mut attr = Vec::with_capacity(4 + padded_len);
    attr.extend_from_slice(&ATTR_ERROR_CODE.to_be_bytes());
    attr.extend_from_slice(&(value_len as u16).to_be_bytes());
    
    // Reserved (2 bytes) + Class (1 byte) + Number (1 byte)
    attr.push(0x00);
    attr.push(0x00);
    attr.push((code / 100) as u8);
    attr.push((code % 100) as u8);
    attr.extend_from_slice(reason_bytes);
    
    // Padding
    let padding = (4 - (value_len % 4)) % 4;
    for _ in 0..padding {
        attr.push(0x00);
    }

    attr
}

/// Build REALM attribute
fn build_realm_attribute(realm: &str) -> Vec<u8> {
    let realm_bytes = realm.as_bytes();
    let mut attr = Vec::with_capacity(4 + realm_bytes.len() + 4);
    
    attr.extend_from_slice(&ATTR_REALM.to_be_bytes());
    attr.extend_from_slice(&(realm_bytes.len() as u16).to_be_bytes());
    attr.extend_from_slice(realm_bytes);
    
    // Padding
    let padding = (4 - (realm_bytes.len() % 4)) % 4;
    for _ in 0..padding {
        attr.push(0x00);
    }

    attr
}

/// Build NONCE attribute
fn build_nonce_attribute(nonce: &str) -> Vec<u8> {
    let nonce_bytes = nonce.as_bytes();
    let mut attr = Vec::with_capacity(4 + nonce_bytes.len() + 4);
    
    attr.extend_from_slice(&ATTR_NONCE.to_be_bytes());
    attr.extend_from_slice(&(nonce_bytes.len() as u16).to_be_bytes());
    attr.extend_from_slice(nonce_bytes);
    
    // Padding
    let padding = (4 - (nonce_bytes.len() % 4)) % 4;
    for _ in 0..padding {
        attr.push(0x00);
    }

    attr
}

/// Build DATA attribute
fn build_data_attribute(data: &[u8]) -> Vec<u8> {
    let mut attr = Vec::with_capacity(4 + data.len() + 4);
    
    attr.extend_from_slice(&ATTR_DATA.to_be_bytes());
    attr.extend_from_slice(&(data.len() as u16).to_be_bytes());
    attr.extend_from_slice(data);
    
    // Padding
    let padding = (4 - (data.len() % 4)) % 4;
    for _ in 0..padding {
        attr.push(0x00);
    }

    attr
}
