use thiserror::Error;

/// Tipo de resultado padrão para operações da SDK
pub type KondutoResult<T> = Result<T, KondutoError>;

/// Erros possíveis ao interagir com a API da Konduto
#[derive(Error, Debug)]
pub enum KondutoError {
    /// Erro ao realizar requisição HTTP
    #[error("Erro de requisição HTTP: {0}")]
    HttpError(#[from] reqwest::Error),

    /// Erro de serialização/deserialização JSON
    #[error("Erro de serialização JSON: {0}")]
    SerializationError(#[from] serde_json::Error),

    /// Erro retornado pela API da Konduto
    #[error("Erro da API Konduto: {status} - {message}")]
    ApiError {
        status: u16,
        message: String,
        code: Option<String>,
    },

    /// Erro de autenticação
    #[error("Erro de autenticação: {0}")]
    AuthenticationError(String),

    /// Erro de validação de dados
    #[error("Erro de validação: {0}")]
    ValidationError(String),

    /// Variável de ambiente ausente
    #[error("Variável de ambiente ausente: {0}")]
    MissingEnvVar(String),

    /// Erro genérico
    #[error("Erro: {0}")]
    GenericError(String),
}

impl KondutoError {
    /// Cria um erro de API a partir de um status HTTP e mensagem
    /// todo aqui acho que é melhor parsear para os dois tipos de erro da konduto ref <https://docs.konduto.com/reference/respostas-de-erro-1>
    pub fn api_error(status: u16, message: String, code: Option<String>) -> Self {
        KondutoError::ApiError {
            status,
            message,
            code,
        }
    }
}

impl From<reqwest_middleware::Error> for KondutoError {
    fn from(err: reqwest_middleware::Error) -> Self {
        // O reqwest_middleware::Error pode conter um reqwest::Error ou um erro de middleware
        match err {
            reqwest_middleware::Error::Middleware(e) => {
                KondutoError::GenericError(format!("Middleware error: {}", e))
            }
            reqwest_middleware::Error::Reqwest(e) => KondutoError::HttpError(e),
        }
    }
}
