#![cfg(feature = "axum")]

use athena_auth::adapters::{MemoryDatabaseAdapter, UserOps};
use athena_auth::handlers::AxumIntegration;
use athena_auth::plugins::{
    EmailPasswordPlugin, PasswordManagementPlugin, SessionManagementPlugin,
};
use athena_auth::{AthenaAuth, AuthBuilder, AuthConfig};
use axum::{
    Router, body,
    body::Body,
    http::{HeaderMap, HeaderValue, Method, Request, Response, StatusCode},
};
use body::Bytes;
use serde_json::{Value, json};
use std::sync::Arc;
use tower::ServiceExt; // for oneshot
use tower_http::cors::CorsLayer;

/// Helper to create test AthenaAuth instance with all plugins
async fn create_test_auth() -> Arc<AthenaAuth<MemoryDatabaseAdapter>> {
    let config: AuthConfig = AuthConfig::new("test-secret-key-that-is-at-least-32-characters-long")
        .base_url("http://localhost:3000")
        .password_min_length(6);

    create_test_auth_with_config(config).await
}

/// Helper to create test AthenaAuth instance with a caller-supplied config.
async fn create_test_auth_with_config(
    config: AuthConfig,
) -> Arc<AthenaAuth<MemoryDatabaseAdapter>> {
    let trusted_origins = config.trusted_origins.clone();
    let mut builder = AuthBuilder::new(config);
    if !trusted_origins.is_empty() {
        let mut cors = athena_auth::CorsConfig::new();
        for origin in trusted_origins {
            cors = cors.allowed_origin(origin);
        }
        builder = builder.cors(cors);
    }

    Arc::new(
        builder
            .database(MemoryDatabaseAdapter::new())
            .plugin(EmailPasswordPlugin::new().enable_signup(true))
            .plugin(SessionManagementPlugin::new())
            .plugin(PasswordManagementPlugin::new())
            .build()
            .await
            .expect("Failed to create test auth instance"),
    )
}

/// Helper to create an auth-only router without outer app-layer CORS behavior.
fn create_direct_auth_router(auth: Arc<AthenaAuth<MemoryDatabaseAdapter>>) -> Router {
    Router::new()
        .merge(auth.clone().axum_router())
        .with_state(auth)
}

/// Helper to create the complete Axum router (mimics the example server)
fn create_test_router(auth: Arc<AthenaAuth<MemoryDatabaseAdapter>>) -> Router {
    use axum::{Router, routing::get};

    // Create auth router using the AthenaAuth AxumIntegration
    let auth_router: Router<Arc<AthenaAuth<MemoryDatabaseAdapter>>> = auth.clone().axum_router();

    // Create main application router (simplified version of the example)
    Router::new()
        .route(
            "/api/public",
            get(|| async {
                axum::Json(json!({
                    "message": "This is a public route",
                    "status": "ok"
                }))
            }),
        )
        // Mount auth routes under /auth prefix
        .nest("/auth", auth_router)
        // Add CORS layer
        .layer(CorsLayer::permissive())
        .with_state(auth)
}

/// Helper to create a user and return user data + session token
async fn create_test_user(router: Router) -> (Value, String) {
    create_test_user_at(router, "/auth/sign-up/email", "test@example.com").await
}

/// Helper to create a user at a caller-supplied auth route path.
async fn create_test_user_at(router: Router, path: &str, email: &str) -> (Value, String) {
    let signup_data: Value = json!({
        "email": email,
        "password": "password123",
        "name": "Test User"
    });

    let request: Request<Body> = Request::builder()
        .method(Method::POST)
        .uri(path)
        .header("content-type", "application/json")
        .body(Body::from(signup_data.to_string()))
        .unwrap();

    let response: Response<Body> = router.clone().oneshot(request).await.unwrap();
    assert_eq!(response.status(), StatusCode::OK); // AthenaAuth returns 200, not 201

    let body_bytes: Bytes = body::to_bytes(response.into_body(), usize::MAX)
        .await
        .unwrap();
    let response_data: Value = serde_json::from_slice(&body_bytes).unwrap();

    let token: String = response_data["token"].as_str().unwrap().to_string();
    (response_data, token)
}

/// Test health check endpoint
#[tokio::test]
async fn test_axum_health_check() {
    let auth: Arc<AthenaAuth<MemoryDatabaseAdapter>> = create_test_auth().await;
    let router: Router = create_test_router(auth);

    let request: Request<Body> = Request::builder()
        .method(Method::GET)
        .uri("/auth/health")
        .body(Body::empty())
        .unwrap();

    let response: Response<Body> = router.oneshot(request).await.unwrap();
    assert_eq!(response.status(), StatusCode::OK);

    let body_bytes: Bytes = body::to_bytes(response.into_body(), usize::MAX)
        .await
        .unwrap();
    let response_data: Value = serde_json::from_slice(&body_bytes).unwrap();

    assert_eq!(response_data["status"], "ok");
    assert_eq!(response_data["service"], "athena-auth");
}

/// Test public API endpoint
#[tokio::test]
async fn test_axum_public_endpoint() {
    let auth: Arc<AthenaAuth<MemoryDatabaseAdapter>> = create_test_auth().await;
    let router: Router = create_test_router(auth);

    let request: Request<Body> = Request::builder()
        .method(Method::GET)
        .uri("/api/public")
        .body(Body::empty())
        .unwrap();

    let response: Response<Body> = router.oneshot(request).await.unwrap();
    assert_eq!(response.status(), StatusCode::OK);

    let body_bytes: Bytes = body::to_bytes(response.into_body(), usize::MAX)
        .await
        .unwrap();
    let response_data: Value = serde_json::from_slice(&body_bytes).unwrap();

    assert_eq!(response_data["status"], "ok");
    assert_eq!(response_data["message"], "This is a public route");
}

