#![allow(unused_imports)]
use super::*;
use serde_json::json;

fn test_config() -> AuthConfig {
    AuthConfig::new("test-secret-key-that-is-at-least-32-characters-long")
        .base_url("http://localhost:3000")
        .password_min_length(8)
}

async fn create_test_auth() -> AthenaAuth<MemoryDatabaseAdapter> {
    AuthBuilder::new(test_config())
        .database(MemoryDatabaseAdapter::new())
        .plugin(plugins::EmailPasswordPlugin::new().enable_signup(true))
        .build()
        .await
        .expect("Failed to create test auth instance")
}

#[tokio::test]
async fn test_auth_builder() {
    let auth = create_test_auth().await;
    assert_eq!(auth.plugin_names(), vec!["email-password"]);
    assert_eq!(
        auth.config().secret,
        "test-secret-key-that-is-at-least-32-characters-long"
    );
}

#[tokio::test]
async fn test_signup_flow() {
    let auth = create_test_auth().await;

    let signup_data = json!({
        "email": "test@example.com",
        "password": "password123",
        "name": "Test User"
    });

    let mut request = AuthRequest::new(HttpMethod::Post, "/sign-up/email");
    request.body = Some(signup_data.to_string().into_bytes());
    request
        .headers
        .insert("content-type".to_string(), "application/json".to_string());

    let response = auth
        .handle_request(request)
        .await
        .expect("Signup request failed");

    assert_eq!(response.status, 200);

    let response_json: serde_json::Value =
        serde_json::from_slice(&response.body).expect("Failed to parse response JSON");

    assert!(response_json["user"]["id"].is_string());
    assert_eq!(response_json["user"]["email"], "test@example.com");
    assert_eq!(response_json["user"]["name"], "Test User");
    assert!(response_json["token"].is_string());
}

#[tokio::test]
async fn test_signin_flow() {
    let auth = create_test_auth().await;

    let signup_data = json!({
        "email": "signin@example.com",
        "password": "password123",
        "name": "Signin User"
    });

    let mut signup_request = AuthRequest::new(HttpMethod::Post, "/sign-up/email");
    signup_request.body = Some(signup_data.to_string().into_bytes());
    signup_request
        .headers
        .insert("content-type".to_string(), "application/json".to_string());

    let signup_response = auth
        .handle_request(signup_request)
        .await
        .expect("Signup failed");
    assert_eq!(signup_response.status, 200);

    let signin_data = json!({
        "email": "signin@example.com",
        "password": "password123"
    });

    let mut signin_request = AuthRequest::new(HttpMethod::Post, "/sign-in/email");
    signin_request.body = Some(signin_data.to_string().into_bytes());
    signin_request
        .headers
        .insert("content-type".to_string(), "application/json".to_string());
    signin_request
        .headers
        .insert("x-forwarded-for".to_string(), "203.0.113.21".to_string());

    let signin_response = auth
        .handle_request(signin_request)
        .await
        .expect("Signin failed");
    assert_eq!(signin_response.status, 200);

    let response_json: serde_json::Value =
        serde_json::from_slice(&signin_response.body).expect("Failed to parse signin response");

    assert_eq!(response_json["user"]["email"], "signin@example.com");
    assert!(response_json["token"].is_string());
    assert!(response_json["session"].is_object());
    assert_eq!(
        response_json["session"]["ipAddress"].as_str(),
        Some("203.0.113.21")
    );
}

#[tokio::test]
async fn test_signin_persists_forwarded_ip_on_session() {
    let auth = create_test_auth().await;

    let signup_data = json!({
        "email": "signin-ip@example.com",
        "password": "password123",
        "name": "Signin IP User"
    });

    let mut signup_request = AuthRequest::new(HttpMethod::Post, "/sign-up/email");
    signup_request.body = Some(signup_data.to_string().into_bytes());
    signup_request
        .headers
        .insert("content-type".to_string(), "application/json".to_string());

    let signup_response = auth
        .handle_request(signup_request)
        .await
        .expect("Signup failed");
    assert_eq!(signup_response.status, 200);
    let signin_data = json!({
        "email": "signin-ip@example.com",
        "password": "password123"
    });
    let mut signin_request = AuthRequest::new(HttpMethod::Post, "/sign-in/email");
    signin_request.body = Some(signin_data.to_string().into_bytes());
    signin_request
        .headers
        .insert("content-type".to_string(), "application/json".to_string());
    signin_request
        .headers
        .insert("x-forwarded-for".to_string(), "203.0.113.42".to_string());

    let signin_response = auth
        .handle_request(signin_request)
        .await
        .expect("Signin failed");
    assert_eq!(signin_response.status, 200);
    let signin_json: serde_json::Value =
        serde_json::from_slice(&signin_response.body).expect("Failed to parse signin JSON");
    let token = signin_json["token"]
        .as_str()
        .expect("signin token must be present")
        .to_string();

    let session = auth
        .session_manager()
        .get_session(&token)
        .await
        .expect("session lookup failed")
        .expect("session must exist");
    assert_eq!(session.ip_address.as_deref(), Some("203.0.113.42"));
}

