use reqwest::Client;
use serde_json::{json, Value};

const BASE_URL: &str = "http://127.0.0.1:8000";

#[tokio::test]
async fn test_health_check() {
    let client = Client::new();
    let response = client
        .get(format!("{}/health", BASE_URL))
        .send()
        .await
        .expect("Failed to send request");

    assert_eq!(response.status(), 200);
}

#[tokio::test]
async fn test_ready_check() {
    let client = Client::new();
    let response = client
        .get(format!("{}/ready", BASE_URL))
        .send()
        .await
        .expect("Failed to send request");

    assert_eq!(response.status(), 200);
}

#[tokio::test]
async fn test_register_user() {
    let client = Client::new();
    let email = format!("test_{}@example.com", uuid::Uuid::new_v4());

    let payload = json!({
        "email": email,
        "password_hash": "hashed_password_placeholder",
        "encrypted_recovery_phrase": "encrypted_phrase_placeholder",
        "recovery_phrase_iv": "iv_placeholder",
        "recovery_phrase_auth_tag": "auth_tag_placeholder"
    });

    let response = client
        .post(format!("{}/api/auth/register", BASE_URL))
        .json(&payload)
        .send()
        .await
        .expect("Failed to send request");

    assert_eq!(response.status(), 200);

    let json: Value = response.json().await.expect("Failed to parse JSON");
    assert_eq!(json["email"], email);
    assert!(json["user_id"].is_string());
}

#[tokio::test]
async fn test_login() {
    let client = Client::new();
    let email = format!("test_{}@example.com", uuid::Uuid::new_v4());

    // First register a user
    let register_payload = json!({
        "email": email,
        "password_hash": "hashed_password_placeholder",
        "encrypted_recovery_phrase": "encrypted_phrase_placeholder",
        "recovery_phrase_iv": "iv_placeholder",
        "recovery_phrase_auth_tag": "auth_tag_placeholder"
    });

    let _reg_response = client
        .post(format!("{}/api/auth/register", BASE_URL))
        .json(&register_payload)
        .send()
        .await
        .expect("Failed to send request");

    // Now login
    let login_payload = json!({
        "email": email,
        "password_hash": "hashed_password_placeholder"
    });

    let response = client
        .post(format!("{}/api/auth/login", BASE_URL))
        .json(&login_payload)
        .send()
        .await
        .expect("Failed to send request");

    assert_eq!(response.status(), 200);

    let json: Value = response.json().await.expect("Failed to parse JSON");
    assert!(json["access_token"].is_string());
    assert!(json["refresh_token"].is_string());
    assert_eq!(json["email"], email);
}

#[tokio::test]
async fn test_get_profile_without_auth() {
    let client = Client::new();

    let response = client
        .get(format!("{}/api/users/me", BASE_URL))
        .send()
        .await
        .expect("Failed to send request");

    // Should return 401 Unauthorized without auth token
    assert_eq!(response.status(), 401);
}

#[tokio::test]
async fn test_get_profile_with_auth() {
    let client = Client::new();
    let email = format!("test_{}@example.com", uuid::Uuid::new_v4());

    // Register and login
    let register_payload = json!({
        "email": email,
        "password_hash": "hashed_password_placeholder",
        "encrypted_recovery_phrase": "encrypted_phrase_placeholder",
        "recovery_phrase_iv": "iv_placeholder",
        "recovery_phrase_auth_tag": "auth_tag_placeholder"
    });

    client
        .post(format!("{}/api/auth/register", BASE_URL))
        .json(&register_payload)
        .send()
        .await
        .expect("Failed to send request");

    let login_payload = json!({
        "email": email,
        "password_hash": "hashed_password_placeholder"
    });

    let login_response = client
        .post(format!("{}/api/auth/login", BASE_URL))
        .json(&login_payload)
        .send()
        .await
        .expect("Failed to send request");

    let login_json: Value = login_response.json().await.expect("Failed to parse JSON");
    let access_token = login_json["access_token"]
        .as_str()
        .expect("No access token");

    // Get profile with auth token
    let response = client
        .get(format!("{}/api/users/me", BASE_URL))
        .header("Authorization", format!("Bearer {}", access_token))
        .send()
        .await
        .expect("Failed to send request");

    assert_eq!(response.status(), 200);

    let json: Value = response.json().await.expect("Failed to parse JSON");
    assert_eq!(json["email"], email);
}
