use std::future::Future;

use gloo_console::log;
use gloo_net::http::{Request, Response};
use visions_types::{AuthRequest, AuthResponse, SessionId, UserOverview};

pub enum ClientError {
    Unauthorized,
    Err(u16),
}

pub trait Client {
    fn auth(&self, username: String, password: String) -> impl Future<Output = Result<AuthResponse, ClientError>>;
    fn list_users(&self, session_id: &SessionId) -> impl Future<Output = Result<Vec<UserOverview>, ClientError>>;
}

pub struct Connection;

impl Connection {
    pub fn new() -> Self { Self }
}

impl Client for Connection {
    async fn auth(&self, username: String, password: String) -> Result<AuthResponse, ClientError> {
        log!("authenticating: ", &username, &password);
        let response: Response = Request::post("/api/test/auth")
            .header("Content-Type", "application/json")
            .body(serde_wasm_bindgen::to_value(&serde_json::to_string(&AuthRequest{ username, password }).unwrap()).unwrap())
            .unwrap()
            .send()
            .await
            .unwrap();

        if response.ok() {
            Ok(serde_json::from_slice(&response.binary().await.unwrap()).unwrap())
        } else {
            Err(ClientError::Err(response.status()))
        }
    }

    async fn list_users(&self, session_id: &SessionId) -> Result<Vec<UserOverview>, ClientError> {
        let response: Response = Request::get("/api/test/list-users")
            .header("Content-Type", "application/json")
            .header("Authorization", &format!("Bearer {}", session_id.as_str()))
            .send()
            .await
            .unwrap();

        if response.ok() {
            Ok(serde_json::from_slice(&response.binary().await.unwrap()).unwrap())
        } else {
            Err(ClientError::Err(response.status()))
        }
    }
}