use alloc::string::ToString;
use alloc::vec::Vec;
use core::ffi::c_int;

use crate::arch::interrupt::TrapFrame;
use crate::arch::syscall::nr::SYS_RT_SIGQUEUEINFO;
use crate::ipc::signal_types::{
    copy_siginfo_from_user, sig_type_from_user_siginfo, PosixSigInfo, SigCode, SigInfo,
};
use crate::ipc::syscall::sys_kill::check_signal_permission_pcb_with_sig;
use crate::process::pid::PidType;
use crate::syscall::table::{FormattedSyscallParam, Syscall};
use crate::{arch::ipc::signal::Signal, mm::VirtAddr, process::ProcessManager, process::RawPid};
use system_error::SystemError;

/// rt_sigqueueinfo 系统调用（最小兼容实现）
///
/// 语义上与 kill(pid, sig) 类似，但允许用户态携带一个 siginfo_t。
/// 参考 Linux 6.6：
/// - 从用户态拷贝 siginfo（并强制以参数 sig 作为 si_signo）
/// - 若向“非自身 pid”发送，禁止伪造内核/kill/tkill 的 si_code：
///   `(si_code >= 0 || si_code == SI_TKILL) && current_pid != pid` => EPERM
/// - 将 si_errno 等字段随信号投递给目标。
struct SysRtSigqueueinfoHandle;

impl SysRtSigqueueinfoHandle {
    #[inline(always)]
    fn pid(args: &[usize]) -> i32 {
        args[0] as i32
    }

    #[inline(always)]
    fn sig(args: &[usize]) -> c_int {
        args[1] as c_int
    }

    #[inline(always)]
    fn _uinfo(args: &[usize]) -> usize {
        args[2]
    }
}

impl Syscall for SysRtSigqueueinfoHandle {
    fn num_args(&self) -> usize {
        3
    }

    fn handle(&self, args: &[usize], _frame: &mut TrapFrame) -> Result<usize, SystemError> {
        let pid = Self::pid(args);
        let sig = Self::sig(args);
        let uinfo = Self::_uinfo(args) as *const PosixSigInfo;

        if pid <= 0 {
            return Err(SystemError::EINVAL);
        }

        if uinfo.is_null() {
            return Err(SystemError::EFAULT);
        }

        let signal = Signal::from(sig);
        if sig != 0 && signal == Signal::INVALID {
            return Err(SystemError::EINVAL);
        }

        // Linux __copy_siginfo_from_user() overwrites si_signo with the syscall
        // argument before validating whether the expansion is required.
        let user_info =
            unsafe { copy_siginfo_from_user(VirtAddr::new(uinfo as usize), Some(sig))? };

        // sig==0 探测仍须先完成上述 copy/validation。
        if sig == 0 {
            let target_pid = RawPid::from(pid as usize);
            let target = ProcessManager::find_task_by_vpid(target_pid).ok_or(SystemError::ESRCH)?;
            check_signal_permission_pcb_with_sig(&target, None)?;
            return Ok(0);
        }

        let target_pid = RawPid::from(pid as usize);
        let current_pcb = ProcessManager::current_pcb();
        let current_pid = current_pcb.raw_pid();

        // Linux 6.6: do_rt_sigqueueinfo 权限校验
        let si_code = user_info.si_code;
        if (si_code >= 0 || si_code == SigCode::Tkill.as_i32()) && current_pid != target_pid {
            return Err(SystemError::EPERM);
        }

        let code_enum = SigCode::try_from_i32(si_code).unwrap_or(SigCode::Raw(si_code));
        let sig_type = sig_type_from_user_siginfo(signal, code_enum, &user_info);

        let mut info = SigInfo::new(signal, user_info.si_errno, code_enum, sig_type);

        // 查找目标进程并检查权限
        let target = ProcessManager::find_task_by_vpid(target_pid).ok_or(SystemError::ESRCH)?;
        check_signal_permission_pcb_with_sig(&target, Some(signal))?;

        // rt_sigqueueinfo 发送进程级信号，使用 PidType::TGID
        signal
            .send_signal_info_to_pcb(Some(&mut info), target, PidType::TGID)
            .map(|x| x as usize)
    }

    fn entry_format(&self, args: &[usize]) -> Vec<FormattedSyscallParam> {
        vec![
            FormattedSyscallParam::new("pid", Self::pid(args).to_string()),
            FormattedSyscallParam::new("sig", Self::sig(args).to_string()),
            FormattedSyscallParam::new("uinfo", format!("{:#x}", Self::_uinfo(args))),
        ]
    }
}

// 注册系统调用
syscall_table_macros::declare_syscall!(SYS_RT_SIGQUEUEINFO, SysRtSigqueueinfoHandle);
