#![allow(unused_variables)]

use core::{
    ffi::{c_char, c_int, c_long, c_longlong, c_size_t, c_void},
    ptr::null_mut,
};

use inout::file::{FILE, STDERR, STDIN, STDOUT};

pub mod alloc;
pub mod crypto;
pub mod gcc_runtime;
pub mod inout;
pub mod string;
pub mod time;

#[allow(non_camel_case_types)]
pub type c_intmax_t = c_longlong;

#[unsafe(no_mangle)]
pub unsafe extern "C" fn __xkbc_imaxabs(j: c_intmax_t) -> c_intmax_t {
    todo!()
}

#[unsafe(no_mangle)]
pub unsafe extern "C" fn __xkbc_eaccess(pathname: *const c_char, mode: c_int) -> c_int {
    todo!()
}

#[allow(non_camel_case_types)]
type stat = c_void; // Not implemented

#[unsafe(no_mangle)]
pub unsafe extern "C" fn __xkbc_stat(path: *const c_char, buf: *mut stat) -> c_int {
    todo!()
}

#[unsafe(no_mangle)]
pub unsafe extern "C" fn __xkbc___errno() -> *mut c_int {
    todo!()
}

#[unsafe(no_mangle)]
pub unsafe extern "C" fn __spre___errno() -> *mut c_int {
    unsafe { __xkbc___errno() }
}

#[unsafe(no_mangle)]
pub unsafe extern "C" fn __xkbc_qsort(
    base: *mut c_void,
    num: c_size_t,
    size: c_size_t,
    compar: Option<unsafe extern "C" fn(*const c_void, *const c_void) -> c_int>,
) {
    todo!()
}

/// An incomplete representation of Newlib's `struct _reent`.
/// https://github.com/bminor/newlib/blob/b41e3b652c4215556a62a2f47e8f8f11553fa550/newlib/libc/include/sys/reent.h#L580
#[repr(C)]
#[allow(non_camel_case_types)]
#[derive(Clone, Copy)]
pub struct _reent {
    _errno: c_int,
    _stdin: *mut FILE,
    _stdout: *mut FILE,
    _stderr: *mut FILE,
    // Rest unimplemented
}

#[unsafe(no_mangle)]
pub unsafe extern "C" fn __xkbc___getreent() -> *mut _reent {
    static mut REENT: [_reent; 2] = [_reent {
        _errno: 0,
        _stdin: STDIN,
        _stdout: STDOUT,
        _stderr: STDERR,
    }; 2];

    unsafe {
        let reent = &mut REENT[esp_hal::system::Cpu::current() as usize];
        reent as *mut _reent
    }
}

#[unsafe(no_mangle)]
pub unsafe extern "C" fn __spre___getreent() -> *mut _reent {
    unsafe { __xkbc___getreent() }
}

#[unsafe(no_mangle)]
pub unsafe extern "C" fn __xkbc_secure_getenv(name: *const c_char) -> *mut c_char {
    unsafe { __xkbc_getenv(name) }
}

#[unsafe(no_mangle)]
pub unsafe extern "C" fn __xkbc_getenv(name: *const c_char) -> *mut c_char {
    null_mut()
}

#[unsafe(no_mangle)]
pub unsafe extern "C" fn __xkbc_open(path: *const c_char, oflag: c_int, ...) -> c_int {
    todo!()
}

#[unsafe(no_mangle)]
pub unsafe extern "C" fn __xkbc_fstat(fildes: c_int, buf: *mut stat) -> c_int {
    todo!()
}

#[unsafe(no_mangle)]
pub unsafe extern "C" fn __xkbc_close(fd: c_int) -> c_int {
    todo!()
}

#[unsafe(no_mangle)]
pub unsafe extern "C" fn __xkbc_fdopen(fd: c_int, mode: *const c_char) -> *mut FILE {
    todo!()
}

#[unsafe(no_mangle)]
pub unsafe extern "C" fn __xkbc_labs(i: c_long) -> c_long {
    i.abs()
}

unsafe extern "C" {
    fn __assert_func(
        file: *const c_char,
        line: c_int,
        function: *const c_char,
        failedExpression: *const c_char,
    );
}

#[unsafe(no_mangle)]
pub unsafe extern "C" fn __xkbc___assert_func(
    file: *const c_char,
    line: c_int,
    function: *const c_char,
    failed_expression: *const c_char,
) {
    unsafe {
        __assert_func(file, line, function, failed_expression);
    }
}

#[unsafe(no_mangle)]
pub unsafe extern "C" fn __xkbc_atoi(s: *const c_char) -> c_int {
    todo!()
}

// A pointer to an array of character attributes.
// This is used by `isdigit()`, `isalpha()`, `isspace()`, etc.
#[unsafe(no_mangle)]
pub static __spre__ctype_: [c_char; 0] = [];

#[unsafe(no_mangle)]
pub unsafe extern "C" fn __spre_abort() -> ! {
    panic!("`abort()` called.")
}
