use std::fmt::{Display, Formatter};

/// Errors that can occur during decoding.
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum DecodeError {
    /// An invalid byte was found in the input. The offending byte is provided.
    InvalidByte(u8),
    /// The length of the input is invalid.
    InvalidLength,
    /// The last non-padding byte of input has discarded bits and those bits are
    /// not zero. While this could be decoded it likely represents a corrupted or
    /// invalid encoding.
    InvalidTrailingBits,
    /// invalid padding
    InvalidPadding
}

impl Display for DecodeError {
    fn fmt(&self, f: &mut Formatter) -> std::fmt::Result {
        match self {
            DecodeError::InvalidByte(byte) => write!(f, "invalid byte {}", byte),
            DecodeError::InvalidLength => write!(f, "encoded text cannot have a 6-bit remainder"),
            DecodeError::InvalidTrailingBits => {
                write!(f, "last byte has unnecessary trailing bits")
            },
            DecodeError::InvalidPadding => {
                write!(f, "invalid padding")
            }
        }
    }
}

#[cfg(feature = "base64-radix64")]
impl From<radix64::DecodeError> for DecodeError {
    fn from(value: radix64::DecodeError) -> Self {
        match value {
            radix64::DecodeError::InvalidByte(b) => Self::InvalidByte(b),
            radix64::DecodeError::InvalidLength => Self::InvalidLength,
            radix64::DecodeError::InvalidTrailingBits => Self::InvalidTrailingBits
        }
    }
}

#[cfg(feature = "base64-base64")]
impl From<base64::DecodeError> for DecodeError {
    fn from(value: base64::DecodeError) -> Self {
        match value {
            base64::DecodeError::InvalidByte(_, b) => Self::InvalidByte(b),
            base64::DecodeError::InvalidLength => Self::InvalidLength,
            base64::DecodeError::InvalidLastSymbol(_, _) => Self::InvalidTrailingBits,
            base64::DecodeError::InvalidPadding => Self::InvalidPadding
        }
    }
}