use crate::repository::api::prelude::*;
use std::sync::RwLock;

pub static AUTH_TOKEN: RwLock<String> = RwLock::new(String::new());

pub async fn upsert_tg_user(
    tg_id: u64, 
    first_name: String, 
    last_name: Option<String>, 
    username: Option<String>,
    referral: Option<String>
) -> Result<()> {
    let url = format!("{host}/rpc/signinup_tg", host=&*BACKEND_API_URL);
    log::trace!("fetching {url}", url = url.red());

    #[derive(serde::Serialize)]
    struct SigninUpRequest {
        id: u64,
        username: Option<String>,
        first_name: String,
        surname: Option<String>,
        referral_id: Option<String>,
    }
    
    let request = SigninUpRequest {
        id: tg_id,
        username,
        first_name,
        surname: last_name,
        referral_id: referral,
    };

    let response = reqwest::Client::new()
        .post(&url)
        .header("Authorization", get_auth_token().await?)
        .header("Content-Type", "application/json")
        .json(&request)
        .send()
        .await?;

    if response.status().is_success() {
        Ok(())
    } else {
        Err(Report::msg(format!(
            "Failed to create user: {}",
            prettify_json_or_text(&response.text().await?)
        )))
    }
}

pub async fn get_auth_token() -> Result<String> {
    //   if cannot, then use String::leak() becouse I thing get() already cloned the value
    let token_opt = {
        let read_guard = AUTH_TOKEN.read().unwrap();
        if read_guard.is_empty() {
            None
        } else {
            Some(read_guard.clone())
        }
    };
    
    if let Some(token) = token_opt {
        log::trace!("{}", format!("Old token: {:?}", token).bright_black());
        Ok(token)
    } else {
        get_new_auth_token().await
    }
}


async fn get_new_auth_token() -> Result<String> {
    #[derive(serde::Serialize)]
    struct Signin {
        username: String,
        password: String,
    }

    let url = format!("{host}/rpc/signin", host=&*BACKEND_API_URL);
    log::trace!("fetching {url}", url = url.red());

    let credentials = Signin {
        username: BACKEND_USERNAME.clone(),
        password: BACKEND_PASSWORD.clone(),
    };

    let response = reqwest::Client::new()
        .post(&url)
        .header("Content-Type", "application/json")
        .header("Accept", "text/plain")
        .json(&credentials)
        .send()
        .await?;

    let status = response.status();
    if status.as_u16() / 100 != 2 {
        let body = response.text().await.unwrap_or_default();
        let body = prettify_json_or_text(&body);
        log::error!("Failed to register a user: {}: {}", status, body);
        return Err(Report::msg(format!(
            "Failed to register a user: {}: {}",
            status,
            body
        )));
    }

    let token_body = response.text().await?;
    let token = format!("Bearer {}", token_body);

    log::debug!("New auth token: {:?}", token);

    let mut write_guard = AUTH_TOKEN.write().unwrap();
    *write_guard = token.clone();
    Ok(token)
}