#![no_std]
#![no_main]
#![feature(alloc_error_handler)]

extern crate alloc;
use alloc::string::String;
use alloc::format;

// ----------------------------------------------------------------------------
// 1. The Nervous System (FFI to Membrane)
// ----------------------------------------------------------------------------
extern "C" {
    fn socket(domain: i32, type_: i32, protocol: i32) -> i32;
    fn connect(fd: i32, addr: *const u8, len: i32) -> i32;
    fn write(fd: i32, buf: *const u8, count: usize) -> isize;
    fn sleep(seconds: u32);
    // We also need the allocator from libnexus (clib.c or libc.nim exports)
    fn malloc(size: usize) -> *mut u8;
    fn free(ptr: *mut u8);
}

// ----------------------------------------------------------------------------
// 2. The Stomach (Global Allocator)
// ----------------------------------------------------------------------------
struct NexusAllocator;

unsafe impl core::alloc::GlobalAlloc for NexusAllocator {
    unsafe fn alloc(&self, layout: core::alloc::Layout) -> *mut u8 {
        malloc(layout.size())
    }
    unsafe fn dealloc(&self, ptr: *mut u8, _layout: core::alloc::Layout) {
        free(ptr)
    }
}

#[global_allocator]
static ALLOCATOR: NexusAllocator = NexusAllocator;

#[alloc_error_handler]
fn alloc_error(_layout: core::alloc::Layout) -> ! {
    panic!("OOM");
}

// ----------------------------------------------------------------------------
// 3. The Voice (Panic Handler)
// ----------------------------------------------------------------------------
#[panic_handler]
fn panic(info: &core::panic::PanicInfo) -> ! {
    let msg = "RUST PANIC!\n";
    unsafe { write(1, msg.as_ptr(), msg.len()); }
    loop {}
}

// ----------------------------------------------------------------------------
// 4. The Astronaut (Main Logic)
// ----------------------------------------------------------------------------
// We need struct layouts for sockaddr if we want to be precise, 
// but for this test, we can use the raw bytes or simple C structs.
#[repr(C)]
struct SockAddrIn {
    sin_family: u16,
    sin_port: u16,
    sin_addr: u32, // 10.0.2.2 = 0x0202000A (Little Endian)
    zero: [u8; 8],
}

#[no_mangle]
pub extern "C" fn main() -> i32 {
    let msg = String::from("[Rust] Booting sequence...\n");
    unsafe { write(1, msg.as_ptr(), msg.len()); }

    let fd = unsafe { socket(2, 1, 0) }; // AF_INET, SOCK_STREAM
    if fd < 0 {
        let err = "[Rust] Socket failed\n";
        unsafe { write(1, err.as_ptr(), err.len()); }
        return 1;
    }

    // 10.0.2.2 = 0x0202000A
    // 8080 = 0x1F90 (Big Endian)
    let port_be: u16 = 8080u16.to_be(); 

    let addr_fixed = SockAddrIn {
        sin_family: 2,
        sin_port: port_be,
        sin_addr: 0x0202000A, 
        zero: [0; 8],
    };

    let hello = format!("[Rust] Hello from the Iron Lung! FD={}\n", fd);
    
    unsafe {
        let res = connect(fd, &addr_fixed as *const _ as *const u8, 16);
        if res < 0 {
            let fail = "[Rust] Connection Failed\n";
            write(1, fail.as_ptr(), fail.len());
        } else {
            write(fd, hello.as_ptr(), hello.len());
            let success = "[Rust] Payload Sent.\n";
            write(1, success.as_ptr(), success.len());
        }
    }

    loop { unsafe { sleep(1); } }
}
