Documentation
use core::mem;
use core::net::{Ipv4Addr, Ipv6Addr, SocketAddr, SocketAddrV4, SocketAddrV6};
use core::ptr;

// Linux socket address structures
#[repr(C)]
#[derive(Copy, Clone)]
pub struct sockaddr {
    pub sa_family: u16,
    pub sa_data: [u8; 14],
}

#[repr(C)]
#[derive(Copy, Clone)]
pub struct sockaddr_in {
    pub sin_family: u16,
    pub sin_port: u16,
    pub sin_addr: in_addr,
    pub sin_zero: [u8; 8],
}

#[repr(C)]
#[derive(Copy, Clone)]
pub struct in_addr {
    pub s_addr: u32,
}

#[repr(C)]
#[derive(Copy, Clone)]
pub struct sockaddr_in6 {
    pub sin6_family: u16,
    pub sin6_port: u16,
    pub sin6_flowinfo: u32,
    pub sin6_addr: in6_addr,
    pub sin6_scope_id: u32,
}

#[repr(C)]
#[derive(Copy, Clone)]
pub struct in6_addr {
    pub s6_addr: [u8; 16],
}

// Socket address storage that can hold any address type
#[repr(C)]
#[derive(Copy, Clone)]
pub union SocketAddrStorage {
    pub sa: sockaddr,
    pub sin: sockaddr_in,
    pub sin6: sockaddr_in6,
    pub storage: [u8; 128], // Ensure enough space
}

// Constants
pub const AF_INET: u16 = 2;
pub const AF_INET6: u16 = 10;

impl SocketAddrStorage {
    pub const fn new() -> Self {
        Self { storage: [0; 128] }
    }

    pub fn from_socket_addr(addr: SocketAddr) -> (Self, usize) {
        let mut storage = Self::new();

        match addr {
            SocketAddr::V4(v4) => {
                let sin = sockaddr_in {
                    sin_family: AF_INET,
                    sin_port: v4.port().to_be(),
                    sin_addr: in_addr {
                        s_addr: u32::from_ne_bytes(v4.ip().octets()),
                    },
                    sin_zero: [0; 8],
                };
                storage.sin = sin;
                (storage, mem::size_of::<sockaddr_in>())
            }
            SocketAddr::V6(v6) => {
                let sin6 = sockaddr_in6 {
                    sin6_family: AF_INET6,
                    sin6_port: v6.port().to_be(),
                    sin6_flowinfo: v6.flowinfo(),
                    sin6_addr: in6_addr {
                        s6_addr: v6.ip().octets(),
                    },
                    sin6_scope_id: v6.scope_id(),
                };
                storage.sin6 = sin6;
                (storage, mem::size_of::<sockaddr_in6>())
            }
        }
    }

    pub fn to_socket_addr(&self, len: usize) -> Option<SocketAddr> {
        unsafe {
            match self.sa.sa_family {
                AF_INET if len >= mem::size_of::<sockaddr_in>() => {
                    let sin = &self.sin;
                    let ip = Ipv4Addr::from(sin.sin_addr.s_addr.to_ne_bytes());
                    let port = u16::from_be(sin.sin_port);
                    Some(SocketAddr::V4(SocketAddrV4::new(ip, port)))
                }
                AF_INET6 if len >= mem::size_of::<sockaddr_in6>() => {
                    let sin6 = &self.sin6;
                    let ip = Ipv6Addr::from(sin6.sin6_addr.s6_addr);
                    let port = u16::from_be(sin6.sin6_port);
                    Some(SocketAddr::V6(SocketAddrV6::new(
                        ip,
                        port,
                        sin6.sin6_flowinfo,
                        sin6.sin6_scope_id,
                    )))
                }
                _ => None,
            }
        }
    }

    pub fn as_ptr(&self) -> *const sockaddr {
        unsafe { &self.sa as *const sockaddr }
    }

    pub fn as_mut_ptr(&mut self) -> *mut sockaddr {
        unsafe { &mut self.sa as *mut sockaddr }
    }
}

// Message header for sendmsg/recvmsg operations
#[repr(C)]
pub struct MsgHdr {
    pub msg_name: *mut u8,     // Socket address
    pub msg_namelen: u32,      // Length of address
    pub msg_iov: *mut IoVec,   // Scatter/gather array
    pub msg_iovlen: usize,     // Elements in msg_iov
    pub msg_control: *mut u8,  // Ancillary data
    pub msg_controllen: usize, // Ancillary data buffer len
    pub msg_flags: i32,        // Flags on received message
}

// IO vector for scatter-gather operations
#[repr(C)]
pub struct IoVec {
    pub iov_base: *mut u8,
    pub iov_len: usize,
}

impl MsgHdr {
    pub fn new() -> Self {
        Self {
            msg_name: ptr::null_mut(),
            msg_namelen: 0,
            msg_iov: ptr::null_mut(),
            msg_iovlen: 0,
            msg_control: ptr::null_mut(),
            msg_controllen: 0,
            msg_flags: 0,
        }
    }

    pub fn with_addr_and_iov(
        addr: &mut SocketAddrStorage,
        addr_len: &mut u32,
        iov: &mut [IoVec],
    ) -> Self {
        Self {
            msg_name: addr as *mut _ as *mut u8,
            msg_namelen: *addr_len,
            msg_iov: iov.as_mut_ptr(),
            msg_iovlen: iov.len(),
            msg_control: ptr::null_mut(),
            msg_controllen: 0,
            msg_flags: 0,
        }
    }
}

// Helper to create IPv6 socket address that supports IPv4-mapped addresses
pub fn socket_addr_to_dual_stack(addr: SocketAddr) -> (SocketAddrStorage, usize) {
    match addr {
        SocketAddr::V4(v4) => {
            // Convert IPv4 to IPv4-mapped IPv6 address
            let octets = v4.ip().octets();
            let ipv6_mapped = Ipv6Addr::new(
                0,
                0,
                0,
                0,
                0,
                0xffff,
                u16::from_be_bytes([octets[0], octets[1]]),
                u16::from_be_bytes([octets[2], octets[3]]),
            );
            let v6_addr = SocketAddrV6::new(ipv6_mapped, v4.port(), 0, 0);
            SocketAddrStorage::from_socket_addr(SocketAddr::V6(v6_addr))
        }
        SocketAddr::V6(_) => SocketAddrStorage::from_socket_addr(addr),
    }
}