#![allow(unused)]

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

unsafe extern "C" {
    fn malloc(size: c_size_t) -> *mut c_void;
}

#[unsafe(no_mangle)]
unsafe extern "C" fn strpbrk(s: *const c_char, accept: *const c_char) -> *mut c_char {
    todo!()
}

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

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

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

#[unsafe(no_mangle)]
unsafe extern "C" fn vasprintf(strp: *mut *mut c_char, fmt: *const c_char, ap: VaList) -> c_int {
    todo!()
}

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

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

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

#[unsafe(no_mangle)]
unsafe extern "C" fn strerror(errnum: c_int) -> *mut c_char {
    todo!()
}

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

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

#[unsafe(no_mangle)]
unsafe extern "C" fn opendir(name: *const c_char) -> *mut DIR {
    todo!()
}

#[unsafe(no_mangle)]
unsafe extern "C" fn readdir(dirp: *mut DIR) ->  *mut dirent {
    todo!()
}

#[unsafe(no_mangle)]
unsafe extern "C" fn closedir(dirp: *mut DIR) -> c_int {
    todo!()
}

#[unsafe(no_mangle)]
unsafe extern "C" fn 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!()
}

#[unsafe(no_mangle)]
unsafe extern "C" fn __getreent() -> *mut c_void /*struct _reent*/ {
    todo!()
}

#[allow(non_camel_case_types)]
#[allow(clippy::upper_case_acronyms)]
enum FILE {}

#[unsafe(no_mangle)]
unsafe extern "C" fn fprintf(
    stream: *mut FILE,
    format: *const c_char,
    ...
) -> c_int {
    todo!()
}

#[unsafe(no_mangle)]
unsafe extern "C" fn vfprintf(stream: *mut FILE, format: *const c_char, ap: VaList) -> c_int {
    todo!()
}

#[unsafe(no_mangle)]
unsafe extern "C" fn strtol(nptr: *const c_char, endptr: *mut *mut c_char, base: c_int) -> c_long {
    todo!()
}

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

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

#[unsafe(no_mangle)]
unsafe extern "C" fn fseek(
    stream: *mut FILE,
    offset: c_long,
    whence: c_int,
) -> c_int {
    todo!()
}

#[unsafe(no_mangle)]
unsafe extern "C" fn ftell(stream: *mut FILE) -> c_long {
    todo!()
}

#[unsafe(no_mangle)]
unsafe extern "C" fn fread(
    ptr: *mut c_void,
    size: c_size_t,
    nobj: c_size_t,
    stream: *mut FILE,
) -> c_size_t {
    todo!()
}

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

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

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

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

#[unsafe(no_mangle)]
unsafe extern "C" fn strndup(
    s: *const c_char,
    n: c_size_t,
) -> *mut c_char {
    let len = unsafe { strnlen(s, n) };
    let new = unsafe { malloc(len + 1) } as *mut c_char;

    if new.is_null() {
        return null_mut();
    }

    unsafe {
        *new.add(len) = b'\0';

        memcpy(new as *mut c_void, s as *const c_void, len) as *mut c_char
    }
}

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

#[unsafe(no_mangle)]
unsafe extern "C" fn memcpy(dest: *mut c_void, src: *const c_void, n: c_size_t) -> *mut c_void {
    todo!()
}

#[unsafe(no_mangle)]
unsafe extern "C" fn strnlen(s: *const c_char, maxlen: c_size_t) -> c_size_t {
  let found: *const c_char = unsafe { memchr(s as *const c_void, b'\0' as c_int, maxlen) } as *const c_char;
  if !found.is_null() { unsafe { found.offset_from(s) as c_size_t } } else { maxlen }
}

#[unsafe(no_mangle)]
unsafe extern "C" fn memchr(s: *const c_void, c: c_int, n: c_size_t) -> *mut c_void {
    let mut s = s as *const c_uchar;
    let c = c as c_uchar;

    for _ in 0..n {
        unsafe {
            if *s == c {
                return s as *mut c_void;
            }

            s = s.add(1);
        }
    }

    null_mut()
}

#[unsafe(no_mangle)]
unsafe extern "C" fn __wrap_strncmp(
    s1: *const c_char,
    s2: *const c_char,
    n: c_size_t,
) -> c_int {
    unsafe {
        for i in 0..n as isize {
            let s1_i = s1.offset(i);
            let s2_i = s2.offset(i);

            let val = *s1_i as c_int - *s2_i as c_int;
            if val != 0 || *s1_i == 0 {
                return val;
            }
        }
        0
    }
}
