use std::borrow::Cow;
use std::error::Error;
use std::fmt;

/// Security setup error with a concrete fix suggestion
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct SecurityError {
    reason: Cow<'static, str>,
    suggestion: Cow<'static, str>,
}

impl SecurityError {
    pub fn new(
        reason: impl Into<Cow<'static, str>>,
        suggestion: impl Into<Cow<'static, str>>,
    ) -> Self {
        Self {
            reason: reason.into(),
            suggestion: suggestion.into(),
        }
    }

    pub fn unsupported_target() -> Self {
        Self::new(
            "seccomp syscall sandboxing is only supported on Linux",
            "guard security setup with cfg(target_os = \"linux\")",
        )
    }

    pub fn reason(&self) -> &str {
        &self.reason
    }

    pub fn suggestion(&self) -> &str {
        &self.suggestion
    }
}

impl fmt::Display for SecurityError {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        write!(
            f,
            "security setup failed\nreason: {}\nplease try: {}",
            self.reason, self.suggestion
        )
    }
}

impl Error for SecurityError {}

#[cfg(feature = "errors")]
impl miette::Diagnostic for SecurityError {
    fn code<'a>(&'a self) -> Option<Box<dyn fmt::Display + 'a>> {
        Some(Box::new("security::sandbox"))
    }

    fn help<'a>(&'a self) -> Option<Box<dyn fmt::Display + 'a>> {
        Some(Box::new(self.suggestion()))
    }
}
