#![forbid(unsafe_code)]
use std::{
    array::TryFromSliceError,
    env::VarError,
    fmt, io,
    net::AddrParseError,
    num::{ParseIntError, TryFromIntError},
    str::Utf8Error,
    thread::JoinHandle,
};
use btoi::ParseIntegerError;
#[cfg(feature = "oci")]
use libcgroups::common::AnyManagerError;
#[cfg(feature = "oci")]
use libcgroups::common::CreateCgroupSetupError;
#[cfg(feature = "oci")]
use libcontainer::error::LibcontainerError;
#[cfg(feature = "oci")]
use libcontainer::signal::SignalError;
#[cfg(feature = "oci")]
use libcontainer::utils::PathBufExtError;
use libseccomp::error::SeccompError;
use nix::errno::Errno;
use procfs_core::ProcError;
use shellexpand::LookupError;
#[cfg(feature = "oci")]
use tracing::subscriber::SetGlobalDefaultError;
use crate::{caps::errors::CapsError, elf::ElfError};
pub type SydResult<T> = std::result::Result<T, SydError>;
pub type SydJoinHandle<T> = JoinHandle<SydResult<T>>;
#[macro_export]
macro_rules! lasterrno {
    () => {
        SydError::Nix(nix::errno::Errno::last())
    };
}
pub enum SydError {
        Addr(AddrParseError),
        Args(lexopt::Error),
        Caps(CapsError),
        Elf(ElfError),
        Env(LookupError<VarError>),
        Nix(Errno),
        Json(serde_json::Error),
        ParseInt(ParseIntError),
        ParseInteger(ParseIntegerError),
        TryInt(TryFromIntError),
        TrySlice(TryFromSliceError),
        ParseSize(parse_size::Error),
        Proc(ProcError),
        Scmp(SeccompError),
        Utf8(Utf8Error),
    #[cfg(feature = "oci")]
        CgSetup(CreateCgroupSetupError),
    #[cfg(feature = "oci")]
        CgMisc(AnyManagerError),
    #[cfg(feature = "oci")]
        Cont(LibcontainerError),
    #[cfg(feature = "oci")]
        Pext(PathBufExtError),
    #[cfg(feature = "oci")]
        SetTracing(SetGlobalDefaultError),
    #[cfg(feature = "oci")]
        Signal(SignalError<String>),
    #[cfg(feature = "oci")]
        Spec(oci_spec::OciSpecError),
}
impl SydError {
        pub fn errno(&self) -> Option<Errno> {
        match self {
            Self::Nix(errno) => Some(*errno),
            Self::Proc(error) => proc_error_to_errno(error),
            Self::Scmp(error) => scmp2no(error),
            Self::ParseInt(_) | Self::ParseInteger(_) | Self::ParseSize(_) => Some(Errno::EINVAL),
            _ => None,
        }
    }
}
impl fmt::Debug for SydError {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        match self {
            Self::Addr(error) => write!(f, "AddrParseError: {error:?}"),
            Self::Args(error) => write!(f, "ArgsParseError: {error:?}"),
            Self::Caps(error) => write!(f, "CapsError: {error:?}"),
            Self::Elf(error) => write!(f, "ElfError: {error:?}"),
            Self::Env(error) => write!(f, "LookupError<VarError>: {error:?}"),
            Self::Nix(errno) => write!(f, "LinuxError: {errno:?}"),
            Self::Json(error) => write!(f, "JsonError: {error:?}"),
            Self::ParseInt(error) => write!(f, "ParseIntError: {error:?}"),
            Self::ParseInteger(error) => write!(f, "ParseIntegerError: {error:?}"),
            Self::Scmp(error) => write!(f, "SeccompError: {error:?}"),
            Self::TryInt(error) => write!(f, "TryFromIntError: {error:?}"),
            Self::TrySlice(error) => write!(f, "TryFromSliceError: {error:?}"),
            Self::ParseSize(error) => write!(f, "ParseSizeError: {error:?}"),
            Self::Proc(error) => write!(f, "ProcError: {error:?}"),
            Self::Utf8(error) => write!(f, "Utf8Error: {error:?}"),
            #[cfg(feature = "oci")]
            Self::CgSetup(error) => write!(f, "CgroupSetupError: {error:?}"),
            #[cfg(feature = "oci")]
            Self::CgMisc(error) => write!(f, "AnyManagerError: {error:?}"),
            #[cfg(feature = "oci")]
            Self::Cont(error) => write!(f, "ContainerError: {error:?}"),
            #[cfg(feature = "oci")]
            Self::Pext(error) => write!(f, "PathBufExtError: {error:?}"),
            #[cfg(feature = "oci")]
            Self::SetTracing(error) => write!(f, "SetGlobalDefaultError: {error:?}"),
            #[cfg(feature = "oci")]
            Self::Signal(error) => write!(f, "SignalError: {error:?}"),
            #[cfg(feature = "oci")]
            Self::Spec(error) => write!(f, "OciSpecError: {error:?}"),
        }
    }
}
impl fmt::Display for SydError {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        match self {
            Self::Addr(error) => write!(f, "AddrParseError: {error}"),
            Self::Args(error) => write!(f, "ArgsParseError: {error}"),
            Self::Caps(error) => write!(f, "CapsError: {error}"),
            Self::Elf(error) => write!(f, "ElfError: {error}"),
            Self::Env(error) => write!(f, "LookupError<VarError>: {error}"),
            Self::Nix(errno) => write!(f, "LinuxError: {errno}"),
            Self::Json(error) => write!(f, "JsonError: {error}"),
            Self::ParseInt(error) => write!(f, "ParseIntError: {error}"),
            Self::ParseInteger(error) => write!(f, "ParseIntegerError: {error}"),
            Self::Scmp(error) => write!(f, "SeccompError: {error}"),
            Self::TryInt(error) => write!(f, "TryFromIntError: {error}"),
            Self::TrySlice(error) => write!(f, "TryFromSliceError: {error}"),
            Self::ParseSize(error) => write!(f, "ParseSizeError: {error}"),
            Self::Proc(error) => write!(f, "ProcError: {error}"),
            Self::Utf8(error) => write!(f, "Utf8Error: {error}"),
            #[cfg(feature = "oci")]
            Self::CgSetup(error) => write!(f, "CgroupSetupError: {error}"),
            #[cfg(feature = "oci")]
            Self::CgMisc(error) => write!(f, "AnyManagerError: {error}"),
            #[cfg(feature = "oci")]
            Self::Cont(error) => write!(f, "ContainerError: {error}"),
            #[cfg(feature = "oci")]
            Self::Pext(error) => write!(f, "PathBufExtError: {error}"),
            #[cfg(feature = "oci")]
            Self::SetTracing(error) => write!(f, "SetGlobalDefaultError: {error}"),
            #[cfg(feature = "oci")]
            Self::Signal(error) => write!(f, "SignalError: {error}"),
            #[cfg(feature = "oci")]
            Self::Spec(error) => write!(f, "OciSpecError: {error}"),
        }
    }
}
impl std::error::Error for SydError {
    fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
        match self {
            Self::Addr(error) => Some(error),
            Self::Args(error) => Some(error),
            Self::Nix(errno) => Some(errno),
            Self::ParseInt(error) => Some(error),
            Self::ParseInteger(error) => Some(error),
            Self::TryInt(error) => Some(error),
            Self::TrySlice(error) => Some(error),
                                    Self::ParseSize(_error) => None,
            Self::Proc(error) => Some(error),
            Self::Utf8(error) => Some(error),
            #[cfg(feature = "oci")]
            Self::CgSetup(error) => Some(error),
            #[cfg(feature = "oci")]
            Self::CgMisc(error) => Some(error),
            #[cfg(feature = "oci")]
            Self::Cont(error) => Some(error),
            #[cfg(feature = "oci")]
            Self::Pext(error) => Some(error),
            #[cfg(feature = "oci")]
            Self::SetTracing(error) => Some(error),
            #[cfg(feature = "oci")]
            Self::Signal(error) => Some(error),
            #[cfg(feature = "oci")]
            Self::Spec(error) => Some(error),
            _ => None,
        }
    }
}
impl From<io::Error> for SydError {
    fn from(err: io::Error) -> SydError {
        SydError::Nix(err2no(&err))
    }
}
impl From<AddrParseError> for SydError {
    fn from(err: AddrParseError) -> SydError {
        SydError::Addr(err)
    }
}
impl From<Utf8Error> for SydError {
    fn from(err: Utf8Error) -> SydError {
        Self::Utf8(err)
    }
}
impl From<ProcError> for SydError {
    fn from(err: ProcError) -> SydError {
        Self::Proc(err)
    }
}
impl From<lexopt::Error> for SydError {
    fn from(err: lexopt::Error) -> SydError {
        Self::Args(err)
    }
}
impl From<CapsError> for SydError {
    fn from(err: CapsError) -> SydError {
        Self::Caps(err)
    }
}
impl From<ElfError> for SydError {
    fn from(err: ElfError) -> SydError {
        Self::Elf(err)
    }
}
impl From<LookupError<VarError>> for SydError {
    fn from(err: LookupError<VarError>) -> SydError {
        Self::Env(err)
    }
}
impl From<Errno> for SydError {
    fn from(err: Errno) -> SydError {
        Self::Nix(err)
    }
}
impl From<serde_json::Error> for SydError {
    fn from(err: serde_json::Error) -> SydError {
        Self::Json(err)
    }
}
#[cfg(feature = "oci")]
impl From<AnyManagerError> for SydError {
    fn from(err: AnyManagerError) -> SydError {
        Self::CgMisc(err)
    }
}
#[cfg(feature = "oci")]
impl From<CreateCgroupSetupError> for SydError {
    fn from(err: CreateCgroupSetupError) -> SydError {
        Self::CgSetup(err)
    }
}
#[cfg(feature = "oci")]
impl From<LibcontainerError> for SydError {
    fn from(err: LibcontainerError) -> SydError {
        Self::Cont(err)
    }
}
#[cfg(feature = "oci")]
impl From<PathBufExtError> for SydError {
    fn from(err: PathBufExtError) -> SydError {
        Self::Pext(err)
    }
}
#[cfg(feature = "oci")]
impl From<SetGlobalDefaultError> for SydError {
    fn from(err: SetGlobalDefaultError) -> SydError {
        Self::SetTracing(err)
    }
}
#[cfg(feature = "oci")]
impl From<SignalError<String>> for SydError {
    fn from(err: SignalError<String>) -> SydError {
        Self::Signal(err)
    }
}
#[cfg(feature = "oci")]
impl From<oci_spec::OciSpecError> for SydError {
    fn from(err: oci_spec::OciSpecError) -> SydError {
        Self::Spec(err)
    }
}
impl From<ParseIntError> for SydError {
    fn from(err: ParseIntError) -> SydError {
        Self::ParseInt(err)
    }
}
impl From<ParseIntegerError> for SydError {
    fn from(err: ParseIntegerError) -> SydError {
        Self::ParseInteger(err)
    }
}
impl From<TryFromIntError> for SydError {
    fn from(err: TryFromIntError) -> SydError {
        Self::TryInt(err)
    }
}
impl From<TryFromSliceError> for SydError {
    fn from(err: TryFromSliceError) -> SydError {
        Self::TrySlice(err)
    }
}
impl From<parse_size::Error> for SydError {
    fn from(err: parse_size::Error) -> SydError {
        Self::ParseSize(err)
    }
}
impl From<SeccompError> for SydError {
    fn from(err: SeccompError) -> SydError {
        Self::Scmp(err)
    }
}
pub fn err2no(err: &std::io::Error) -> Errno {
    err.raw_os_error()
        .map(Errno::from_raw)
        .unwrap_or(Errno::ENOSYS)
}
pub fn scmp2no(err: &SeccompError) -> Option<Errno> {
    err.sysrawrc().map(|errno| errno.abs()).map(Errno::from_raw)
}
pub fn proc_error_to_errno(error: &ProcError) -> Option<Errno> {
    match error {
        ProcError::PermissionDenied(_) => Some(Errno::EACCES),
        ProcError::NotFound(_) => Some(Errno::ESRCH),
        ProcError::Io(error, _) => Some(err2no(error)),
        ProcError::Other(_) => None,
        ProcError::Incomplete(_) => None,
        ProcError::InternalError(_) => None,
    }
}