use std::env;
use axum::{Router, Json};
use axum::routing::post;
use reqwest::StatusCode;
use reqwest::Client;
use serde::{Serialize, Deserialize};

#[derive(Deserialize)]
struct GenerateTokenRequest {
    username: String,
    password: String,
}

#[derive(Serialize)]
struct TokenRequest {
    grant_type: String,
    username: String,
    password: String,
    client_id: String,
    client_secret: String,
}

#[derive(Serialize, Deserialize)]
struct TokenResponse {
    access_token: String,
    token_type: String,
    expires_in: i64,
}

pub fn router() -> Router {
    Router::new()
        .route("/login/generate_token", post(gen_token))
}

async fn gen_token(Json(payload): Json<GenerateTokenRequest>) -> Result<Json<TokenResponse>, StatusCode> {
    let client = Client::new();

    let account_url = env::var("ACCOUNT_URL").unwrap_or("https://account.spfn.net".into());
    let client_id = env::var("ACCOUNT_CLIENT_ID").unwrap_or("account".into());
    let client_secret = match env::var("ACCOUNT_CLIENT_SECRET") {
        Ok(secret) => secret,
        Err(_) => {
            println!("No account client secret specified - Token generation will always fail");
            return Err(StatusCode::INTERNAL_SERVER_ERROR)
        },
    };

    let body = TokenRequest {
        grant_type: "password".into(),
        username: payload.username,
        password: payload.password,
        client_id,
        client_secret,
    };

    let response = client
        .post(format!("{}/api/v2/oauth2/generate_token", account_url))
        .form(&body)
        .send()
        .await;

    match response {
        Ok(res) => {
            let body = res.json::<TokenResponse>().await;

            match body {
                Ok(b) => return Ok(Json(b)),
                Err(_) => return Err(StatusCode::BAD_GATEWAY)
            };
        },
        Err(e) => match e.status() {
            Some(code) => return Err(code),
            None => {
                println!("[/api/v1/login/generate_token] No status error returned from upstream: {}", e);
                return Err(StatusCode::BAD_GATEWAY);
            }
        }
    }
}