/// Test user signup via Axum
#[tokio::test]
async fn test_axum_user_signup() {
    let auth: Arc<AthenaAuth<MemoryDatabaseAdapter>> = create_test_auth().await;
    let router: Router = create_test_router(auth);

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

    let request: Request<Body> = Request::builder()
        .method(Method::POST)
        .uri("/auth/sign-up/email")
        .header("content-type", "application/json")
        .body(Body::from(signup_data.to_string()))
        .unwrap();

    let response: Response<Body> = router.oneshot(request).await.unwrap();
    assert_eq!(response.status(), StatusCode::OK);

    let body_bytes: Bytes = body::to_bytes(response.into_body(), usize::MAX)
        .await
        .unwrap();
    let response_data: Value = serde_json::from_slice(&body_bytes).unwrap();

    assert!(response_data["user"]["id"].is_string());
    assert_eq!(response_data["user"]["email"], "signup@example.com");
    assert_eq!(response_data["user"]["name"], "Signup User");
    assert!(response_data["token"].is_string());
}

/// Test user signin via Axum
#[tokio::test]
async fn test_axum_user_signin() {
    let auth: Arc<AthenaAuth<MemoryDatabaseAdapter>> = create_test_auth().await;
    let router: Router = create_test_router(auth);

    // First create a user
    let (_user_data, _token) = create_test_user(router.clone()).await;

    // Then sign in
    let signin_data: Value = json!({
        "email": "test@example.com",
        "password": "password123"
    });

    let request: Request<Body> = Request::builder()
        .method(Method::POST)
        .uri("/auth/sign-in/email")
        .header("content-type", "application/json")
        .body(Body::from(signin_data.to_string()))
        .unwrap();

    let response: Response<Body> = router.oneshot(request).await.unwrap();
    assert_eq!(response.status(), StatusCode::OK);

    let body_bytes: Bytes = body::to_bytes(response.into_body(), usize::MAX)
        .await
        .unwrap();
    let response_data: Value = serde_json::from_slice(&body_bytes).unwrap();

    assert_eq!(response_data["user"]["email"], "test@example.com");
    assert!(response_data["token"].is_string());
}

/// Test invalid signin credentials
#[tokio::test]
async fn test_axum_invalid_signin() {
    let auth: Arc<AthenaAuth<MemoryDatabaseAdapter>> = create_test_auth().await;
    let router: Router = create_test_router(auth);

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

    let request: Request<Body> = Request::builder()
        .method(Method::POST)
        .uri("/auth/sign-in/email")
        .header("content-type", "application/json")
        .body(Body::from(signin_data.to_string()))
        .unwrap();

    let response: Response<Body> = router.oneshot(request).await.unwrap();
    assert_eq!(response.status(), StatusCode::UNAUTHORIZED);
}

/// Test session retrieval via Axum
#[tokio::test]
async fn test_axum_get_session() {
    let auth: Arc<AthenaAuth<MemoryDatabaseAdapter>> = create_test_auth().await;
    let router: Router = create_test_router(auth);

    let (_user_data, token) = create_test_user(router.clone()).await;

    let request: Request<Body> = Request::builder()
        .method(Method::GET)
        .uri("/auth/get-session")
        .header("authorization", format!("Bearer {}", token))
        .body(Body::empty())
        .unwrap();

    let response: Response<Body> = router.oneshot(request).await.unwrap();
    assert_eq!(response.status(), StatusCode::OK);

    let body_bytes: Bytes = body::to_bytes(response.into_body(), usize::MAX)
        .await
        .unwrap();
    let response_data: Value = serde_json::from_slice(&body_bytes).unwrap();

    assert!(response_data["session"]["token"].is_string());
    assert!(response_data["user"]["id"].is_string());
    assert_eq!(response_data["user"]["email"], "test@example.com");
}

#[tokio::test]
async fn test_axum_get_session_reflects_direct_db_role_updates_immediately() {
    let auth: Arc<AthenaAuth<MemoryDatabaseAdapter>> = create_test_auth().await;
    let router: Router = create_test_router(auth.clone());

    let (user_data, token) = create_test_user(router.clone()).await;
    let user_id = user_data["user"]["id"]
        .as_str()
        .expect("signup response missing user.id");

    auth.database()
        .update_user(
            user_id,
            athena_auth::types::UpdateUser {
                role: Some("admin".to_string()),
                ..Default::default()
            },
        )
        .await
        .unwrap();

    let request: Request<Body> = Request::builder()
        .method(Method::GET)
        .uri("/auth/get-session")
        .header("authorization", format!("Bearer {}", token))
        .body(Body::empty())
        .unwrap();

    let response: Response<Body> = router.oneshot(request).await.unwrap();
    assert_eq!(response.status(), StatusCode::OK);

    let body_bytes: Bytes = body::to_bytes(response.into_body(), usize::MAX)
        .await
        .unwrap();
    let response_data: Value = serde_json::from_slice(&body_bytes).unwrap();
    assert_eq!(
        response_data["user"]["role"], "admin",
        "Axum /auth/get-session should re-read the user and reflect the current role immediately"
    );
}

/// Test session list via Axum
#[tokio::test]
async fn test_axum_list_sessions() {
    let auth: Arc<AthenaAuth<MemoryDatabaseAdapter>> = create_test_auth().await;
    let router: Router = create_test_router(auth);

    let (_user_data, token) = create_test_user(router.clone()).await;

    let request: Request<Body> = Request::builder()
        .method(Method::GET)
        .uri("/auth/list-sessions")
        .header("authorization", format!("Bearer {}", token))
        .body(Body::empty())
        .unwrap();

    let response: Response<Body> = router.oneshot(request).await.unwrap();
    assert_eq!(response.status(), StatusCode::OK);

    let body_bytes: Bytes = body::to_bytes(response.into_body(), usize::MAX)
        .await
        .unwrap();
    let sessions: Vec<Value> = serde_json::from_slice(&body_bytes).unwrap();

    assert_eq!(sessions.len(), 1);
    assert!(sessions[0]["token"].is_string());
}

