use std::fmt;

#[derive(Debug)]
pub enum Error {
    Transport(String),
    Http {
        status: u16,
        body: String,
    },
    Aws {
        code: String,
        message: String,
        status: u16,
    },
    Parse(String),
    Invalid(String),
}

impl Error {
    pub(crate) fn transport(msg: impl Into<String>) -> Self {
        Error::Transport(msg.into())
    }

    pub(crate) fn parse(msg: impl Into<String>) -> Self {
        Error::Parse(msg.into())
    }
}

impl fmt::Display for Error {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        match self {
            Error::Transport(m) => write!(f, "transport error: {m}"),
            Error::Http { status, body } => write!(f, "http {status}: {body}"),
            Error::Aws {
                code,
                message,
                status,
            } => {
                write!(f, "aws error [{code}] (http {status}): {message}")
            }
            Error::Parse(m) => write!(f, "parse error: {m}"),
            Error::Invalid(m) => write!(f, "invalid input: {m}"),
        }
    }
}

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

impl From<std::io::Error> for Error {
    fn from(e: std::io::Error) -> Self {
        Error::Transport(e.to_string())
    }
}
