//! Contract SDK errors

use std::fmt;

/// Contract SDK result type
pub type Result<T> = std::result::Result<T, ContractError>;

/// Contract SDK error
#[derive(Debug)]
pub enum ContractError {
    /// HTTP request error
    Request(String),
    /// Invalid response
    Response(String),
    /// Serialization error
    Serialization(String),
    /// API error
    Api {
        message: String,
        code: Option<String>,
        status_code: Option<u16>,
    },
    /// Client is closed
    Closed,
}

impl fmt::Display for ContractError {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        match self {
            ContractError::Request(msg) => write!(f, "Request error: {}", msg),
            ContractError::Response(msg) => write!(f, "Response error: {}", msg),
            ContractError::Serialization(msg) => write!(f, "Serialization error: {}", msg),
            ContractError::Api { message, code, status_code } => {
                write!(f, "API error: {}", message)?;
                if let Some(c) = code {
                    write!(f, " (code: {})", c)?;
                }
                if let Some(s) = status_code {
                    write!(f, " (status: {})", s)?;
                }
                Ok(())
            }
            ContractError::Closed => write!(f, "Client has been closed"),
        }
    }
}

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

impl From<reqwest::Error> for ContractError {
    fn from(err: reqwest::Error) -> Self {
        ContractError::Request(err.to_string())
    }
}

impl From<serde_json::Error> for ContractError {
    fn from(err: serde_json::Error) -> Self {
        ContractError::Serialization(err.to_string())
    }
}