/// Test sign out via Axum
#[tokio::test]
async fn test_axum_sign_out() {
    let auth: Arc<AthenaAuth<MemoryDatabaseAdapter>> = create_test_auth().await;
    let router: Router = create_test_router(auth);

    let (_user_data, token) = create_test_user(router.clone()).await;

    let request: Request<Body> = Request::builder()
        .method(Method::POST)
        .uri("/auth/sign-out")
        .header("authorization", format!("Bearer {}", token))
        .header("content-type", "application/json")
        .body(Body::from("{}"))
        .unwrap();

    let response: Response<Body> = router.oneshot(request).await.unwrap();
    assert_eq!(response.status(), StatusCode::OK);

    let body_bytes: Bytes = body::to_bytes(response.into_body(), usize::MAX)
        .await
        .unwrap();
    let response_data: Value = serde_json::from_slice(&body_bytes).unwrap();

    assert_eq!(response_data["success"], true);
}

/// Test forget password via Axum
#[tokio::test]
async fn test_axum_forget_password() {
    let auth: Arc<AthenaAuth<MemoryDatabaseAdapter>> = create_test_auth().await;
    let router: Router = create_test_router(auth);

    let (_user_data, _token) = create_test_user(router.clone()).await;

    let forget_data: Value = json!({
        "email": "test@example.com",
        "redirectTo": "http://localhost:3000/reset"
    });

    let request: Request<Body> = Request::builder()
        .method(Method::POST)
        .uri("/auth/forget-password")
        .header("content-type", "application/json")
        .body(Body::from(forget_data.to_string()))
        .unwrap();

    let response: Response<Body> = router.oneshot(request).await.unwrap();
    assert_eq!(response.status(), StatusCode::OK);

    let body_bytes: Bytes = body::to_bytes(response.into_body(), usize::MAX)
        .await
        .unwrap();
    let response_data: Value = serde_json::from_slice(&body_bytes).unwrap();

    assert_eq!(response_data["status"], true);
}

/// Test change password via Axum
#[tokio::test]
async fn test_axum_change_password() {
    let auth: Arc<AthenaAuth<MemoryDatabaseAdapter>> = create_test_auth().await;
    let router: Router = create_test_router(auth);

    let (_user_data, token) = create_test_user(router.clone()).await;

    let change_data: Value = json!({
        "currentPassword": "password123",
        "newPassword": "newpassword123",
        "revokeOtherSessions": "false"
    });

    let request: Request<Body> = Request::builder()
        .method(Method::POST)
        .uri("/auth/change-password")
        .header("authorization", format!("Bearer {}", token))
        .header("content-type", "application/json")
        .body(Body::from(change_data.to_string()))
        .unwrap();

    let response: Response<Body> = router.oneshot(request).await.unwrap();
    assert_eq!(response.status(), StatusCode::OK);

    let body_bytes: Bytes = body::to_bytes(response.into_body(), usize::MAX)
        .await
        .unwrap();
    let response_data: Value = serde_json::from_slice(&body_bytes).unwrap();

    assert!(response_data["user"]["id"].is_string());
    assert!(response_data["token"].is_null()); // No new token when not revoking sessions
}

/// Test change password with session revocation via Axum
#[tokio::test]
async fn test_axum_change_password_with_revocation() {
    let auth: Arc<AthenaAuth<MemoryDatabaseAdapter>> = create_test_auth().await;
    let router: Router = create_test_router(auth);

    let (_user_data, token) = create_test_user(router.clone()).await;

    let change_data: Value = json!({
        "currentPassword": "password123",
        "newPassword": "newpassword123",
        "revokeOtherSessions": "true"
    });

    let request: Request<Body> = Request::builder()
        .method(Method::POST)
        .uri("/auth/change-password")
        .header("authorization", format!("Bearer {}", token))
        .header("content-type", "application/json")
        .body(Body::from(change_data.to_string()))
        .unwrap();

    let response: Response<Body> = router.oneshot(request).await.unwrap();
    assert_eq!(response.status(), StatusCode::OK);

    let body_bytes: Bytes = body::to_bytes(response.into_body(), usize::MAX)
        .await
        .unwrap();
    let response_data: Value = serde_json::from_slice(&body_bytes).unwrap();

    assert!(response_data["user"]["id"].is_string());
    assert!(response_data["token"].is_string()); // New token when revoking sessions
}

/// Test unauthorized access to protected endpoints
#[tokio::test]
async fn test_axum_unauthorized_access() {
    let auth: Arc<AthenaAuth<MemoryDatabaseAdapter>> = create_test_auth().await;
    let router: Router = create_test_router(auth);

    // Test get-session without token
    let request: Request<Body> = Request::builder()
        .method(Method::GET)
        .uri("/auth/get-session")
        .body(Body::empty())
        .unwrap();

    let response: Response<Body> = router.clone().oneshot(request).await.unwrap();
    assert_eq!(response.status(), StatusCode::UNAUTHORIZED);

    // Test change-password without token
    let change_data: Value = json!({
        "currentPassword": "password123",
        "newPassword": "newpassword123"
    });

    let request: Request<Body> = Request::builder()
        .method(Method::POST)
        .uri("/auth/change-password")
        .header("content-type", "application/json")
        .body(Body::from(change_data.to_string()))
        .unwrap();

    let response: Response<Body> = router.oneshot(request).await.unwrap();
    assert_eq!(response.status(), StatusCode::UNAUTHORIZED);
}

