use core::{ffi::c_char, ptr::NonNull};

use crate::{
    error::{CIntZeroResult, CUsizeResult, OptionExt},
    headers::{errno::Errno, stdlib::MB_CUR_MAX, wchar::imp},
    types::wchar_t,
    util::PointerExt,
};

use super::mbstate_t;

static mut GLOBAL: mbstate_t = mbstate_t { __dummy: 0 };

#[no_mangle]
unsafe extern "C" fn mbrlen(_str: *const c_char, _n: usize, _state: *mut mbstate_t) -> usize {
    todo!()
}

#[no_mangle]
unsafe extern "C" fn wcrtomb(dst: *mut c_char, wc: wchar_t, state: *mut mbstate_t) -> CUsizeResult {
    let _state = match state.as_mut() {
        Some(state) => state,
        #[allow(static_mut_refs)]
        None => &mut GLOBAL,
    };
    // dst must be at least MB_CUR_MAX (4)
    let dst = dst.cast::<u8>().ensure_slice_mut(MB_CUR_MAX as usize);

    // TODO EILSEQ
    let ch = char::from_u32(wc as u32).e_ok_or(Errno::EINVAL)?;

    let len = ch.encode_utf8(dst).len();
    CUsizeResult::success(len)
}

#[no_mangle]
pub unsafe extern "C" fn mbrtowc(
    dst: *mut wchar_t,
    src: *const c_char,
    n: usize,
    state: *mut mbstate_t,
) -> CUsizeResult {
    let state = match state.as_mut() {
        Some(state) => state,
        #[allow(static_mut_refs)]
        None => &mut GLOBAL,
    };

    let res = match NonNull::new(src.cast_mut()) {
        Some(src) => imp::mbrtowc(dst, src, n, state)?,
        None => {
            let x: [c_char; 1] = [0];
            imp::mbrtowc(dst, NonNull::from_ref(&x[0]), 1, state)?
        }
    };

    CUsizeResult::success(res)
}

#[no_mangle]
unsafe extern "C" fn mbsinit(_state: *const mbstate_t) -> CIntZeroResult {
    CIntZeroResult::SUCCESS
}

#[no_mangle]
unsafe extern "C" fn mbsnrtowcs(
    _dst: *mut wchar_t,
    _bufs: *const *const c_char,
    _n: usize,
    _len: usize,
    _state: *mut mbstate_t,
) -> usize {
    todo!()
}

#[no_mangle]
unsafe extern "C" fn mbsrtowcs(
    _dst: *mut wchar_t,
    _bufs: *const *const c_char,
    _n: usize,
    _state: *mut mbstate_t,
) -> usize {
    todo!()
}

#[no_mangle]
unsafe extern "C" fn wcsnrtombs(
    _dst: *mut c_char,
    _bufs: *const *const wchar_t,
    _n: usize,
    _len: usize,
    _state: *mut mbstate_t,
) -> usize {
    todo!()
}

#[no_mangle]
unsafe extern "C" fn wcsrtombs(
    _dst: *mut c_char,
    _bufs: *const *const wchar_t,
    _n: usize,
    _state: *mut mbstate_t,
) -> usize {
    todo!()
}
