// PTHREAD_BARRIER_SERIAL_THREAD

use core::{
    ffi::{c_int, c_uint},
    ptr::NonNull,
    sync::atomic::{self, Ordering},
};

use yggdrasil_rt::process::MutexOperation;

use crate::{
    error::{self, CIntZeroResult, CResult},
    headers::{
        errno::Errno,
        sys_types::{pthread_barrier_t, pthread_barrierattr_t},
    },
    util::PointerExt,
};

use super::PTHREAD_PROCESS_PRIVATE;

impl pthread_barrier_t {
    fn wait(&self) {
        // Fastpath
        if self.__state.fetch_add(1, Ordering::Release) >= self.__limit {
            self.signal();
            return;
        }

        loop {
            if self.check() {
                self.signal();
                return;
            }
            self.block();
        }
    }

    fn block(&self) {
        unsafe {
            yggdrasil_rt::sys::mutex(
                &self.__state,
                &MutexOperation::WaitUntilEqual(self.__limit, None),
            )
            .ok()
        };
    }

    fn signal(&self) {
        unsafe { yggdrasil_rt::sys::mutex(&self.__state, &MutexOperation::Wake(u32::MAX)).ok() };
    }

    fn check(&self) -> bool {
        self.__state.load(Ordering::Acquire) >= self.__limit
    }
}

#[no_mangle]
unsafe extern "C" fn pthread_barrier_destroy(_barrier: *mut pthread_barrier_t) -> c_int {
    log::error!("TODO: pthread_barrier_destroy()");
    0
}

#[no_mangle]
unsafe extern "C" fn pthread_barrier_init(
    barrier: *mut pthread_barrier_t,
    _attr: *const pthread_barrierattr_t,
    limit: c_uint,
) -> c_int {
    let barrier = barrier.ensure_mut();
    barrier.__state.store(0, Ordering::Release);
    barrier.__limit = limit;
    atomic::fence(Ordering::Release);
    0
}

#[no_mangle]
unsafe extern "C" fn pthread_barrier_wait(barrier: *mut pthread_barrier_t) -> c_int {
    let barrier = barrier.ensure_mut();
    barrier.wait();
    0
}

#[no_mangle]
unsafe extern "C" fn pthread_barrierattr_destroy(_attr: *mut pthread_barrierattr_t) -> c_int {
    log::error!("TODO: pthread_barrierattr_destroy()");
    0
}

#[no_mangle]
unsafe extern "C" fn pthread_barrierattr_getpshared(
    _attr: *const pthread_barrierattr_t,
    shared: *mut c_int,
) -> c_int {
    if let Some(shared) = NonNull::new(shared) {
        shared.write(PTHREAD_PROCESS_PRIVATE);
    }
    0
}

#[no_mangle]
unsafe extern "C" fn pthread_barrierattr_init(_attr: *mut pthread_barrierattr_t) -> c_int {
    log::error!("TODO: pthread_barrierattr_init()");
    0
}

#[no_mangle]
unsafe extern "C" fn pthread_barrierattr_setpshared(
    _attr: *mut pthread_barrierattr_t,
    shared: c_int,
) -> CIntZeroResult {
    if shared == PTHREAD_PROCESS_PRIVATE {
        CIntZeroResult::SUCCESS
    } else {
        log::error!("TODO: pthread_barrierattr_setpshared()");
        error::set_errno(Errno::EINVAL);
        CIntZeroResult::ERROR
    }
}