/// Test invalid JSON handling
#[tokio::test]
async fn test_axum_invalid_json() {
    let auth: Arc<AthenaAuth<MemoryDatabaseAdapter>> = create_test_auth().await;
    let router: Router = create_test_router(auth);

    let request = Request::builder()
        .method(Method::POST)
        .uri("/auth/sign-up/email")
        .header("content-type", "application/json")
        .body(Body::from("invalid json"))
        .unwrap();

    let response = router.oneshot(request).await.unwrap();
    assert_eq!(response.status(), StatusCode::BAD_REQUEST);
}

/// Test missing required fields
#[tokio::test]
async fn test_axum_missing_fields() {
    let auth: Arc<AthenaAuth<MemoryDatabaseAdapter>> = create_test_auth().await;
    let router: Router = create_test_router(auth);

    // Test signup with missing password
    let incomplete_data: Value = json!({
        "email": "incomplete@example.com"
        // missing password
    });

    let request: Request<Body> = Request::builder()
        .method(Method::POST)
        .uri("/auth/sign-up/email")
        .header("content-type", "application/json")
        .body(Body::from(incomplete_data.to_string()))
        .unwrap();

    let response = router.oneshot(request).await.unwrap();
    assert_eq!(response.status(), StatusCode::BAD_REQUEST);
}

/// Test duplicate email handling
#[tokio::test]
async fn test_axum_duplicate_email() {
    let auth: Arc<AthenaAuth<MemoryDatabaseAdapter>> = create_test_auth().await;
    let router: Router = create_test_router(auth);

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

    // First signup should succeed
    let request1: Request<Body> = Request::builder()
        .method(Method::POST)
        .uri("/auth/sign-up/email")
        .header("content-type", "application/json")
        .body(Body::from(signup_data.to_string()))
        .unwrap();

    let response1: Response<Body> = router.clone().oneshot(request1).await.unwrap();
    assert_eq!(response1.status(), StatusCode::OK);

    // Second signup with same email should fail
    let request2: Request<Body> = Request::builder()
        .method(Method::POST)
        .uri("/auth/sign-up/email")
        .header("content-type", "application/json")
        .body(Body::from(signup_data.to_string()))
        .unwrap();

    let response2: Response<Body> = router.oneshot(request2).await.unwrap();
    assert_eq!(response2.status(), StatusCode::CONFLICT);
}

/// Test password validation
#[tokio::test]
async fn test_axum_password_validation() {
    let auth: Arc<AthenaAuth<MemoryDatabaseAdapter>> = create_test_auth().await;
    let router: Router = create_test_router(auth);

    // Test with password too short (less than 6 characters)
    let signup_data: Value = json!({
        "email": "short@example.com",
        "password": "123",
        "name": "Short Password User"
    });

    let request: Request<Body> = Request::builder()
        .method(Method::POST)
        .uri("/auth/sign-up/email")
        .header("content-type", "application/json")
        .body(Body::from(signup_data.to_string()))
        .unwrap();

    let response: Response<Body> = router.oneshot(request).await.unwrap();
    assert_eq!(response.status(), StatusCode::BAD_REQUEST);

    let body_bytes: Bytes = body::to_bytes(response.into_body(), usize::MAX)
        .await
        .unwrap();
    let response_data: Value = serde_json::from_slice(&body_bytes).unwrap();

    // Check password validation message
    let message: &str = response_data["message"].as_str().unwrap();
    assert!(message.contains("6 characters"));
}

/// Test session revocation flow
#[tokio::test]
async fn test_axum_session_revocation_flow() {
    let auth: Arc<AthenaAuth<MemoryDatabaseAdapter>> = create_test_auth().await;
    let router: Router = create_test_router(auth);

    let (_user_data, token1) = create_test_user(router.clone()).await;

    // Create second session by signing in again
    let signin_data: Value = json!({
        "email": "test@example.com",
        "password": "password123"
    });

    let request: Request<Body> = Request::builder()
        .method(Method::POST)
        .uri("/auth/sign-in/email")
        .header("content-type", "application/json")
        .body(Body::from(signin_data.to_string()))
        .unwrap();

    let response: Response<Body> = router.clone().oneshot(request).await.unwrap();
    assert_eq!(response.status(), StatusCode::OK);

    let body_bytes: Bytes = body::to_bytes(response.into_body(), usize::MAX)
        .await
        .unwrap();
    let response_data: Value = serde_json::from_slice(&body_bytes).unwrap();
    let token2: &str = response_data["token"].as_str().unwrap();

    // Verify we have 2 sessions
    let request: Request<Body> = Request::builder()
        .method(Method::GET)
        .uri("/auth/list-sessions")
        .header("authorization", format!("Bearer {}", token1))
        .body(Body::empty())
        .unwrap();

    let response: Response<Body> = router.clone().oneshot(request).await.unwrap();
    assert_eq!(response.status(), StatusCode::OK);

    let body_bytes: Bytes = body::to_bytes(response.into_body(), usize::MAX)
        .await
        .unwrap();
    let sessions: Vec<Value> = serde_json::from_slice(&body_bytes).unwrap();
    assert_eq!(sessions.len(), 2);

    // Revoke the second session using the first session
    let revoke_data: Value = json!({
        "token": token2
    });

    let request: Request<Body> = Request::builder()
        .method(Method::POST)
        .uri("/auth/revoke-session")
        .header("authorization", format!("Bearer {}", token1))
        .header("content-type", "application/json")
        .body(Body::from(revoke_data.to_string()))
        .unwrap();

    let response: Response<Body> = router.clone().oneshot(request).await.unwrap();
    assert_eq!(response.status(), StatusCode::OK);

    let body_bytes: Bytes = body::to_bytes(response.into_body(), usize::MAX)
        .await
        .unwrap();
    let response_data: Value = serde_json::from_slice(&body_bytes).unwrap();
    assert_eq!(response_data["status"], true);

    // Verify token2 is no longer valid
    let request: Request<Body> = Request::builder()
        .method(Method::GET)
        .uri("/auth/get-session")
        .header("authorization", format!("Bearer {}", token2))
        .body(Body::empty())
        .unwrap();

    let response: Response<Body> = router.oneshot(request).await.unwrap();
    assert_eq!(response.status(), StatusCode::UNAUTHORIZED);
}

