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

use crate::{
    allocator,
    error::{CPtrResult, OptionExt},
    headers::errno::Errno,
};

#[no_mangle]
unsafe extern "C" fn calloc(size: usize, nmemb: usize) -> CPtrResult<c_void> {
    let size = size.checked_mul(nmemb).e_ok_or(Errno::ENOMEM)?;
    let ptr = allocator::c_alloc(size, 16, true)?;
    CPtrResult::success(ptr)
}

#[no_mangle]
unsafe extern "C" fn free(ptr: *mut c_void) {
    if let Some(ptr) = NonNull::new(ptr) {
        allocator::c_free(ptr);
    }
}

#[no_mangle]
unsafe extern "C" fn malloc(size: usize) -> CPtrResult<c_void> {
    let ptr = allocator::c_alloc(size, 16, false)?;
    CPtrResult::success(ptr)
}

#[no_mangle]
unsafe extern "C" fn realloc(ptr: *mut c_void, size: usize) -> CPtrResult<c_void> {
    let old_ptr = NonNull::new(ptr);
    let new_ptr = allocator::c_realloc(old_ptr, size)?;
    CPtrResult::success(new_ptr)
}

// Aligned allocations

#[no_mangle]
unsafe extern "C" fn posix_memalign(
    _memptr: *mut *mut c_void,
    _alignment: usize,
    _size: usize,
) -> c_int {
    todo!()
}

#[no_mangle]
unsafe extern "C" fn aligned_alloc(align: usize, size: usize) -> CPtrResult<c_void> {
    if align > 16 {
        todo!()
    }
    malloc(size)
}
