use std::fmt;

/// Error type for AXML and ARSC parsing and manipulation.
#[derive(Debug)]
#[non_exhaustive]
pub enum AxmlError {
    /// Unexpected end of input while reading a required field.
    UnexpectedEof,
    /// Invalid magic bytes for AXML or ARSC format.
    InvalidMagic(u16),
    /// Invalid chunk type identifier.
    InvalidChunkType(u16),
    /// String index out of bounds (requested index, valid count).
    InvalidStringIndex(usize, usize),
    /// UTF-8 decoding error from the string pool.
    Utf8Error(std::string::FromUtf8Error),
    /// UTF-16 decoding error from the string pool.
    Utf16Error(std::char::DecodeUtf16Error),
    /// XML parsing or generation error.
    XmlError(String),
    /// Slice bounds or format error.
    SliceError(String),
    /// Protobuf message decoding error.
    ProtoError(prost::DecodeError),
    /// File I/O error.
    IoError(std::io::Error),
}

impl fmt::Display for AxmlError {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        match self {
            AxmlError::UnexpectedEof => write!(f, "Unexpected end of file"),
            AxmlError::InvalidMagic(t) => write!(f, "Invalid file magic: 0x{:04x}", t),
            AxmlError::InvalidChunkType(t) => write!(f, "Invalid chunk type: 0x{:04x}", t),
            AxmlError::InvalidStringIndex(idx, len) => {
                write!(f, "String index {} out of range (pool size: {})", idx, len)
            }
            AxmlError::Utf8Error(e) => write!(f, "UTF-8 decode error: {}", e),
            AxmlError::Utf16Error(e) => write!(f, "UTF-16 decode error: {}", e),
            AxmlError::XmlError(s) => write!(f, "XML error: {}", s),
            AxmlError::SliceError(s) => write!(f, "Slice error: {}", s),
            AxmlError::ProtoError(e) => write!(f, "Protobuf decode error: {}", e),
            AxmlError::IoError(e) => write!(f, "I/O error: {}", e),
        }
    }
}

impl std::error::Error for AxmlError {}

impl From<std::string::FromUtf8Error> for AxmlError {
    fn from(e: std::string::FromUtf8Error) -> Self {
        AxmlError::Utf8Error(e)
    }
}

impl From<prost::DecodeError> for AxmlError {
    fn from(e: prost::DecodeError) -> Self {
        AxmlError::ProtoError(e)
    }
}

impl From<std::char::DecodeUtf16Error> for AxmlError {
    fn from(e: std::char::DecodeUtf16Error) -> Self {
        AxmlError::Utf16Error(e)
    }
}

impl From<std::io::Error> for AxmlError {
    fn from(e: std::io::Error) -> Self {
        AxmlError::IoError(e)
    }
}