/// Test revoke all sessions
#[tokio::test]
async fn test_axum_revoke_all_sessions() {
    let auth: Arc<AthenaAuth<MemoryDatabaseAdapter>> = create_test_auth().await;
    let router: Router = create_test_router(auth);

    let (_user_data, token) = create_test_user(router.clone()).await;

    // Revoke all sessions
    let request: Request<Body> = Request::builder()
        .method(Method::POST)
        .uri("/auth/revoke-sessions")
        .header("authorization", format!("Bearer {}", token))
        .header("content-type", "application/json")
        .body(Body::from("{}"))
        .unwrap();

    let response: Response<Body> = router.clone().oneshot(request).await.unwrap();
    assert_eq!(response.status(), StatusCode::OK);

    let body_bytes: Bytes = body::to_bytes(response.into_body(), usize::MAX)
        .await
        .unwrap();
    let response_data: Value = serde_json::from_slice(&body_bytes).unwrap();
    assert_eq!(response_data["status"], true);

    // Verify token is no longer valid
    let request: Request<Body> = Request::builder()
        .method(Method::GET)
        .uri("/auth/get-session")
        .header("authorization", format!("Bearer {}", token))
        .body(Body::empty())
        .unwrap();

    let response: Response<Body> = router.oneshot(request).await.unwrap();
    assert_eq!(response.status(), StatusCode::UNAUTHORIZED);
}

/// Test session cookies are set on sign-up
#[tokio::test]
async fn test_axum_signup_sets_cookie() {
    let auth: Arc<AthenaAuth<MemoryDatabaseAdapter>> = create_test_auth().await;
    let router: Router = create_test_router(auth);

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

    let request: Request<Body> = Request::builder()
        .method(Method::POST)
        .uri("/auth/sign-up/email")
        .header("content-type", "application/json")
        .body(Body::from(signup_data.to_string()))
        .unwrap();

    let response: Response<Body> = router.oneshot(request).await.unwrap();
    assert_eq!(response.status(), StatusCode::OK);

    // Check that Set-Cookie header is present
    let headers: &HeaderMap = response.headers();
    let cookie_header: Option<&HeaderValue> = headers.get("set-cookie");
    assert!(
        cookie_header.is_some(),
        "Set-Cookie header should be present"
    );

    let cookie_value: &str = cookie_header.unwrap().to_str().unwrap();
    assert!(
        cookie_value.contains("athena-auth.session-token="),
        "Cookie should contain session token"
    );
    assert!(cookie_value.contains("Path=/"), "Cookie should have Path=/");
    assert!(
        cookie_value.contains("HttpOnly"),
        "Cookie should be HttpOnly"
    );
    assert!(
        cookie_value.contains("SameSite=Lax"),
        "Cookie should have SameSite=Lax"
    );
}

/// Test session cookies are set on sign-in
#[tokio::test]
async fn test_axum_signin_sets_cookie() {
    let auth: Arc<AthenaAuth<MemoryDatabaseAdapter>> = create_test_auth().await;
    let router: Router = create_test_router(auth);

    // First create a user
    let (_user_data, _token) = create_test_user(router.clone()).await;

    // Then sign in
    let signin_data: Value = json!({
        "email": "test@example.com",
        "password": "password123"
    });

    let request: Request<Body> = Request::builder()
        .method(Method::POST)
        .uri("/auth/sign-in/email")
        .header("content-type", "application/json")
        .body(Body::from(signin_data.to_string()))
        .unwrap();

    let response = router.oneshot(request).await.unwrap();
    assert_eq!(response.status(), StatusCode::OK);

    // Check that Set-Cookie header is present
    let headers = response.headers();
    let cookie_header = headers.get("set-cookie");
    assert!(
        cookie_header.is_some(),
        "Set-Cookie header should be present"
    );

    let cookie_value = cookie_header.unwrap().to_str().unwrap();
    assert!(
        cookie_value.contains("athena-auth.session-token="),
        "Cookie should contain session token"
    );
    assert!(cookie_value.contains("Path=/"), "Cookie should have Path=/");
    assert!(
        cookie_value.contains("HttpOnly"),
        "Cookie should be HttpOnly"
    );
    assert!(
        cookie_value.contains("SameSite=Lax"),
        "Cookie should have SameSite=Lax"
    );
}

/// Test session cookie is cleared on sign-out
#[tokio::test]
async fn test_axum_signout_clears_cookie() {
    let auth: Arc<AthenaAuth<MemoryDatabaseAdapter>> = create_test_auth().await;
    let router: Router = create_test_router(auth);

    let (_user_data, token) = create_test_user(router.clone()).await;

    let request: Request<Body> = Request::builder()
        .method(Method::POST)
        .uri("/auth/sign-out")
        .header("authorization", format!("Bearer {}", token))
        .header("content-type", "application/json")
        .body(Body::from("{}"))
        .unwrap();

    let response: Response<Body> = router.oneshot(request).await.unwrap();
    assert_eq!(response.status(), StatusCode::OK);

    // Check that Set-Cookie header is present and clears the cookie
    let headers: &HeaderMap = response.headers();
    let cookie_header: Option<&HeaderValue> = headers.get("set-cookie");
    assert!(
        cookie_header.is_some(),
        "Set-Cookie header should be present to clear cookie"
    );

    let cookie_value = cookie_header.unwrap().to_str().unwrap();
    assert!(
        cookie_value.contains("athena-auth.session-token="),
        "Cookie should contain session token name"
    );
    assert!(
        cookie_value.contains("Expires=Thu, 01 Jan 1970"),
        "Cookie should be expired to clear it"
    );
    assert!(cookie_value.contains("Path=/"), "Cookie should have Path=/");
}

