use core::ffi::{c_int, c_void};

use crate::error::CIntZeroResult;

use super::{sockaddr, socklen_t};

#[no_mangle]
unsafe extern "C" fn getsockopt(
    _fd: c_int,
    _level: c_int,
    _name: c_int,
    _value: *mut c_void,
    _size: *mut socklen_t,
) -> CIntZeroResult {
    todo!()
    // if value.is_null() || size.is_null() {
    //     error::set_errno(Errno::EINVAL);
    //     return CIntZeroResult::ERROR;
    // }

    // let space = *size;
    // let fd = RawFd::e_try_from(fd)?;

    // *size = match (level, name) {
    //     (SOL_SOCKET, SO_RCVTIMEO) if space >= size_of::<timeval>() => {
    //         let timeout =
    //             rt::get_socket_option!(fd, options::RecvTimeout).e_map_err(Errno::from)?;
    //         let value = value.cast::<timeval>();
    //         match timeout {
    //             Some(timeout) => value.write(timeval::from(timeout)),
    //             None => value.write(timeval::zero()),
    //         }
    //         size_of::<timeval>()
    //     }
    //     (SOL_SOCKET, SO_SNDTIMEO) => {
    //         let timeout =
    //             rt::get_socket_option!(fd, options::SendTimeout).e_map_err(Errno::from)?;
    //         let value = value.cast::<timeval>();
    //         match timeout {
    //             Some(timeout) => value.write(timeval::from(timeout)),
    //             None => value.write(timeval::zero()),
    //         }
    //         size_of::<timeval>()
    //     }
    //     (SOL_SOCKET, SO_BROADCAST) => {
    //         let broadcast =
    //             rt::get_socket_option!(fd, options::Broadcast).e_map_err(Errno::from)?;
    //         let value = value.cast::<c_int>();
    //         value.write(broadcast as c_int);
    //         size_of::<c_int>()
    //     }
    //     (IPPROTO_TCP, TCP_NODELAY) => {
    //         let broadcast = rt::get_socket_option!(fd, options::NoDelay).e_map_err(Errno::from)?;
    //         let value = value.cast::<c_int>();
    //         value.write(broadcast as c_int);
    //         size_of::<c_int>()
    //     }
    //     _ => {
    //         yggdrasil_rt::debug_trace!("Unhandled getsockopt({level}, {name}, {space})");
    //         error::set_errno(Errno::EINVAL);
    //         return CIntZeroResult::ERROR;
    //     }
    // };

    // CIntZeroResult::SUCCESS
}

#[no_mangle]
unsafe extern "C" fn setsockopt(
    _fd: c_int,
    _level: c_int,
    _name: c_int,
    _value: *const c_void,
    _size: socklen_t,
) -> CIntZeroResult {
    todo!()
    // if value.is_null() {
    //     error::set_errno(Errno::EINVAL);
    //     return CIntZeroResult::ERROR;
    // }

    // let fd = RawFd::e_try_from(fd)?;

    // match (level, name) {
    //     (SOL_SOCKET, SO_RCVTIMEO) if size == size_of::<timeval>() => {
    //         let timeval = *value.cast::<timeval>();
    //         let timeout = timeval.to_duration_opt();
    //         rt::set_socket_option::<options::RecvTimeout>(fd, &timeout).e_map_err(Errno::from)?;
    //     }
    //     (SOL_SOCKET, SO_SNDTIMEO) if size == size_of::<timeval>() => {
    //         let timeval = *value.cast::<timeval>();
    //         let timeout = timeval.to_duration_opt();
    //         rt::set_socket_option::<options::SendTimeout>(fd, &timeout).e_map_err(Errno::from)?;
    //     }
    //     (SOL_SOCKET, SO_BROADCAST) if size == size_of::<c_int>() => {
    //         let value = *value.cast::<c_int>() != 0;
    //         rt::set_socket_option::<options::Broadcast>(fd, &value).e_map_err(Errno::from)?;
    //     }
    //     (IPPROTO_TCP, TCP_NODELAY) if size == size_of::<c_int>() => {
    //         let value = *value.cast::<c_int>() != 0;
    //         rt::set_socket_option::<options::NoDelay>(fd, &value).e_map_err(Errno::from)?;
    //     }
    //     _ => {
    //         yggdrasil_rt::debug_trace!("Unhandled setsockopt({level}, {name}, {size})");
    //         error::set_errno(Errno::EINVAL);
    //         return CIntZeroResult::ERROR;
    //     }
    // }

    // CIntZeroResult::SUCCESS
}

#[no_mangle]
unsafe extern "C" fn getpeername(
    _fd: c_int,
    _remote: *mut sockaddr,
    _len: *mut socklen_t,
) -> CIntZeroResult {
    todo!()
    // if remote.is_null() || len.is_null() {
    //     error::set_errno(Errno::EINVAL);
    //     return CIntZeroResult::ERROR;
    // }

    // let fd = RawFd::e_try_from(fd)?;
    // let address = rt::get_socket_option!(fd, options::PeerAddress).e_map_err(Errno::from)?;
    // let address = address.e_ok_or(Errno::ENOTCONN)?;

    // *len = address.to_c(remote, *len)?;
    // CIntZeroResult::SUCCESS
}

#[no_mangle]
unsafe extern "C" fn getsockname(
    _fd: c_int,
    _local: *mut sockaddr,
    _len: *mut socklen_t,
) -> CIntZeroResult {
    todo!()
    // if local.is_null() || len.is_null() {
    //     error::set_errno(Errno::EINVAL);
    //     return CIntZeroResult::ERROR;
    // }

    // let fd = RawFd::e_try_from(fd)?;
    // let address = rt::get_socket_option!(fd, options::LocalAddress).e_map_err(Errno::from)?;
    // let address = address.e_ok_or(Errno::ENOTCONN)?;

    // *len = address.to_c(local, *len)?;
    // CIntZeroResult::SUCCESS
}
