use crate::Syscall;

/// Raw OS errno returned by [`Rule::ReturnError`]
pub type RawOsErrorNum = u16;

/// Action used when a syscall does not match an allow-list rule
#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord)]
pub enum ViolationAction {
    /// Kill the whole process
    KillProcess,
    /// Let the syscall continue and ask the kernel to log it
    AllowAndLog,
}

/// Value used by syscall argument comparisons
#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord)]
pub struct ArgCmpValue(u64);

impl ArgCmpValue {
    /// Create a comparison value from a static pointer
    pub fn from_static<T>(value: &'static T) -> Self {
        Self(value as *const T as u64)
    }

    /// Raw value passed to seccomp
    pub fn get(self) -> u64 {
        self.0
    }
}

impl<T> From<T> for ArgCmpValue
where
    T: Into<u64>,
{
    fn from(value: T) -> Self {
        Self(value.into())
    }
}

/// Syscall argument comparison
#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord)]
pub enum ArgCmp {
    /// Argument must not equal value
    NotEqual { arg_idx: u32, value: ArgCmpValue },
    /// Argument must be less than value
    LessThan { arg_idx: u32, value: ArgCmpValue },
    /// Argument must be less than or equal to value
    LessThanOrEqual { arg_idx: u32, value: ArgCmpValue },
    /// Argument must equal value
    Equal { arg_idx: u32, value: ArgCmpValue },
    /// Argument must be greater than or equal to value
    GreaterThanOrEqual { arg_idx: u32, value: ArgCmpValue },
    /// Argument must be greater than value
    GreaterThan { arg_idx: u32, value: ArgCmpValue },
    /// Masked argument must equal masked value
    EqualMasked {
        arg_idx: u32,
        mask: ArgCmpValue,
        value: ArgCmpValue,
    },
}

/// Syscall exception rule
#[derive(Clone, Debug, PartialEq, Eq)]
pub enum Rule {
    /// Allow a syscall when the argument comparisons match
    Allow(Syscall, Vec<ArgCmp>),
    /// Allow and log a syscall when the argument comparisons match
    AllowAndLog(Syscall, Vec<ArgCmp>),
    /// Return errno when the argument comparisons match
    ReturnError(Syscall, RawOsErrorNum, Vec<ArgCmp>),
}