#[tokio::test]
async fn test_axum_direct_auth_signin_sets_shared_parent_cookie_and_cors_headers() {
    let config = AuthConfig::new("test-secret-key-that-is-at-least-32-characters-long")
        .base_url("https://auth.athena-auth.com")
        .password_min_length(6)
        .trusted_origins(vec!["https://ui.athena-auth.com".to_string()]);
    let auth: Arc<AthenaAuth<MemoryDatabaseAdapter>> = create_test_auth_with_config(config).await;
    let router: Router = create_direct_auth_router(auth);

    let (_user_data, _token) = create_test_user_at(
        router.clone(),
        "/sign-up/email",
        "shared-cookie@example.com",
    )
    .await;

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

    let request: Request<Body> = Request::builder()
        .method(Method::POST)
        .uri("/sign-in/email")
        .header("content-type", "application/json")
        .header("origin", "https://ui.athena-auth.com")
        .body(Body::from(signin_data.to_string()))
        .unwrap();

    let response: Response<Body> = router.oneshot(request).await.unwrap();
    assert_eq!(response.status(), StatusCode::OK);

    let headers = response.headers();
    assert_eq!(
        headers
            .get("access-control-allow-origin")
            .and_then(|value| value.to_str().ok()),
        Some("https://ui.athena-auth.com")
    );
    assert_eq!(
        headers
            .get("access-control-allow-credentials")
            .and_then(|value| value.to_str().ok()),
        Some("true")
    );

    let cookie_value = headers
        .get("set-cookie")
        .and_then(|value| value.to_str().ok())
        .expect("sign-in should set a session cookie");
    assert!(cookie_value.contains("athena-auth.session-token="));
    assert!(cookie_value.contains("Domain=.athena-auth.com"));
    assert!(cookie_value.contains("Path=/"));
    assert!(cookie_value.contains("Secure"));
    assert!(cookie_value.contains("HttpOnly"));
    assert!(cookie_value.contains("SameSite=Lax"));
}

#[tokio::test]
async fn test_axum_direct_auth_signout_clears_shared_parent_cookie() {
    let config = AuthConfig::new("test-secret-key-that-is-at-least-32-characters-long")
        .base_url("https://auth.athena-auth.com")
        .password_min_length(6)
        .trusted_origins(vec!["https://ui.athena-auth.com".to_string()]);
    let auth: Arc<AthenaAuth<MemoryDatabaseAdapter>> = create_test_auth_with_config(config).await;
    let router: Router = create_direct_auth_router(auth);

    let (_user_data, token) = create_test_user_at(
        router.clone(),
        "/sign-up/email",
        "shared-signout@example.com",
    )
    .await;

    let request: Request<Body> = Request::builder()
        .method(Method::POST)
        .uri("/sign-out")
        .header("authorization", format!("Bearer {}", token))
        .header("origin", "https://ui.athena-auth.com")
        .header("content-type", "application/json")
        .body(Body::from("{}"))
        .unwrap();

    let response: Response<Body> = router.oneshot(request).await.unwrap();
    assert_eq!(response.status(), StatusCode::OK);

    let headers = response.headers();
    assert_eq!(
        headers
            .get("access-control-allow-origin")
            .and_then(|value| value.to_str().ok()),
        Some("https://ui.athena-auth.com")
    );
    assert_eq!(
        headers
            .get("access-control-allow-credentials")
            .and_then(|value| value.to_str().ok()),
        Some("true")
    );

    let cookie_value = headers
        .get("set-cookie")
        .and_then(|value| value.to_str().ok())
        .expect("sign-out should clear the session cookie");
    assert!(cookie_value.contains("athena-auth.session-token="));
    assert!(cookie_value.contains("Domain=.athena-auth.com"));
    assert!(cookie_value.contains("Expires=Thu, 01 Jan 1970"));
    assert!(cookie_value.contains("Path=/"));
    assert!(cookie_value.contains("Secure"));
    assert!(cookie_value.contains("HttpOnly"));
    assert!(cookie_value.contains("SameSite=Lax"));
}

/// Test 404 for non-existent routes
#[tokio::test]
async fn test_axum_404_routes() {
    let auth: Arc<AthenaAuth<MemoryDatabaseAdapter>> = create_test_auth().await;
    let router: Router = create_test_router(auth);

    let request: Request<Body> = Request::builder()
        .method(Method::GET)
        .uri("/auth/non-existent-route")
        .body(Body::empty())
        .unwrap();

    let response: Response<Body> = router.oneshot(request).await.unwrap();
    assert_eq!(response.status(), StatusCode::NOT_FOUND);
}

/// Test user profile update
#[tokio::test]
async fn test_axum_update_user() {
    let auth: Arc<AthenaAuth<MemoryDatabaseAdapter>> = create_test_auth().await;
    let router: Router = create_test_router(auth);

    let (_user_data, token) = create_test_user(router.clone()).await;

    let update_data: Value = json!({
        "name": "Updated Test User",
        "email": "updated@example.com",
        "username": "updateduser",
        "displayUsername": "Updated User"
    });

    let request: Request<Body> = Request::builder()
        .method(Method::POST)
        .uri("/auth/update-user")
        .header("authorization", format!("Bearer {}", token))
        .header("content-type", "application/json")
        .body(Body::from(update_data.to_string()))
        .unwrap();

    let response: Response<Body> = router.oneshot(request).await.unwrap();
    assert_eq!(response.status(), StatusCode::OK);

    let body_bytes: Bytes = body::to_bytes(response.into_body(), usize::MAX)
        .await
        .unwrap();
    let response_data: Value = serde_json::from_slice(&body_bytes).unwrap();

    assert_eq!(response_data["status"], true);
}

