use std::fmt::Display;
pub enum Authentication {
    Password{
        username: String,
        password: String
    },
    ApiKey{
        username: String,
        key: String
    },
    OAuth{
        provider: String,
        token: String
    }
}
pub type JsonMap = serde_json::Map<String, serde_json::Value>;
#[derive(Debug)]
pub enum Error {
    Client{
        message: String,
        status: u32,
        api_version: Option<String>,
        api_response: Option<String>
    },
    TransportError(String),
    InvalidHeader,
    MalformedResponse,
    InvalidSha256,
    InvalidSubmitFilePath,
    InvalidSubmitUrl,
    IO(std::io::Error),
    Serialization(serde_json::Error),
    ParameterSerialization,
}
impl Error {
    pub (crate) fn client_error(message: String, status: u32) -> Self {
        return Error::Client { message, status, api_response: None, api_version: None }
    }
}
impl Display for Error {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        match self {
            Error::Client { message, status, .. } =>
                f.write_fmt(format_args!("Client error [{status}]: {message}")),
            Error::TransportError(message) =>
                f.write_fmt(format_args!("Error communicating with server: {message}")),
            Error::InvalidHeader =>
                f.write_str("An invalid HTTP header name or value was encountered"),
            Error::MalformedResponse =>
                f.write_str("A server response was malformed"),
            Error::InvalidSha256 =>
                f.write_str("An invalid SHA256 string was provided"),
            Error::InvalidSubmitFilePath =>
                f.write_str("An invalid path was given for submission"),
            Error::InvalidSubmitUrl =>
                f.write_str("An invalid URL was given for submission, try setting the file name explicitly"),
            Error::IO(error) =>
                f.write_fmt(format_args!("An IO error ocurred: {error}")),
            Error::Serialization(error) =>
                f.write_fmt(format_args!("An error occurred serializing a body: {error}")),
            Error::ParameterSerialization =>
                f.write_str("Parameter serialization yielded unexpected type."),
        }
    }
}
impl From<reqwest::Error> for Error {
    fn from(value: reqwest::Error) -> Self {
        if let Some(code) = value.status() {
            Error::client_error(value.to_string(), code.as_u16() as u32)
        } else {
            Error::TransportError(value.to_string())
        }
    }
}
impl From<reqwest::header::InvalidHeaderName> for Error {
    fn from(_value: reqwest::header::InvalidHeaderName) -> Self {
        Self::InvalidHeader
    }
}
impl From<reqwest::header::InvalidHeaderValue> for Error {
    fn from(_value: reqwest::header::InvalidHeaderValue) -> Self {
        Self::InvalidHeader
    }
}
impl From<serde_json::Error> for Error {
    fn from(value: serde_json::Error) -> Self {
        Self::Serialization(value)
    }
}
impl From<std::io::Error> for Error {
    fn from(value: std::io::Error) -> Self {
        Self::IO(value)
    }
}
impl From<url::ParseError> for Error {
    fn from(_value: url::ParseError) -> Self {
        Self::InvalidSubmitUrl
    }
}
impl std::error::Error for Error {
}
pub type Result<T> = std::result::Result<T, Error>;
pub trait IBool: Into<Option<bool>> + Copy {}
impl<T: Into<Option<bool>> + Copy> IBool for T {}