use core::{ffi::c_void, ptr::null_mut, sync::atomic::compiler_fence};

use alloc::boxed::Box;

use crate::{
    arch::x86_64::asm::current::current_pcb,
    include::bindings::bindings::{
        process_control_block, CLONE_CLEAR_SIGHAND, CLONE_SIGHAND, CLONE_THREAD, ENOMEM,
    },
    ipc::{
        signal::{flush_signal_handlers, DEFAULT_SIGACTION},
        signal_types::{sigaction, sighand_struct, signal_struct, SigQueue},
    },
    libs::{
        atomic::atomic_set,
        ffi_convert::FFIBind2Rust,
        refcount::{refcount_inc, RefCount},
        spinlock::{spin_lock_irqsave, spin_unlock_irqrestore},
    },
};

#[no_mangle]
pub extern "C" fn process_copy_sighand(clone_flags: u64, pcb: *mut process_control_block) -> i32 {
    // kdebug!("process_copy_sighand");

    if (clone_flags & (CLONE_SIGHAND as u64)) != 0 {
        let r = RefCount::convert_mut(unsafe { &mut (*(current_pcb().sighand)).count }).unwrap();
        refcount_inc(r);
    }

    // 在这里使用Box::leak将动态申请的内存的生命周期转换为static的
    let mut sig: &mut sighand_struct = Box::leak(Box::new(sighand_struct::default()));
    if (sig as *mut sighand_struct) == null_mut() {
        return -(ENOMEM as i32);
    }

    // 将新的sighand赋值给pcb
    unsafe {
        (*pcb).sighand = sig as *mut sighand_struct as usize
            as *mut crate::include::bindings::bindings::sighand_struct;
    }

    // kdebug!("DEFAULT_SIGACTION.sa_flags={}", DEFAULT_SIGACTION.sa_flags);

    // 拷贝sigaction
    let mut flags: u64 = 0;

    spin_lock_irqsave(unsafe { &mut (*current_pcb().sighand).siglock }, &mut flags);
    compiler_fence(core::sync::atomic::Ordering::SeqCst);

    for (index, x) in unsafe { (*current_pcb().sighand).action }
        .iter()
        .enumerate()
    {
        compiler_fence(core::sync::atomic::Ordering::SeqCst);
        if !(x as *const crate::include::bindings::bindings::sigaction).is_null() {
            sig.action[index] =
                *sigaction::convert_ref(x as *const crate::include::bindings::bindings::sigaction)
                    .unwrap();
        } else {
            sig.action[index] = DEFAULT_SIGACTION;
        }
    }
    compiler_fence(core::sync::atomic::Ordering::SeqCst);

    spin_unlock_irqrestore(unsafe { &mut (*current_pcb().sighand).siglock }, &flags);
    compiler_fence(core::sync::atomic::Ordering::SeqCst);

    // 将信号的处理函数设置为default(除了那些被手动屏蔽的)
    if (clone_flags & (CLONE_CLEAR_SIGHAND as u64)) != 0 {
        compiler_fence(core::sync::atomic::Ordering::SeqCst);

        flush_signal_handlers(pcb, false);
        compiler_fence(core::sync::atomic::Ordering::SeqCst);
    }
    compiler_fence(core::sync::atomic::Ordering::SeqCst);

    return 0;
}

#[no_mangle]
pub extern "C" fn process_copy_signal(clone_flags: u64, pcb: *mut process_control_block) -> i32 {
    // kdebug!("process_copy_signal");
    // 如果克隆的是线程，则不拷贝信号（同一进程的各个线程之间共享信号）
    if (clone_flags & (CLONE_THREAD as u64)) != 0 {
        return 0;
    }
    let sig: &mut signal_struct = Box::leak(Box::new(signal_struct::default()));
    if (sig as *mut signal_struct) == null_mut() {
        return -(ENOMEM as i32);
    }
    atomic_set(&mut sig.sig_cnt, 1);
    // 将sig赋值给pcb中的字段
    unsafe {
        (*pcb).signal = sig as *mut signal_struct as usize
            as *mut crate::include::bindings::bindings::signal_struct;
    }

    // 创建新的sig_pending->sigqueue
    unsafe {
        (*pcb).sig_pending.signal = 0;
        (*pcb).sig_pending.sigqueue =
            Box::leak(Box::new(SigQueue::default())) as *mut SigQueue as *mut c_void;
    }
    return 0;
}

#[no_mangle]
pub extern "C" fn process_exit_signal(pcb: *mut process_control_block) {
    // 回收进程的信号结构体
    unsafe {
        // 回收sighand
        let sighand = Box::from_raw((*pcb).sighand as *mut sighand_struct);

        drop(sighand);
        (*pcb).sighand = 0 as *mut crate::include::bindings::bindings::sighand_struct;

        // 回收sigqueue
        let queue = Box::from_raw((*pcb).sig_pending.sigqueue as *mut SigQueue);
        drop(queue);
    }
}

#[no_mangle]
pub extern "C" fn process_exit_sighand(pcb: *mut process_control_block) {
    // todo: 回收进程的sighand结构体
    unsafe {
        let sig = Box::from_raw((*pcb).signal as *mut signal_struct);
        drop(sig);
        (*pcb).signal = 0 as *mut crate::include::bindings::bindings::signal_struct;
    }
}