/// Test unauthorized user profile update
#[tokio::test]
async fn test_axum_update_user_unauthorized() {
    let auth: Arc<AthenaAuth<MemoryDatabaseAdapter>> = create_test_auth().await;
    let router: Router = create_test_router(auth);

    let update_data: Value = json!({
        "name": "Updated Test User"
    });

    let request: Request<Body> = Request::builder()
        .method(Method::POST)
        .uri("/auth/update-user")
        .header("content-type", "application/json")
        .body(Body::from(update_data.to_string()))
        .unwrap();

    let response: Response<Body> = router.oneshot(request).await.unwrap();
    assert_eq!(response.status(), StatusCode::UNAUTHORIZED);
}

/// Test user profile update with invalid JSON
#[tokio::test]
async fn test_axum_update_user_invalid_json() {
    let auth: Arc<AthenaAuth<MemoryDatabaseAdapter>> = create_test_auth().await;
    let router: Router = create_test_router(auth);

    let (_user_data, token) = create_test_user(router.clone()).await;

    let request: Request<Body> = Request::builder()
        .method(Method::POST)
        .uri("/auth/update-user")
        .header("authorization", format!("Bearer {}", token))
        .header("content-type", "application/json")
        .body(Body::from("invalid json"))
        .unwrap();

    let response: Response<Body> = router.oneshot(request).await.unwrap();
    assert_eq!(response.status(), StatusCode::BAD_REQUEST);
}

/// Test user deletion
#[tokio::test]
async fn test_axum_delete_user() {
    let auth: Arc<AthenaAuth<MemoryDatabaseAdapter>> = create_test_auth().await;
    let router: Router = create_test_router(auth);

    let (_user_data, token) = create_test_user(router.clone()).await;

    let request: Request<Body> = Request::builder()
        .method(Method::DELETE)
        .uri("/auth/delete-user")
        .header("authorization", format!("Bearer {}", token))
        .body(Body::empty())
        .unwrap();

    let response: Response<Body> = router.oneshot(request).await.unwrap();
    assert_eq!(response.status(), StatusCode::OK);

    let body_bytes: Bytes = body::to_bytes(response.into_body(), usize::MAX)
        .await
        .unwrap();
    let response_data: Value = serde_json::from_slice(&body_bytes).unwrap();

    assert_eq!(response_data["success"], true);
    assert_eq!(
        response_data["message"],
        "User account successfully deleted"
    );
}

/// Test unauthorized user deletion
#[tokio::test]
async fn test_axum_delete_user_unauthorized() {
    let auth: Arc<AthenaAuth<MemoryDatabaseAdapter>> = create_test_auth().await;
    let router: Router = create_test_router(auth);

    let request: Request<Body> = Request::builder()
        .method(Method::DELETE)
        .uri("/auth/delete-user")
        .body(Body::empty())
        .unwrap();

    let response = router.oneshot(request).await.unwrap();
    assert_eq!(response.status(), StatusCode::UNAUTHORIZED);
}

/// Test user deletion invalidates sessions
#[tokio::test]
async fn test_axum_delete_user_invalidates_sessions() {
    let auth: Arc<AthenaAuth<MemoryDatabaseAdapter>> = create_test_auth().await;
    let router: Router = create_test_router(auth);

    let (_user_data, token) = create_test_user(router.clone()).await;

    // Delete the user
    let delete_request: Request<Body> = Request::builder()
        .method(Method::DELETE)
        .uri("/auth/delete-user")
        .header("authorization", format!("Bearer {}", token))
        .body(Body::empty())
        .unwrap();

    let delete_response: Response<Body> = router.clone().oneshot(delete_request).await.unwrap();
    assert_eq!(delete_response.status(), StatusCode::OK);

    // Try to use the same token - should be unauthorized
    let session_request: Request<Body> = Request::builder()
        .method(Method::GET)
        .uri("/auth/get-session")
        .header("authorization", format!("Bearer {}", token))
        .body(Body::empty())
        .unwrap();

    let session_response: Response<Body> = router.oneshot(session_request).await.unwrap();
    assert_eq!(session_response.status(), StatusCode::UNAUTHORIZED);
}