#[tokio::test]
async fn test_signup_persists_forwarded_ip_on_created_session() {
    let auth = create_test_auth().await;

    let signup_data = json!({
        "email": "signup-ip@example.com",
        "password": "password123",
        "name": "Signup IP User"
    });

    let mut signup_request = AuthRequest::new(HttpMethod::Post, "/sign-up/email");
    signup_request.body = Some(signup_data.to_string().into_bytes());
    signup_request
        .headers
        .insert("content-type".to_string(), "application/json".to_string());
    signup_request
        .headers
        .insert("x-forwarded-for".to_string(), "203.0.113.41".to_string());

    let signup_response = auth
        .handle_request(signup_request)
        .await
        .expect("Signup failed");
    assert_eq!(signup_response.status, 200);

    let signup_json: serde_json::Value =
        serde_json::from_slice(&signup_response.body).expect("Failed to parse signup JSON");
    let token = signup_json["token"]
        .as_str()
        .expect("signup token must be present")
        .to_string();

    let session = auth
        .session_manager()
        .get_session(&token)
        .await
        .expect("session lookup failed")
        .expect("session must exist");
    assert_eq!(session.ip_address.as_deref(), Some("203.0.113.41"));
}

#[tokio::test]
async fn test_duplicate_email_signup() {
    let auth = create_test_auth().await;

    let signup_data = json!({
        "name": "Duplicate User",
        "email": "duplicate@example.com",
        "password": "password123"
    });

    let mut request = AuthRequest::new(HttpMethod::Post, "/sign-up/email");
    request.body = Some(signup_data.to_string().into_bytes());
    request
        .headers
        .insert("content-type".to_string(), "application/json".to_string());

    let response1 = auth
        .handle_request(request.clone())
        .await
        .expect("First signup failed");
    assert_eq!(response1.status, 200);

    let response2 = auth
        .handle_request(request)
        .await
        .expect("Second signup request failed");
    assert_eq!(response2.status, 409);
}

#[tokio::test]
async fn test_invalid_credentials_signin() {
    let auth = create_test_auth().await;

    let signin_data = json!({
        "email": "nonexistent@example.com",
        "password": "password123"
    });

    let mut request = AuthRequest::new(HttpMethod::Post, "/sign-in/email");
    request.body = Some(signin_data.to_string().into_bytes());
    request
        .headers
        .insert("content-type".to_string(), "application/json".to_string());

    let response = auth
        .handle_request(request)
        .await
        .expect("Request should not panic");
    assert_eq!(response.status, 401);
}

#[tokio::test]
async fn test_weak_password_validation() {
    let auth = create_test_auth().await;

    let signup_data = json!({
        "email": "weak@example.com",
        "password": "123",
        "name": "Weak Password User"
    });

    let mut request = AuthRequest::new(HttpMethod::Post, "/sign-up/email");
    request.body = Some(signup_data.to_string().into_bytes());
    request
        .headers
        .insert("content-type".to_string(), "application/json".to_string());

    let response = auth
        .handle_request(request)
        .await
        .expect("Request should not panic");
    assert_eq!(response.status, 400);

    let response_json: serde_json::Value =
        serde_json::from_slice(&response.body).expect("Failed to parse response");
    assert!(
        response_json["message"]
            .as_str()
            .unwrap_or("")
            .contains("Password must be at least")
    );
}

#[tokio::test]
async fn test_session_management() {
    let auth = create_test_auth().await;
    let session_manager = auth.session_manager();

    let database = auth.database();
    let create_user = CreateUser::new()
        .with_email("session@example.com")
        .with_name("Session User");

    let user = database
        .create_user(create_user)
        .await
        .expect("Failed to create user");

    let session = session_manager
        .create_session(&user, None, None)
        .await
        .expect("Failed to create session");

    assert!(session.token.starts_with("session_"));
    assert_eq!(session.user_id, user.id);
    assert!(session.active);

    let retrieved_session = session_manager
        .get_session(&session.token)
        .await
        .expect("Failed to get session")
        .expect("Session not found");

    assert_eq!(retrieved_session.id, session.id);
    assert_eq!(retrieved_session.user_id, user.id);

    session_manager
        .delete_session(&session.token)
        .await
        .expect("Failed to delete session");

    let deleted_session = session_manager
        .get_session(&session.token)
        .await
        .expect("Failed to check deleted session");
    assert!(deleted_session.is_none());
}

#[tokio::test]
async fn test_token_format_validation() {
    let auth = create_test_auth().await;
    let session_manager = auth.session_manager();

    assert!(
        session_manager.validate_token_format("session_abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMN")
    );
    assert!(!session_manager.validate_token_format("invalid_token"));
    assert!(!session_manager.validate_token_format("session_short"));
    assert!(!session_manager.validate_token_format(""));
}

#[tokio::test]
async fn test_health_check_route() {
    let auth = create_test_auth().await;

    let request = AuthRequest::new(HttpMethod::Get, "/health");
    let response = auth
        .handle_request(request)
        .await
        .expect("Health check failed");

    assert_eq!(response.status, 200);
    let payload: serde_json::Value =
        serde_json::from_slice(&response.body).expect("health response should be valid json");
    assert_eq!(payload["status"], "ok");
    assert_eq!(payload["service"], "athena-auth");
}

#[tokio::test]
async fn test_config_validation() {
    let config = AuthConfig::new("");
    assert!(config.validate().is_err());

    let config = AuthConfig::new("short");
    assert!(config.validate().is_err());

    let config = AuthConfig::new("this-is-a-valid-32-character-secret-key");
    assert!(config.validate().is_ok());
}
