use crate::repository::api::prelude::*;

#[derive(Debug)]
pub enum PromoError {
    PromoNotExists,
    PromoExpired,
    PromoAlreadyUsed,
    Other(String),
}

impl std::fmt::Display for PromoError {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        match self {
            PromoError::PromoNotExists => write!(f, "Promocode does not exist"),
            PromoError::PromoExpired => write!(f, "Promocode is expired"),
            PromoError::PromoAlreadyUsed => write!(f, "Promocode already used by user"),
            PromoError::Other(msg) => write!(f, "{}", msg),
        }
    }
}

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

/// Activate a traffic promocode for a user
pub async fn activate_traffic_promocode(user_id: String, code: &str) -> Result<(), PromoError> {
    let url = format!("{host}/rpc/activate_traffic_promocode", host=&*BACKEND_API_URL);
    log::trace!("fetching {url}", url = url.red());

    #[derive(serde::Serialize)]
    struct ActivatePromoRequest {
        code: String,
    }

    let response = reqwest::Client::new()
        .post(&url)
        .json(&ActivatePromoRequest { 
            code: code.to_string() 
        })
        .header("Authorization", get_auth_token().await.map_err(|e| PromoError::Other(e.to_string()))?)
        .header("Content-Type", "application/json")
        .header("X-Tg-Id", user_id)
        .send()
        .await
        .map_err(|e| PromoError::Other(e.to_string()))?;

    let status = response.status();
    
    if status.is_success() {
        Ok(())
    } else {
        let error_text = response.text().await.unwrap_or_default();
        
        match status.as_u16() {
            422 => Err(PromoError::PromoNotExists),
            409 => Err(PromoError::PromoAlreadyUsed),
            _ => Err(PromoError::Other(format!(
                "HTTP {}: {}",
                status,
                prettify_json_or_text(&error_text)
            ))),
        }
    }
}