/// Test user profile management workflow
#[tokio::test]
async fn test_axum_user_profile_workflow() {
    let auth: Arc<AthenaAuth<MemoryDatabaseAdapter>> = create_test_auth().await;
    let router: Router = create_test_router(auth);

    // 1. Create user
    let (_user_data, token) = create_test_user(router.clone()).await;

    // 2. Update profile multiple times
    let update1_data: Value = json!({
        "name": "First Update",
        "username": "firstupdate"
    });

    let request1: Request<Body> = Request::builder()
        .method(Method::POST)
        .uri("/auth/update-user")
        .header("authorization", format!("Bearer {}", token))
        .header("content-type", "application/json")
        .body(Body::from(update1_data.to_string()))
        .unwrap();

    let response1: Response<Body> = router.clone().oneshot(request1).await.unwrap();
    assert_eq!(response1.status(), StatusCode::OK);

    // 3. Update profile again
    let update2_data: Value = json!({
        "name": "Second Update",
        "image": "http://localhost:3000/avatar.jpg"
    });

    let request2: Request<Body> = Request::builder()
        .method(Method::POST)
        .uri("/auth/update-user")
        .header("authorization", format!("Bearer {}", token))
        .header("content-type", "application/json")
        .body(Body::from(update2_data.to_string()))
        .unwrap();

    let response2: Response<Body> = router.clone().oneshot(request2).await.unwrap();
    assert_eq!(response2.status(), StatusCode::OK);

    let body_bytes: Bytes = body::to_bytes(response2.into_body(), usize::MAX)
        .await
        .unwrap();
    let response_data: Value = serde_json::from_slice(&body_bytes).unwrap();

    // Response should be { status: true }
    assert_eq!(response_data["status"], true);

    // 4. Get current session to verify user data is updated
    let session_request: Request<Body> = Request::builder()
        .method(Method::GET)
        .uri("/auth/get-session")
        .header("authorization", format!("Bearer {}", token))
        .body(Body::empty())
        .unwrap();

    let session_response: Response<Body> = router.clone().oneshot(session_request).await.unwrap();
    assert_eq!(session_response.status(), StatusCode::OK);

    let session_body: Bytes = body::to_bytes(session_response.into_body(), usize::MAX)
        .await
        .unwrap();
    let session_data: Value = serde_json::from_slice(&session_body).unwrap();

    assert_eq!(session_data["user"]["name"], "Second Update");
    assert_eq!(session_data["user"]["username"], "firstupdate");
    assert_eq!(
        session_data["user"]["image"],
        "http://localhost:3000/avatar.jpg"
    );

    // 5. Finally delete the user
    let delete_request: Request<Body> = Request::builder()
        .method(Method::DELETE)
        .uri("/auth/delete-user")
        .header("authorization", format!("Bearer {}", token))
        .body(Body::empty())
        .unwrap();

    let delete_response: Response<Body> = router.oneshot(delete_request).await.unwrap();
    assert_eq!(delete_response.status(), StatusCode::OK);
}

/// Test comprehensive authentication workflow
#[tokio::test]
async fn test_axum_complete_workflow() {
    let auth: Arc<AthenaAuth<MemoryDatabaseAdapter>> = create_test_auth().await;
    let router: Router = create_test_router(auth);

    // 1. Sign up
    let signup_data: Value = json!({
        "email": "workflow@example.com",
        "password": "password123",
        "name": "Workflow User"
    });

    let request: Request<Body> = Request::builder()
        .method(Method::POST)
        .uri("/auth/sign-up/email")
        .header("content-type", "application/json")
        .body(Body::from(signup_data.to_string()))
        .unwrap();

    let response: Response<Body> = router.clone().oneshot(request).await.unwrap();
    assert_eq!(response.status(), StatusCode::OK);

    let body_bytes: Bytes = body::to_bytes(response.into_body(), usize::MAX)
        .await
        .unwrap();
    let signup_response: Value = serde_json::from_slice(&body_bytes).unwrap();
    let _signup_token: &str = signup_response["token"].as_str().unwrap();

    // 2. Sign in to get a new session
    let signin_data: Value = json!({
        "email": "workflow@example.com",
        "password": "password123"
    });

    let request: Request<Body> = Request::builder()
        .method(Method::POST)
        .uri("/auth/sign-in/email")
        .header("content-type", "application/json")
        .body(Body::from(signin_data.to_string()))
        .unwrap();

    let response: Response<Body> = router.clone().oneshot(request).await.unwrap();
    assert_eq!(response.status(), StatusCode::OK);

    let body_bytes: Bytes = body::to_bytes(response.into_body(), usize::MAX)
        .await
        .unwrap();
    let signin_response: Value = serde_json::from_slice(&body_bytes).unwrap();
    let signin_token = signin_response["token"].as_str().unwrap();

    // 3. Get session info
    let request: Request<Body> = Request::builder()
        .method(Method::GET)
        .uri("/auth/get-session")
        .header("authorization", format!("Bearer {}", signin_token))
        .body(Body::empty())
        .unwrap();

    let response: Response<Body> = router.clone().oneshot(request).await.unwrap();
    assert_eq!(response.status(), StatusCode::OK);

    // 4. List sessions (should have 2)
    let request: Request<Body> = Request::builder()
        .method(Method::GET)
        .uri("/auth/list-sessions")
        .header("authorization", format!("Bearer {}", signin_token))
        .body(Body::empty())
        .unwrap();

    let response: Response<Body> = router.clone().oneshot(request).await.unwrap();
    assert_eq!(response.status(), StatusCode::OK);

    let body_bytes: Bytes = body::to_bytes(response.into_body(), usize::MAX)
        .await
        .unwrap();
    let sessions: Vec<Value> = serde_json::from_slice(&body_bytes).unwrap();
    assert_eq!(sessions.len(), 2);

    // 5. Change password
    let change_data: Value = json!({
        "currentPassword": "password123",
        "newPassword": "newpassword123",
        "revokeOtherSessions": "false"
    });

    let request: Request<Body> = Request::builder()
        .method(Method::POST)
        .uri("/auth/change-password")
        .header("authorization", format!("Bearer {}", signin_token))
        .header("content-type", "application/json")
        .body(Body::from(change_data.to_string()))
        .unwrap();

    let response: Response<Body> = router.clone().oneshot(request).await.unwrap();
    assert_eq!(response.status(), StatusCode::OK);

    // 6. Sign out
    let request: Request<Body> = Request::builder()
        .method(Method::POST)
        .uri("/auth/sign-out")
        .header("authorization", format!("Bearer {}", signin_token))
        .header("content-type", "application/json")
        .body(Body::from("{}"))
        .unwrap();

    let response: Response<Body> = router.clone().oneshot(request).await.unwrap();
    assert_eq!(response.status(), StatusCode::OK);

    // 7. Verify session is invalidated
    let request: Request<Body> = Request::builder()
        .method(Method::GET)
        .uri("/auth/get-session")
        .header("authorization", format!("Bearer {}", signin_token))
        .body(Body::empty())
        .unwrap();

    let response: Response<Body> = router.oneshot(request).await.unwrap();
    assert_eq!(response.status(), StatusCode::UNAUTHORIZED);
}
