//! HTTP handlers for user management endpoints.

use sqlx_pool_router::PoolProvider;

use crate::{
    AppState,
    api::models::{
        groups::GroupResponse,
        pagination::PaginatedResponse,
        users::{CurrentUser, GetUserQuery, ListUsersQuery, UserCreate, UserResponse, UserUpdate},
    },
    auth::permissions::{self as permissions, RequiresPermission, can_read_all_resources, can_read_own_resource, operation, resource},
    db::{
        handlers::{Credits, Groups, Organizations, Repository, Users, users::UserFilter},
        models::users::{UserCreateDBRequest, UserUpdateDBRequest},
    },
    errors::{Error, Result},
    types::{GroupId, Operation, Permission, Resource, UserId, UserIdOrCurrent},
};
use axum::{
    extract::{Path, Query, State},
    http::StatusCode,
    response::Json,
};
use rust_decimal::prelude::ToPrimitive;
use serde::{Deserialize, Serialize};
use tracing::error;

// GET /user - List users (admin only)
#[utoipa::path(
    get,
    path = "/users",
    tag = "users",
    summary = "List users",
    description = "List all users (admin only)",
    params(
        ("skip" = Option<i64>, Query, description = "Number of users to skip"),
        ("limit" = Option<i64>, Query, description = "Maximum number of users to return"),
        ("include" = Option<String>, Query, description = "Comma-separated list of related entities to include (e.g., 'groups', 'billing')"),
        ("search" = Option<String>, Query, description = "Search query to filter users by display_name, username, or email (case-insensitive substring match)"),
    ),
    responses(
        (status = 200, description = "List of users", body = [UserResponse]),
        (status = 401, description = "Unauthorized"),
        (status = 403, description = "Forbidden - admin access required"),
        (status = 500, description = "Internal server error"),
    ),
    security(
        ("BearerAuth" = []),
        ("CookieAuth" = []),
        ("X-Doubleword-User" = [])
    )
)]
#[tracing::instrument(skip_all)]
pub async fn list_users<P: PoolProvider>(
    State(state): State<AppState<P>>,
    Query(query): Query<ListUsersQuery>,
    current_user: CurrentUser,
    _: RequiresPermission<resource::Users, operation::ReadAll>,
) -> Result<Json<PaginatedResponse<UserResponse>>> {
    // Use read replica for this read-only operation
    let mut conn = state.db.read().acquire().await.map_err(|e| Error::Database(e.into()))?;
    let skip = query.pagination.skip();
    let limit = query.pagination.limit();

    // Build filter with search if provided
    let mut filter = UserFilter::new(skip, limit);
    if let Some(search) = query.search.as_ref()
        && !search.trim().is_empty()
    {
        filter = filter.with_search(search.trim().to_string());
    }

    let users;
    let total_count;
    {
        let mut repo = Users::new(&mut conn);
        users = repo.list(&filter).await?;
        total_count = repo.count(&filter).await?;
    }
    // Parse include parameter
    let includes: Vec<&str> = query
        .include
        .as_deref()
        .unwrap_or("")
        .split(',')
        .map(|s| s.trim())
        .filter(|s| !s.is_empty())
        .collect();

    let mut response_users = Vec::new();

    // Create a list of user IDs for bulk fetching related data
    let user_ids: Vec<_> = users.iter().map(|u| u.id).collect();

    // Check if user has permission to view billing data (Credits ReadAll)
    let can_view_billing = permissions::has_permission(&current_user, Resource::Credits, Operation::ReadAll);

    // If includes billing AND user has permission, create balances_map
    let balances_map = if includes.contains(&"billing") && can_view_billing {
        let mut credits_repo = Credits::new(&mut conn);
        Some(credits_repo.get_users_balances_bulk(&user_ids, None).await?)
    } else {
        None
    };

    // If includes groups, make groups_map and user_groups_map
    let (groups_map, user_groups_map) = if includes.contains(&"groups") {
        let mut groups_repo = Groups::new(&mut conn);
        let user_groups_map = groups_repo.get_users_groups_bulk(&user_ids).await?;
        // Collect all unique group IDs that we need to fetch
        let all_group_ids: Vec<GroupId> = user_groups_map
            .values()
            .flatten()
            .copied()
            .collect::<std::collections::HashSet<_>>()
            .into_iter()
            .collect();

        // Fetch only the specific groups we need in bulk
        let groups_map = groups_repo.get_bulk(all_group_ids).await?;
        (Some(groups_map), Some(user_groups_map))
    } else {
        (None, None)
    };

    // Iterate through and enrich users
    for user in users {
        let mut response_user = UserResponse::from(user);
        // If includes groups
        if let Some(groups_map) = &groups_map
            && let Some(user_groups_map) = &user_groups_map
        {
            let group_ids = user_groups_map.get(&response_user.id).cloned().unwrap_or_default();
            let groups: Vec<GroupResponse> = group_ids
                .iter()
                .filter_map(|group_id| groups_map.get(group_id))
                .cloned()
                .map(|group| group.into())
                .collect();
            response_user = response_user.with_groups(groups);
        }

        // If includes billing
        if let Some(balances_map) = &balances_map {
            let balance = balances_map.get(&response_user.id).and_then(|b| b.to_f64()).unwrap_or(0.0);
            response_user = response_user.with_credit_balance(balance);
        }

        response_users.push(response_user);
    }

    let paginated_response = PaginatedResponse::new(response_users, total_count, skip, limit);
    Ok(Json(paginated_response))
}

// GET /users/{user_id} - Get specific user (admin only) or current user
#[utoipa::path(
    get,
    path = "/users/{user_id}",
    tag = "users",
    summary = "Get user",
    description = "Get a specific user by ID or current user",
    params(
        ("user_id" = String, Path, description = "User ID (UUID) or 'current' for current user"),
        ("includes" = Option<String>, Query, description = "Data to include, currently only 'billing' is supported"),
    ),
    responses(
        (status = 200, description = "User information", body = UserResponse),
        (status = 401, description = "Unauthorized"),
        (status = 403, description = "Forbidden - can only view own user data unless admin"),
        (status = 404, description = "User not found"),
        (status = 500, description = "Internal server error")
    ),
    security(
        ("BearerAuth" = []),
        ("CookieAuth" = []),
        ("X-Doubleword-User" = [])
    )
)]
#[tracing::instrument(skip_all)]
pub async fn get_user<P: PoolProvider>(
    State(state): State<AppState<P>>,
    Path(user_id): Path<UserIdOrCurrent>,
    Query(query): Query<GetUserQuery>,
    // Can't use RequiresPermission here because we need conditional logic for own vs other users
    current_user: CurrentUser,
) -> Result<Json<UserResponse>> {
    let is_current = matches!(user_id, UserIdOrCurrent::Current(_));
    let target_user_id = match user_id {
        UserIdOrCurrent::Current(_) => {
            // Even for /current, verify they have permission to read their own user data
            if !can_read_own_resource(&current_user, Resource::Users, current_user.id) {
                return Err(Error::InsufficientPermissions {
                    required: Permission::Allow(Resource::Users, Operation::ReadOwn),
                    action: Operation::ReadOwn,
                    resource: "current user data".to_string(),
                });
            }
            current_user.id
        }
        UserIdOrCurrent::Id(uuid) => {
            let can_read_all_users = can_read_all_resources(&current_user, Resource::Users);
            let can_read_own_user = can_read_own_resource(&current_user, Resource::Users, uuid);

            // Allow access if user can read all users, read their own user data,
            // or is a member of the org (orgs are virtual users)
            if !can_read_all_users && !can_read_own_user {
                let mut conn = state.db.read().acquire().await.map_err(|e| Error::Database(e.into()))?;
                let is_member = permissions::is_org_member(&current_user, uuid, &mut conn)
                    .await
                    .map_err(Error::Database)?;
                if !is_member {
                    return Err(Error::InsufficientPermissions {
                        required: Permission::Any(vec![
                            Permission::Allow(Resource::Users, Operation::ReadAll),
                            Permission::Allow(Resource::Users, Operation::ReadOwn),
                        ]),
                        action: Operation::ReadAll,
                        resource: format!("user data for user {uuid}"),
                    });
                }
            }
            uuid
        }
    };

    // Use read replica for this read-only operation
    let mut pool_conn = state.db.read().acquire().await.map_err(|e| Error::Database(e.into()))?;
    let mut repo = Users::new(&mut pool_conn);

    let user = repo.get_by_id(target_user_id).await?.ok_or_else(|| Error::NotFound {
        resource: "User".to_string(),
        id: target_user_id.to_string(),
    })?;

    let mut response = UserResponse::from(user);

    // Include billing if requested and permitted
    // Permitted if:
    //     1. You have ReadAll on Credits
    //     2. You are requesting your own data and have ReadOwn on Credits
    //     3. You are a member of the org being queried (org balance is shared)
    let is_org_member = current_user.organizations.iter().any(|o| o.id == target_user_id);
    if query.include.as_deref().is_some_and(|includes| includes.contains("billing"))
        && (permissions::has_permission(&current_user, Resource::Credits, Operation::ReadAll)
            || (target_user_id == current_user.id && permissions::has_permission(&current_user, Resource::Credits, Operation::ReadOwn))
            || is_org_member)
    {
        let mut credits_repo = Credits::new(&mut pool_conn);
        let balance = credits_repo.get_user_balance(target_user_id).await?.to_f64().unwrap_or_else(|| {
            error!("Failed to convert balance to f64 for user_id {}", target_user_id);
            0.0
        });
        response = response.with_credit_balance(balance);
    }

    // Include organizations if requested
    if query.include.as_deref().is_some_and(|includes| includes.contains("organizations")) {
        let mut org_repo = Organizations::new(&mut pool_conn);
        let memberships = org_repo.list_user_organizations(target_user_id).await?;

        let org_ids: Vec<UserId> = memberships.iter().map(|m| m.organization_id).collect();
        if !org_ids.is_empty() {
            let mut users_repo = Users::new(&mut pool_conn);
            let org_map = users_repo.get_bulk(org_ids).await?;

            let summaries: Vec<crate::api::models::organizations::OrganizationSummary> = memberships
                .iter()
                .filter_map(|m| {
                    org_map
                        .get(&m.organization_id)
                        .map(|org| crate::api::models::organizations::OrganizationSummary {
                            id: m.organization_id,
                            name: org.display_name.clone().unwrap_or_else(|| org.username.clone()),
                            role: m.role.clone(),
                        })
                })
                .collect();

            response = response.with_organizations(summaries);
        } else {
            response = response.with_organizations(vec![]);
        }
    }

    // Include active organization for /users/current requests
    if is_current {
        response = response.with_active_organization(current_user.active_organization);

        // Include onboarding redirect URL when the user is treated as "first login".
        // A user is considered first login if last_login is null, or if last_login is
        // within 10 seconds of created_at. The small time window accounts for cases
        // where a background task updates last_login before the first /current call
        // or before this handler reads the user from the database.
        let is_first_login = response.last_login.is_none()
            || response
                .last_login
                .is_some_and(|ll| (ll - response.created_at).num_seconds().abs() < 10);
        let config = state.current_config();
        if is_first_login && let Some(url) = &config.onboarding_url {
            response = response.with_onboarding_redirect_url(url.clone());
        }
    }

    Ok(Json(response))
}

// POST /users - Create user (admin only)
#[utoipa::path(
    post,
    path = "/users",
    tag = "users",
    summary = "Create user",
    description = "Create a new user (admin only)",
    responses(
        (status = 201, description = "User created successfully", body = UserResponse),
        (status = 400, description = "Bad request - invalid user data"),
        (status = 401, description = "Unauthorized"),
        (status = 403, description = "Forbidden - admin access required"),
        (status = 500, description = "Internal server error"),
    ),
    security(
        ("BearerAuth" = []),
        ("CookieAuth" = []),
        ("X-Doubleword-User" = [])
    )
)]
#[tracing::instrument(skip_all)]
pub async fn create_user<P: PoolProvider>(
    State(state): State<AppState<P>>,
    _: RequiresPermission<resource::Users, operation::CreateAll>,
    Json(user_data): Json<UserCreate>,
) -> Result<(StatusCode, Json<UserResponse>)> {
    let mut tx = state.db.write().begin().await.map_err(|e| Error::Database(e.into()))?;

    let mut repo = Users::new(&mut tx);
    let db_request = UserCreateDBRequest::from(user_data);

    let user = repo.create(&db_request).await?;

    // Note: Batch and playground hidden API keys are pre-created by the create() method
    // to avoid race conditions with onwards sync. Realtime keys are created by users
    // explicitly via API and can tolerate activation delay.

    tx.commit().await.map_err(|e| Error::Database(e.into()))?;

    // user.created webhook deliveries are created by the notification poller
    // via PG LISTEN/NOTIFY on the users table.

    Ok((StatusCode::CREATED, Json(UserResponse::from(user))))
}

// PATCH /user/{user_id} - Update user (admin only) or own user (authenticated user)
#[utoipa::path(
    patch,
    path = "/users/{user_id}",
    tag = "users",
    summary = "Update user",
    description = "Update an existing user (admin can update any user, users can update their own profile)",
    params(
        ("user_id" = uuid::Uuid, Path, description = "User ID to update"),
    ),
    responses(
        (status = 200, description = "User updated successfully", body = UserResponse),
        (status = 400, description = "Bad request - invalid user data"),
        (status = 401, description = "Unauthorized"),
        (status = 403, description = "Forbidden - can only update own user data unless admin"),
        (status = 404, description = "User not found"),
        (status = 500, description = "Internal server error"),
    ),
    security(
        ("BearerAuth" = []),
        ("CookieAuth" = []),
        ("X-Doubleword-User" = [])
    )
)]
#[tracing::instrument(skip_all)]
pub async fn update_user<P: PoolProvider>(
    State(state): State<AppState<P>>,
    Path(user_id): Path<UserId>,
    current_user: CurrentUser,
    Json(user_data): Json<UserUpdate>,
) -> Result<Json<UserResponse>> {
    // Check permissions: user can update all users OR update their own user
    let can_update_all_users = permissions::can_update_all_resources(&current_user, Resource::Users);
    let can_update_own_user = permissions::can_update_own_resource(&current_user, Resource::Users, user_id);

    if !can_update_all_users && !can_update_own_user {
        return Err(Error::InsufficientPermissions {
            required: Permission::Any(vec![
                Permission::Allow(Resource::Users, Operation::UpdateAll),
                Permission::Allow(Resource::Users, Operation::UpdateOwn),
            ]),
            action: Operation::UpdateAll,
            resource: format!("user data for user {user_id}"),
        });
    }

    // SECURITY: Prevent role escalation - only users with UpdateAll can modify roles
    if !can_update_all_users && user_data.roles.is_some() {
        return Err(Error::InsufficientPermissions {
            required: Permission::Allow(Resource::Users, Operation::UpdateAll),
            action: Operation::UpdateAll,
            resource: "user roles".to_string(),
        });
    }

    // Validate auto-topup fields if provided
    if let Some(Some(amount)) = &user_data.auto_topup_amount
        && *amount <= 0.0
    {
        return Err(Error::BadRequest {
            message: "Auto top-up amount must be positive".to_string(),
        });
    }
    if let Some(Some(threshold)) = &user_data.auto_topup_threshold
        && *threshold < 0.0
    {
        return Err(Error::BadRequest {
            message: "Auto top-up threshold must be non-negative".to_string(),
        });
    }
    if let Some(Some(limit)) = &user_data.auto_topup_monthly_limit
        && *limit <= 0.0
    {
        return Err(Error::BadRequest {
            message: "Auto top-up monthly limit must be positive".to_string(),
        });
    }

    let mut conn = state.db.write().acquire().await.expect("Failed to acquire database connection");

    let mut repo = Users::new(&mut conn);
    let db_request = UserUpdateDBRequest::new(user_data);

    let user = repo.update(user_id, &db_request).await?;
    Ok(Json(UserResponse::from(user)))
}

// DELETE /user/{user_id} - Delete user (admin only)
#[utoipa::path(
    delete,
    path = "/users/{user_id}",
    tag = "users",
    summary = "Delete user",
    description = "Delete a user (admin only)",
    params(
        ("user_id" = uuid::Uuid, Path, description = "User ID to delete"),
    ),
    responses(
        (status = 204, description = "User deleted successfully"),
        (status = 400, description = "Bad request - cannot delete yourself"),
        (status = 401, description = "Unauthorized"),
        (status = 403, description = "Forbidden - admin access required"),
        (status = 404, description = "User not found"),
        (status = 500, description = "Internal server error"),
    ),
    security(
        ("BearerAuth" = []),
        ("CookieAuth" = []),
        ("X-Doubleword-User" = [])
    )
)]
#[tracing::instrument(skip_all)]
pub async fn delete_user<P: PoolProvider>(
    State(state): State<AppState<P>>,
    Path(user_id): Path<UserId>,
    current_user: RequiresPermission<resource::Users, operation::DeleteAll>,
) -> Result<StatusCode> {
    use fusillade::Storage;

    // Prevent self-deletion
    if user_id == current_user.id {
        return Err(Error::BadRequest {
            message: "You cannot delete your own account".to_string(),
        });
    }

    // Cancel all active batches for this user before deletion
    let user_id_str = user_id.to_string();
    let batches = state
        .request_manager
        .list_batches(fusillade::ListBatchesFilter {
            created_by: Some(user_id_str.clone()),
            limit: Some(i64::MAX),
            ..Default::default()
        })
        .await
        .map_err(|e| {
            // A listing failure is an internal fault (DB unreachable, etc.), not
            // a missing resource — don't mislabel it as 404 "Batch not found".
            tracing::error!(user_id = %user_id, error = %e, "Failed to list batches for user deletion");
            Error::Internal {
                operation: "list user batches for deletion".to_string(),
            }
        })?;

    for batch in batches {
        if batch.completed_at.is_none()
            && let Err(e) = state.request_manager.cancel_batch(batch.id).await
        {
            tracing::warn!(
                batch_id = %batch.id,
                user_id = %user_id,
                error = %e,
                "Failed to cancel batch during user deletion"
            );
        }
    }

    // Soft-delete + scrub the user row and hard-delete their API keys
    // (atomic, in repo.delete). Scoped so the connection borrow is released
    // before we enqueue the background purge below.
    let deleted = {
        let mut conn = state.db.write().acquire().await.expect("Failed to acquire database connection");
        let mut repo = Users::new(&mut conn);
        repo.delete(user_id).await?
    };

    if !deleted {
        return Err(Error::NotFound {
            resource: "User".to_string(),
            id: user_id.to_string(),
        });
    }

    // Erase the user's fusillade data (files, batches, requests) in the
    // background. API keys were already hard-deleted synchronously above so
    // they stop authenticating immediately; fusillade data can be unbounded,
    // so it is offloaded to an at-least-once underway job.
    enqueue_purge_user_data(&state, user_id_str).await;

    Ok(StatusCode::NO_CONTENT)
}

/// Input for the user-data purge background job. Carries the user id as a
/// string because fusillade keys ownership (`created_by` / `uploaded_by`) as
/// text.
#[derive(Debug, Serialize, Deserialize)]
pub struct PurgeUserDataInput {
    pub user_id: String,
}

/// Build the underway job that erases a deleted user's fusillade data
/// (batchless requests, batches, files) via `Storage::bulk_delete_data`,
/// looping in chunks until nothing is left. Retryable on error so a crashed
/// or partial purge is resumed.
pub async fn build_purge_user_data_job<P: sqlx_pool_router::PoolProvider + Clone + Send + Sync + 'static>(
    pool: sqlx::PgPool,
    state: crate::tasks::TaskState<P>,
) -> anyhow::Result<underway::Job<PurgeUserDataInput, crate::tasks::TaskState<P>>> {
    use fusillade::Storage;
    use underway::Job;
    use underway::job::To;
    use underway::task::Error as TaskError;

    // Chunk size per bulk_delete_data call. bulk_delete_data only touches the
    // user's batch/file rows and batchless requests (child rows are reaped by
    // the orphan-purge daemon), so even large accounts drain in a few passes.
    const BATCH_SIZE: i64 = 1000;

    Job::<PurgeUserDataInput, _>::builder()
        .state(state)
        .step(|cx, input: PurgeUserDataInput| async move {
            let mut total: u64 = 0;
            loop {
                match cx.state.request_manager.bulk_delete_data(&input.user_id, BATCH_SIZE).await {
                    Ok(0) => {
                        if total > 0 {
                            tracing::info!(user_id = %input.user_id, rows = total, "Purged user fusillade data");
                        }
                        return To::done();
                    }
                    Ok(n) => total += n,
                    Err(e) => {
                        tracing::error!(user_id = %input.user_id, error = %e, "Failed to purge user fusillade data");
                        return Err(TaskError::Retryable(e.to_string()));
                    }
                }
            }
        })
        .name("purge-user-data")
        .pool(pool)
        .build()
        .await
        .map_err(Into::into)
}

/// Enqueue the purge-user-data job. Best-effort: the delete handler still
/// returns success on failure (the row + keys are already gone). But a failed
/// enqueue means the user's fusillade data is *not* scheduled for erasure and
/// nothing retries it automatically — a right-to-erasure gap that must be
/// visible, so it emits the background-error metric (severity `error`:
/// triageable, ~1-month legal window, not a page) rather than a silent warn.
async fn enqueue_purge_user_data<P: PoolProvider>(state: &AppState<P>, user_id: String) {
    if let Err(e) = state
        .task_runner
        .purge_user_data_job
        .enqueue(&PurgeUserDataInput { user_id: user_id.clone() })
        .await
    {
        crate::background_error!(
            crate::metrics::errors::component::TASK_WORKER,
            "purge_user_data_enqueue",
            Error,
            user_id = %user_id,
            error = %e,
            "Failed to enqueue purge-user-data job; fusillade data will NOT be erased until retried (right-to-erasure gap)"
        );
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    use crate::api::models::pagination::MAX_LIMIT;
    use crate::api::models::users::Role;
    use crate::db::handlers::{Credits, Groups, Repository};
    use crate::db::models::{credits::CreditTransactionCreateDBRequest, groups::GroupCreateDBRequest};
    use crate::test::utils::*;
    use rust_decimal::Decimal;
    use serde_json::json;
    use sqlx::PgPool;
    use std::collections::HashSet;
    use std::str::FromStr;
    use uuid::Uuid;

    #[sqlx::test]
    #[test_log::test]
    async fn test_get_current_user_info(pool: PgPool) {
        let (app, _bg_services) = create_test_app(pool.clone(), false).await;
        let user = create_test_user(&pool, Role::StandardUser).await;

        let response = app
            .get("/admin/api/v1/users/current")
            .add_header(&add_auth_headers(&user)[0].0, &add_auth_headers(&user)[0].1)
            .add_header(&add_auth_headers(&user)[1].0, &add_auth_headers(&user)[1].1)
            .await;

        response.assert_status_ok();
        let current_user: UserResponse = response.json();
        assert_eq!(current_user.id, user.id);
        assert_eq!(current_user.email, user.email);
        assert_eq!(current_user.roles, user.roles);
    }

    #[sqlx::test]
    #[test_log::test]
    async fn test_list_users_as_admin(pool: PgPool) {
        let (app, _bg_services) = create_test_app(pool.clone(), false).await;
        let admin_user = create_test_admin_user(&pool, Role::PlatformManager).await;

        let response = app
            .get("/admin/api/v1/users")
            .add_header(&add_auth_headers(&admin_user)[0].0, &add_auth_headers(&admin_user)[0].1)
            .add_header(&add_auth_headers(&admin_user)[1].0, &add_auth_headers(&admin_user)[1].1)
            .await;

        response.assert_status_ok();
        let paginated: PaginatedResponse<UserResponse> = response.json();
        assert!(!paginated.data.is_empty());
        assert!(paginated.total_count > 0);
    }

    #[sqlx::test]
    #[test_log::test]
    async fn test_list_users_as_non_admin_forbidden(pool: PgPool) {
        let (app, _bg_services) = create_test_app(pool.clone(), false).await;
        let user = create_test_user(&pool, Role::StandardUser).await;

        let response = app
            .get("/admin/api/v1/users")
            .add_header(&add_auth_headers(&user)[0].0, &add_auth_headers(&user)[0].1)
            .add_header(&add_auth_headers(&user)[1].0, &add_auth_headers(&user)[1].1)
            .await;

        response.assert_status_forbidden();
    }

    #[sqlx::test]
    #[test_log::test]
    async fn test_create_user_as_admin(pool: PgPool) {
        let (app, _bg_services) = create_test_app(pool.clone(), false).await;
        let admin_user = create_test_admin_user(&pool, Role::PlatformManager).await;

        let new_user = json!({
            "username": "newuser",
            "email": "newuser@example.com",
            "display_name": "New User",
            "avatar_url": null,
            "roles": ["StandardUser"]
        });

        let response = app
            .post("/admin/api/v1/users")
            .add_header(&add_auth_headers(&admin_user)[0].0, &add_auth_headers(&admin_user)[0].1)
            .add_header(&add_auth_headers(&admin_user)[1].0, &add_auth_headers(&admin_user)[1].1)
            .json(&new_user)
            .await;

        response.assert_status(axum::http::StatusCode::CREATED);
        let created_user: UserResponse = response.json();
        assert_eq!(created_user.username, "newuser");
        assert_eq!(created_user.email, "newuser@example.com");
    }

    #[sqlx::test]
    #[test_log::test]
    async fn test_unauthenticated_request(pool: PgPool) {
        let (app, _bg_services) = create_test_app(pool, false).await;

        let response = app.get("/admin/api/v1/users/current").await;
        response.assert_status_unauthorized();
    }

    #[sqlx::test]
    #[test_log::test]
    async fn test_list_users_with_pagination(pool: PgPool) {
        let (app, _bg_services) = create_test_app(pool.clone(), false).await;
        let admin_user = create_test_admin_user(&pool, Role::PlatformManager).await;

        // Create additional test users
        for _ in 0..5 {
            create_test_user(&pool, Role::StandardUser).await;
        }

        // Test with limit
        let response = app
            .get("/admin/api/v1/users?limit=3")
            .add_header(&add_auth_headers(&admin_user)[0].0, &add_auth_headers(&admin_user)[0].1)
            .add_header(&add_auth_headers(&admin_user)[1].0, &add_auth_headers(&admin_user)[1].1)
            .await;

        response.assert_status_ok();
        let paginated: PaginatedResponse<UserResponse> = response.json();
        assert_eq!(paginated.data.len(), 3);
        assert_eq!(paginated.limit, 3);
        assert_eq!(paginated.skip, 0);

        // Test with skip and limit
        let response = app
            .get("/admin/api/v1/users?skip=2&limit=2")
            .add_header(&add_auth_headers(&admin_user)[0].0, &add_auth_headers(&admin_user)[0].1)
            .add_header(&add_auth_headers(&admin_user)[1].0, &add_auth_headers(&admin_user)[1].1)
            .await;

        response.assert_status_ok();
        let paginated: PaginatedResponse<UserResponse> = response.json();
        assert!(paginated.data.len() <= 2);
        assert_eq!(paginated.skip, 2);
        assert_eq!(paginated.limit, 2);

        // Test skip beyond available users
        let response = app
            .get("/admin/api/v1/users?skip=1000&limit=10")
            .add_header(&add_auth_headers(&admin_user)[0].0, &add_auth_headers(&admin_user)[0].1)
            .add_header(&add_auth_headers(&admin_user)[1].0, &add_auth_headers(&admin_user)[1].1)
            .await;

        response.assert_status_ok();
        let paginated: PaginatedResponse<UserResponse> = response.json();
        assert!(paginated.data.is_empty());
        assert_eq!(paginated.skip, 1000);

        // Test maximum limit enforcement
        let response = app
            .get("/admin/api/v1/users?limit=2000")
            .add_header(&add_auth_headers(&admin_user)[0].0, &add_auth_headers(&admin_user)[0].1)
            .add_header(&add_auth_headers(&admin_user)[1].0, &add_auth_headers(&admin_user)[1].1)
            .await;

        response.assert_status_ok();
        let paginated: PaginatedResponse<UserResponse> = response.json();
        assert!(paginated.data.len() <= MAX_LIMIT as usize); // Should be capped at MAX_LIMIT
        assert_eq!(paginated.limit, MAX_LIMIT); // Limit should be clamped
    }

    #[sqlx::test]
    #[test_log::test]
    async fn test_get_other_user_as_admin(pool: PgPool) {
        let (app, _bg_services) = create_test_app(pool.clone(), false).await;
        let admin_user = create_test_admin_user(&pool, Role::PlatformManager).await;
        let regular_user = create_test_user(&pool, Role::StandardUser).await;

        let response = app
            .get(&format!("/admin/api/v1/users/{}", regular_user.id))
            .add_header(&add_auth_headers(&admin_user)[0].0, &add_auth_headers(&admin_user)[0].1)
            .add_header(&add_auth_headers(&admin_user)[1].0, &add_auth_headers(&admin_user)[1].1)
            .await;

        response.assert_status_ok();
        let user_response: UserResponse = response.json();
        assert_eq!(user_response.id, regular_user.id);
        assert_eq!(user_response.email, regular_user.email);
    }

    #[sqlx::test]
    #[test_log::test]
    async fn test_get_other_user_as_non_admin_forbidden(pool: PgPool) {
        let (app, _bg_services) = create_test_app(pool.clone(), false).await;
        let user1 = create_test_user(&pool, Role::StandardUser).await;
        let user2 = create_test_user(&pool, Role::StandardUser).await;

        let response = app
            .get(&format!("/admin/api/v1/users/{}", user2.id))
            .add_header(&add_auth_headers(&user1)[0].0, &add_auth_headers(&user1)[0].1)
            .add_header(&add_auth_headers(&user1)[1].0, &add_auth_headers(&user1)[1].1)
            .await;

        response.assert_status_forbidden();
    }

    #[sqlx::test]
    #[test_log::test]
    async fn test_get_user_not_found(pool: PgPool) {
        let (app, _bg_services) = create_test_app(pool.clone(), false).await;
        let admin_user = create_test_admin_user(&pool, Role::PlatformManager).await;
        let nonexistent_id = uuid::Uuid::new_v4();

        let response = app
            .get(&format!("/admin/api/v1/users/{nonexistent_id}"))
            .add_header(&add_auth_headers(&admin_user)[0].0, &add_auth_headers(&admin_user)[0].1)
            .add_header(&add_auth_headers(&admin_user)[1].0, &add_auth_headers(&admin_user)[1].1)
            .await;

        response.assert_status_not_found();
    }

    #[sqlx::test]
    #[test_log::test]
    async fn test_list_users_with_groups_include(pool: PgPool) {
        let (app, _bg_services) = create_test_app(pool.clone(), false).await;
        let admin_user = create_test_admin_user(&pool, Role::PlatformManager).await;
        let regular_user = create_test_user(&pool, Role::StandardUser).await;

        // Create a group and add the regular user to it
        let mut conn = pool.acquire().await.expect("Failed to acquire database connection");
        let mut group_repo = Groups::new(&mut conn);
        let group_create = GroupCreateDBRequest {
            name: "Test Group".to_string(),
            description: Some("Test group for user include".to_string()),
            created_by: admin_user.id,
        };
        let group = group_repo.create(&group_create).await.expect("Failed to create test group");
        group_repo
            .add_user_to_group(regular_user.id, group.id)
            .await
            .expect("Failed to add user to group");

        // Test without include parameter - should not include groups
        let response = app
            .get("/admin/api/v1/users")
            .add_header(&add_auth_headers(&admin_user)[0].0, &add_auth_headers(&admin_user)[0].1)
            .add_header(&add_auth_headers(&admin_user)[1].0, &add_auth_headers(&admin_user)[1].1)
            .await;

        response.assert_status_ok();
        let paginated: PaginatedResponse<UserResponse> = response.json();
        let found_user = paginated.data.iter().find(|u| u.id == regular_user.id).expect("User not found");
        assert!(found_user.groups.is_none());

        // Test with include=groups - should include groups
        let response = app
            .get("/admin/api/v1/users?include=groups")
            .add_header(&add_auth_headers(&admin_user)[0].0, &add_auth_headers(&admin_user)[0].1)
            .add_header(&add_auth_headers(&admin_user)[1].0, &add_auth_headers(&admin_user)[1].1)
            .await;

        response.assert_status_ok();
        let paginated: PaginatedResponse<UserResponse> = response.json();
        let found_user = paginated.data.iter().find(|u| u.id == regular_user.id).expect("User not found");
        assert!(found_user.groups.is_some());
        let groups = found_user.groups.as_ref().unwrap().iter().map(|x| x.id).collect::<HashSet<_>>();
        assert!(groups.contains(&group.id));

        // Test with include=groups and pagination
        let response = app
            .get("/admin/api/v1/users?include=groups&limit=10")
            .add_header(&add_auth_headers(&admin_user)[0].0, &add_auth_headers(&admin_user)[0].1)
            .add_header(&add_auth_headers(&admin_user)[1].0, &add_auth_headers(&admin_user)[1].1)
            .await;

        response.assert_status_ok();
        let paginated: PaginatedResponse<UserResponse> = response.json();
        let found_user = paginated.data.iter().find(|u| u.id == regular_user.id).expect("User not found");
        assert!(found_user.groups.is_some());
        let groups = found_user.groups.as_ref().unwrap().iter().map(|x| x.id).collect::<HashSet<_>>();
        assert!(groups.contains(&group.id));

        // Test with include=invalid - should ignore invalid includes
        let response = app
            .get("/admin/api/v1/users?include=invalid,groups")
            .add_header(&add_auth_headers(&admin_user)[0].0, &add_auth_headers(&admin_user)[0].1)
            .add_header(&add_auth_headers(&admin_user)[1].0, &add_auth_headers(&admin_user)[1].1)
            .await;

        response.assert_status_ok();
        let paginated: PaginatedResponse<UserResponse> = response.json();
        let found_user = paginated.data.iter().find(|u| u.id == regular_user.id).expect("User not found");
        assert!(found_user.groups.is_some());
        let groups = found_user.groups.as_ref().unwrap().iter().map(|x| x.id).collect::<HashSet<_>>();
        assert!(groups.contains(&group.id));
    }

    #[sqlx::test]
    #[test_log::test]
    async fn test_list_users_with_billing_include(pool: PgPool) {
        let (app, _bg_services) = create_test_app(pool.clone(), false).await;
        let admin_user = create_test_admin_user(&pool, Role::PlatformManager).await;
        let regular_user = create_test_user(&pool, Role::StandardUser).await;

        // Add credits to the regular user
        create_initial_credit_transaction(&pool, regular_user.id, "250.0").await;

        // Test without include parameter - should not include billing
        let response = app
            .get("/admin/api/v1/users")
            .add_header(&add_auth_headers(&admin_user)[0].0, &add_auth_headers(&admin_user)[0].1)
            .add_header(&add_auth_headers(&admin_user)[1].0, &add_auth_headers(&admin_user)[1].1)
            .await;

        response.assert_status_ok();
        let paginated: PaginatedResponse<UserResponse> = response.json();
        let found_user = paginated.data.iter().find(|u| u.id == regular_user.id).expect("User not found");
        assert!(found_user.credit_balance.is_none());

        // Test with include=billing - should include credit balance
        let response = app
            .get("/admin/api/v1/users?include=billing")
            .add_header(&add_auth_headers(&admin_user)[0].0, &add_auth_headers(&admin_user)[0].1)
            .add_header(&add_auth_headers(&admin_user)[1].0, &add_auth_headers(&admin_user)[1].1)
            .await;

        response.assert_status_ok();
        let paginated: PaginatedResponse<UserResponse> = response.json();
        let found_user = paginated.data.iter().find(|u| u.id == regular_user.id).expect("User not found");
        assert!(found_user.credit_balance.is_some());
        assert_eq!(found_user.credit_balance.unwrap(), 250.0);

        // Test with include=billing and pagination
        let response = app
            .get("/admin/api/v1/users?include=billing&limit=10")
            .add_header(&add_auth_headers(&admin_user)[0].0, &add_auth_headers(&admin_user)[0].1)
            .add_header(&add_auth_headers(&admin_user)[1].0, &add_auth_headers(&admin_user)[1].1)
            .await;

        response.assert_status_ok();
        let paginated: PaginatedResponse<UserResponse> = response.json();
        let found_user = paginated.data.iter().find(|u| u.id == regular_user.id).expect("User not found");
        assert!(found_user.credit_balance.is_some());
        assert_eq!(found_user.credit_balance.unwrap(), 250.0);

        // Test with include=invalid,billing - should ignore invalid and include billing
        let response = app
            .get("/admin/api/v1/users?include=invalid,billing")
            .add_header(&add_auth_headers(&admin_user)[0].0, &add_auth_headers(&admin_user)[0].1)
            .add_header(&add_auth_headers(&admin_user)[1].0, &add_auth_headers(&admin_user)[1].1)
            .await;

        response.assert_status_ok();
        let paginated: PaginatedResponse<UserResponse> = response.json();
        let found_user = paginated.data.iter().find(|u| u.id == regular_user.id).expect("User not found");
        assert!(found_user.credit_balance.is_some());
        assert_eq!(found_user.credit_balance.unwrap(), 250.0);
    }

    #[sqlx::test]
    #[test_log::test]
    async fn test_list_users_with_groups_and_billing_include(pool: PgPool) {
        let (app, _bg_services) = create_test_app(pool.clone(), false).await;
        let admin_user = create_test_admin_user(&pool, Role::PlatformManager).await;
        let regular_user = create_test_user(&pool, Role::StandardUser).await;

        // Create a group and add the regular user to it
        let mut conn = pool.acquire().await.expect("Failed to acquire database connection");
        let mut group_repo = Groups::new(&mut conn);
        let group_create = GroupCreateDBRequest {
            name: "Test Group".to_string(),
            description: Some("Test group for combined include".to_string()),
            created_by: admin_user.id,
        };
        let group = group_repo.create(&group_create).await.expect("Failed to create test group");
        group_repo
            .add_user_to_group(regular_user.id, group.id)
            .await
            .expect("Failed to add user to group");

        // Add credits to the regular user
        create_initial_credit_transaction(&pool, regular_user.id, "500.0").await;

        // Test with include=groups,billing - should include both
        let response = app
            .get("/admin/api/v1/users?include=groups,billing")
            .add_header(&add_auth_headers(&admin_user)[0].0, &add_auth_headers(&admin_user)[0].1)
            .add_header(&add_auth_headers(&admin_user)[1].0, &add_auth_headers(&admin_user)[1].1)
            .await;

        response.assert_status_ok();
        let paginated: PaginatedResponse<UserResponse> = response.json();
        let found_user = paginated.data.iter().find(|u| u.id == regular_user.id).expect("User not found");

        // Verify groups are included
        assert!(found_user.groups.is_some());
        let groups = found_user.groups.as_ref().unwrap().iter().map(|x| x.id).collect::<HashSet<_>>();
        assert!(groups.contains(&group.id));

        // Verify billing is included
        assert!(found_user.credit_balance.is_some());
        assert_eq!(found_user.credit_balance.unwrap(), 500.0);
    }

    #[sqlx::test]
    #[test_log::test]
    async fn test_list_users_billing_with_zero_balance(pool: PgPool) {
        let (app, _bg_services) = create_test_app(pool.clone(), false).await;
        let admin_user = create_test_admin_user(&pool, Role::PlatformManager).await;
        let regular_user = create_test_user(&pool, Role::StandardUser).await;

        // Don't add any credits - user should have zero balance

        // Test with include=billing - should show 0.0 for users with no transactions
        let response = app
            .get("/admin/api/v1/users?include=billing")
            .add_header(&add_auth_headers(&admin_user)[0].0, &add_auth_headers(&admin_user)[0].1)
            .add_header(&add_auth_headers(&admin_user)[1].0, &add_auth_headers(&admin_user)[1].1)
            .await;

        response.assert_status_ok();
        let paginated: PaginatedResponse<UserResponse> = response.json();
        let found_user = paginated.data.iter().find(|u| u.id == regular_user.id).expect("User not found");
        assert!(found_user.credit_balance.is_some());
        assert_eq!(found_user.credit_balance.unwrap(), 0.0);
    }

    #[sqlx::test]
    #[test_log::test]
    async fn test_list_users_billing_with_multiple_transactions(pool: PgPool) {
        let (app, _bg_services) = create_test_app(pool.clone(), false).await;
        let admin_user = create_test_admin_user(&pool, Role::PlatformManager).await;
        let user1 = create_test_user(&pool, Role::StandardUser).await;
        let user2 = create_test_user(&pool, Role::StandardUser).await;
        let user3 = create_test_user(&pool, Role::StandardUser).await;

        // Add different credit amounts to different users
        create_initial_credit_transaction(&pool, user1.id, "100.0").await;
        create_initial_credit_transaction(&pool, user2.id, "200.0").await;
        create_initial_credit_transaction(&pool, user3.id, "300.0").await;

        // Add a second transaction to user1
        let mut conn = pool.acquire().await.expect("Failed to acquire connection");
        let mut credits_repo = Credits::new(&mut conn);
        let request = CreditTransactionCreateDBRequest::admin_grant(
            user1.id,
            admin_user.id,
            Decimal::from_str("50.0").unwrap(),
            Some("Additional grant".to_string()),
        );
        credits_repo
            .create_transaction(&request)
            .await
            .expect("Failed to create transaction");

        // Test with include=billing - should show latest balance for all users
        let response = app
            .get("/admin/api/v1/users?include=billing")
            .add_header(&add_auth_headers(&admin_user)[0].0, &add_auth_headers(&admin_user)[0].1)
            .add_header(&add_auth_headers(&admin_user)[1].0, &add_auth_headers(&admin_user)[1].1)
            .await;

        response.assert_status_ok();
        let paginated: PaginatedResponse<UserResponse> = response.json();

        let found_user1 = paginated.data.iter().find(|u| u.id == user1.id).expect("User1 not found");
        assert_eq!(found_user1.credit_balance.unwrap(), 150.0); // 100 + 50

        let found_user2 = paginated.data.iter().find(|u| u.id == user2.id).expect("User2 not found");
        assert_eq!(found_user2.credit_balance.unwrap(), 200.0);

        let found_user3 = paginated.data.iter().find(|u| u.id == user3.id).expect("User3 not found");
        assert_eq!(found_user3.credit_balance.unwrap(), 300.0);
    }

    #[sqlx::test]
    #[test_log::test]
    async fn test_list_users_billing_manager_can_view_billing(pool: PgPool) {
        let (app, _bg_services) = create_test_app(pool.clone(), false).await;
        let billing_manager = create_test_admin_user(&pool, Role::BillingManager).await;
        let regular_user = create_test_user(&pool, Role::StandardUser).await;

        // Add credits to the regular user
        create_initial_credit_transaction(&pool, regular_user.id, "350.0").await;

        // Test with include=billing - BillingManager should see balances
        let response = app
            .get("/admin/api/v1/users?include=billing")
            .add_header(&add_auth_headers(&billing_manager)[0].0, &add_auth_headers(&billing_manager)[0].1)
            .add_header(&add_auth_headers(&billing_manager)[1].0, &add_auth_headers(&billing_manager)[1].1)
            .await;

        response.assert_status_ok();
        let paginated: PaginatedResponse<UserResponse> = response.json();
        let found_user = paginated.data.iter().find(|u| u.id == regular_user.id).expect("User not found");
        assert!(found_user.credit_balance.is_some());
        assert_eq!(found_user.credit_balance.unwrap(), 350.0);
    }

    #[sqlx::test]
    #[test_log::test]
    async fn test_update_user_as_admin(pool: PgPool) {
        let (app, _bg_services) = create_test_app(pool.clone(), false).await;
        let admin_user = create_test_admin_user(&pool, Role::PlatformManager).await;
        let regular_user = create_test_user(&pool, Role::StandardUser).await;

        let update_data = json!({
            "display_name": "Updated Display Name",
            "avatar_url": "https://example.com/new-avatar.jpg"
        });

        let response = app
            .patch(&format!("/admin/api/v1/users/{}", regular_user.id))
            .add_header(&add_auth_headers(&admin_user)[0].0, &add_auth_headers(&admin_user)[0].1)
            .add_header(&add_auth_headers(&admin_user)[1].0, &add_auth_headers(&admin_user)[1].1)
            .json(&update_data)
            .await;

        response.assert_status_ok();
        let updated_user: UserResponse = response.json();
        assert_eq!(updated_user.id, regular_user.id);
        assert_eq!(updated_user.display_name.as_deref(), Some("Updated Display Name"));
        assert_eq!(updated_user.avatar_url.as_deref(), Some("https://example.com/new-avatar.jpg"));
    }

    #[sqlx::test]
    #[test_log::test]
    async fn test_update_own_user_as_standard_user(pool: PgPool) {
        let (app, _bg_services) = create_test_app(pool.clone(), false).await;
        let user = create_test_user(&pool, Role::StandardUser).await;

        let update_data = json!({
            "display_name": "My New Display Name",
            "avatar_url": "https://example.com/my-avatar.jpg"
        });

        let response = app
            .patch(&format!("/admin/api/v1/users/{}", user.id))
            .add_header(&add_auth_headers(&user)[0].0, &add_auth_headers(&user)[0].1)
            .add_header(&add_auth_headers(&user)[1].0, &add_auth_headers(&user)[1].1)
            .json(&update_data)
            .await;

        response.assert_status_ok();
        let updated_user: UserResponse = response.json();
        assert_eq!(updated_user.id, user.id);
        assert_eq!(updated_user.display_name.as_deref(), Some("My New Display Name"));
        assert_eq!(updated_user.avatar_url.as_deref(), Some("https://example.com/my-avatar.jpg"));
    }

    #[sqlx::test]
    #[test_log::test]
    async fn test_update_user_as_non_admin_forbidden(pool: PgPool) {
        let (app, _bg_services) = create_test_app(pool.clone(), false).await;
        let user1 = create_test_user(&pool, Role::StandardUser).await;
        let user2 = create_test_user(&pool, Role::StandardUser).await;

        let update_data = json!({
            "display_name": "Should Not Work"
        });

        let response = app
            .patch(&format!("/admin/api/v1/users/{}", user2.id))
            .add_header(&add_auth_headers(&user1)[0].0, &add_auth_headers(&user1)[0].1)
            .add_header(&add_auth_headers(&user1)[1].0, &add_auth_headers(&user1)[1].1)
            .json(&update_data)
            .await;

        response.assert_status_forbidden();
    }

    #[sqlx::test]
    #[test_log::test]
    async fn test_update_nonexistent_user(pool: PgPool) {
        let (app, _bg_services) = create_test_app(pool.clone(), false).await;
        let admin_user = create_test_admin_user(&pool, Role::PlatformManager).await;
        let nonexistent_id = uuid::Uuid::new_v4();

        let update_data = json!({
            "display_name": "Should Not Work"
        });

        let response = app
            .patch(&format!("/admin/api/v1/users/{nonexistent_id}"))
            .add_header(&add_auth_headers(&admin_user)[0].0, &add_auth_headers(&admin_user)[0].1)
            .add_header(&add_auth_headers(&admin_user)[1].0, &add_auth_headers(&admin_user)[1].1)
            .json(&update_data)
            .await;

        response.assert_status_not_found();
    }

    #[sqlx::test]
    #[test_log::test]
    async fn test_delete_user_as_admin(pool: PgPool) {
        let (app, _bg_services) = create_test_app(pool.clone(), false).await;
        let admin_user = create_test_admin_user(&pool, Role::PlatformManager).await;
        let regular_user = create_test_user(&pool, Role::StandardUser).await;

        let response = app
            .delete(&format!("/admin/api/v1/users/{}", regular_user.id))
            .add_header(&add_auth_headers(&admin_user)[0].0, &add_auth_headers(&admin_user)[0].1)
            .add_header(&add_auth_headers(&admin_user)[1].0, &add_auth_headers(&admin_user)[1].1)
            .await;

        response.assert_status(axum::http::StatusCode::NO_CONTENT);

        // Verify user is deleted by trying to get it
        let get_response = app
            .get(&format!("/admin/api/v1/users/{}", regular_user.id))
            .add_header(&add_auth_headers(&admin_user)[0].0, &add_auth_headers(&admin_user)[0].1)
            .add_header(&add_auth_headers(&admin_user)[1].0, &add_auth_headers(&admin_user)[1].1)
            .await;

        get_response.assert_status_not_found();
    }

    #[sqlx::test]
    #[test_log::test]
    async fn test_delete_user_as_non_admin_forbidden(pool: PgPool) {
        let (app, _bg_services) = create_test_app(pool.clone(), false).await;
        let user1 = create_test_user(&pool, Role::StandardUser).await;
        let user2 = create_test_user(&pool, Role::StandardUser).await;

        let response = app
            .delete(&format!("/admin/api/v1/users/{}", user2.id))
            .add_header(&add_auth_headers(&user1)[0].0, &add_auth_headers(&user1)[0].1)
            .add_header(&add_auth_headers(&user1)[1].0, &add_auth_headers(&user1)[1].1)
            .await;

        response.assert_status_forbidden();
    }

    #[sqlx::test]
    #[test_log::test]
    async fn test_delete_nonexistent_user(pool: PgPool) {
        let (app, _bg_services) = create_test_app(pool.clone(), false).await;
        let admin_user = create_test_admin_user(&pool, Role::PlatformManager).await;
        let nonexistent_id = uuid::Uuid::new_v4();

        let response = app
            .delete(&format!("/admin/api/v1/users/{nonexistent_id}"))
            .add_header(&add_auth_headers(&admin_user)[0].0, &add_auth_headers(&admin_user)[0].1)
            .add_header(&add_auth_headers(&admin_user)[1].0, &add_auth_headers(&admin_user)[1].1)
            .await;

        response.assert_status_not_found();
    }

    #[sqlx::test]
    #[test_log::test]
    async fn test_delete_self_forbidden(pool: PgPool) {
        let (app, _bg_services) = create_test_app(pool.clone(), false).await;
        let admin_user = create_test_admin_user(&pool, Role::PlatformManager).await;

        let response = app
            .delete(&format!("/admin/api/v1/users/{}", admin_user.id))
            .add_header(&add_auth_headers(&admin_user)[0].0, &add_auth_headers(&admin_user)[0].1)
            .add_header(&add_auth_headers(&admin_user)[1].0, &add_auth_headers(&admin_user)[1].1)
            .await;

        response.assert_status_bad_request();
    }

    #[sqlx::test]
    #[test_log::test]
    async fn test_standard_user_permissions(pool: PgPool) {
        let (app, _bg_services) = create_test_app(pool.clone(), false).await;
        let standard_user = create_test_user(&pool, Role::StandardUser).await;
        let other_user = create_test_user(&pool, Role::StandardUser).await;

        // StandardUser should be able to get their own info
        let response = app
            .get("/admin/api/v1/users/current")
            .add_header(&add_auth_headers(&standard_user)[0].0, &add_auth_headers(&standard_user)[0].1)
            .add_header(&add_auth_headers(&standard_user)[1].0, &add_auth_headers(&standard_user)[1].1)
            .await;
        response.assert_status_ok();

        let response = app
            .get(&format!("/admin/api/v1/users/{}", standard_user.id))
            .add_header(&add_auth_headers(&standard_user)[0].0, &add_auth_headers(&standard_user)[0].1)
            .add_header(&add_auth_headers(&standard_user)[1].0, &add_auth_headers(&standard_user)[1].1)
            .await;
        response.assert_status_ok();

        // StandardUser should NOT be able to list all users (no ReadAll permission)
        let response = app
            .get("/admin/api/v1/users")
            .add_header(&add_auth_headers(&standard_user)[0].0, &add_auth_headers(&standard_user)[0].1)
            .add_header(&add_auth_headers(&standard_user)[1].0, &add_auth_headers(&standard_user)[1].1)
            .await;
        response.assert_status_forbidden();

        // StandardUser should NOT be able to get other users (no ReadAll permission)
        let response = app
            .get(&format!("/admin/api/v1/users/{}", other_user.id))
            .add_header(&add_auth_headers(&standard_user)[0].0, &add_auth_headers(&standard_user)[0].1)
            .add_header(&add_auth_headers(&standard_user)[1].0, &add_auth_headers(&standard_user)[1].1)
            .await;
        response.assert_status_forbidden();

        // StandardUser should NOT be able to create users
        let new_user = json!({
            "username": "should_not_work",
            "email": "shouldnotwork@example.com",
            "roles": ["StandardUser"]
        });

        let response = app
            .post("/admin/api/v1/users")
            .add_header(&add_auth_headers(&standard_user)[0].0, &add_auth_headers(&standard_user)[0].1)
            .add_header(&add_auth_headers(&standard_user)[1].0, &add_auth_headers(&standard_user)[1].1)
            .json(&new_user)
            .await;
        response.assert_status_forbidden();

        // StandardUser should NOT be able to update other users
        let update_data = json!({"display_name": "Should Not Work"});
        let response = app
            .patch(&format!("/admin/api/v1/users/{}", other_user.id))
            .add_header(&add_auth_headers(&standard_user)[0].0, &add_auth_headers(&standard_user)[0].1)
            .add_header(&add_auth_headers(&standard_user)[1].0, &add_auth_headers(&standard_user)[1].1)
            .json(&update_data)
            .await;
        response.assert_status_forbidden();

        // StandardUser should NOT be able to delete users
        let response = app
            .delete(&format!("/admin/api/v1/users/{}", other_user.id))
            .add_header(&add_auth_headers(&standard_user)[0].0, &add_auth_headers(&standard_user)[0].1)
            .add_header(&add_auth_headers(&standard_user)[1].0, &add_auth_headers(&standard_user)[1].1)
            .await;
        response.assert_status_forbidden();
    }

    #[sqlx::test]
    #[test_log::test]
    async fn test_request_viewer_permissions(pool: PgPool) {
        let (app, _bg_services) = create_test_app(pool.clone(), false).await;
        let request_viewer = create_test_user(&pool, Role::RequestViewer).await;
        let other_user = create_test_user(&pool, Role::StandardUser).await;

        // RequestViewer should be able to get their own info (has ReadOwn for Users)
        let response = app
            .get("/admin/api/v1/users/current")
            .add_header(&add_auth_headers(&request_viewer)[0].0, &add_auth_headers(&request_viewer)[0].1)
            .add_header(&add_auth_headers(&request_viewer)[1].0, &add_auth_headers(&request_viewer)[1].1)
            .await;
        response.assert_status_ok();

        // RequestViewer should NOT be able to list all users (no ReadAll for Users)
        let response = app
            .get("/admin/api/v1/users")
            .add_header(&add_auth_headers(&request_viewer)[0].0, &add_auth_headers(&request_viewer)[0].1)
            .add_header(&add_auth_headers(&request_viewer)[1].0, &add_auth_headers(&request_viewer)[1].1)
            .await;
        response.assert_status_forbidden();

        // RequestViewer should NOT be able to get other users (no ReadAll for Users)
        let response = app
            .get(&format!("/admin/api/v1/users/{}", other_user.id))
            .add_header(&add_auth_headers(&request_viewer)[0].0, &add_auth_headers(&request_viewer)[0].1)
            .add_header(&add_auth_headers(&request_viewer)[1].0, &add_auth_headers(&request_viewer)[1].1)
            .await;
        response.assert_status_forbidden();

        // RequestViewer should NOT be able to create, update, or delete users
        let new_user = json!({
            "username": "should_not_work",
            "email": "shouldnotwork@example.com",
            "roles": ["StandardUser"]
        });

        let response = app
            .post("/admin/api/v1/users")
            .add_header(&add_auth_headers(&request_viewer)[0].0, &add_auth_headers(&request_viewer)[0].1)
            .add_header(&add_auth_headers(&request_viewer)[1].0, &add_auth_headers(&request_viewer)[1].1)
            .json(&new_user)
            .await;
        response.assert_status_forbidden();
    }

    #[sqlx::test]
    #[test_log::test]
    async fn test_platform_manager_user_permissions(pool: PgPool) {
        let (app, _bg_services) = create_test_app(pool.clone(), false).await;
        let platform_manager = create_test_user(&pool, Role::PlatformManager).await; // Non-admin PlatformManager
        let standard_user = create_test_user(&pool, Role::StandardUser).await;

        // PlatformManager should be able to list all users
        let response = app
            .get("/admin/api/v1/users")
            .add_header(&add_auth_headers(&platform_manager)[0].0, &add_auth_headers(&platform_manager)[0].1)
            .add_header(&add_auth_headers(&platform_manager)[1].0, &add_auth_headers(&platform_manager)[1].1)
            .await;
        response.assert_status_ok();

        // PlatformManager should be able to get any user
        let response = app
            .get(&format!("/admin/api/v1/users/{}", standard_user.id))
            .add_header(&add_auth_headers(&platform_manager)[0].0, &add_auth_headers(&platform_manager)[0].1)
            .add_header(&add_auth_headers(&platform_manager)[1].0, &add_auth_headers(&platform_manager)[1].1)
            .await;
        response.assert_status_ok();

        // PlatformManager should be able to create users
        let new_user = json!({
            "username": "created_by_pm",
            "email": "createdbypm@example.com",
            "roles": ["StandardUser"]
        });

        let response = app
            .post("/admin/api/v1/users")
            .add_header(&add_auth_headers(&platform_manager)[0].0, &add_auth_headers(&platform_manager)[0].1)
            .add_header(&add_auth_headers(&platform_manager)[1].0, &add_auth_headers(&platform_manager)[1].1)
            .json(&new_user)
            .await;
        response.assert_status(axum::http::StatusCode::CREATED);
        let created_user: UserResponse = response.json();

        // PlatformManager should be able to update users
        let update_data = json!({"display_name": "Updated by PM"});
        let response = app
            .patch(&format!("/admin/api/v1/users/{}", created_user.id))
            .add_header(&add_auth_headers(&platform_manager)[0].0, &add_auth_headers(&platform_manager)[0].1)
            .add_header(&add_auth_headers(&platform_manager)[1].0, &add_auth_headers(&platform_manager)[1].1)
            .json(&update_data)
            .await;
        response.assert_status_ok();

        // PlatformManager should be able to delete users
        let response = app
            .delete(&format!("/admin/api/v1/users/{}", created_user.id))
            .add_header(&add_auth_headers(&platform_manager)[0].0, &add_auth_headers(&platform_manager)[0].1)
            .add_header(&add_auth_headers(&platform_manager)[1].0, &add_auth_headers(&platform_manager)[1].1)
            .await;
        response.assert_status(axum::http::StatusCode::NO_CONTENT);
    }

    #[sqlx::test]
    #[test_log::test]
    async fn test_multi_role_user_permissions(pool: PgPool) {
        let (app, _bg_services) = create_test_app(pool.clone(), false).await;

        // User with StandardUser + RequestViewer should have additive permissions
        let multi_role_user = create_test_user_with_roles(&pool, vec![Role::StandardUser, Role::RequestViewer]).await;
        let other_user = create_test_user(&pool, Role::StandardUser).await;

        // Should be able to get their own info (both roles have ReadOwn for Users)
        let response = app
            .get("/admin/api/v1/users/current")
            .add_header(&add_auth_headers(&multi_role_user)[0].0, &add_auth_headers(&multi_role_user)[0].1)
            .add_header(&add_auth_headers(&multi_role_user)[1].0, &add_auth_headers(&multi_role_user)[1].1)
            .await;
        response.assert_status_ok();

        // Should NOT be able to list all users (neither role has ReadAll for Users)
        let response = app
            .get("/admin/api/v1/users")
            .add_header(&add_auth_headers(&multi_role_user)[0].0, &add_auth_headers(&multi_role_user)[0].1)
            .add_header(&add_auth_headers(&multi_role_user)[1].0, &add_auth_headers(&multi_role_user)[1].1)
            .await;
        response.assert_status_forbidden();

        // Should NOT be able to get other users (neither role has ReadAll for Users)
        let response = app
            .get(&format!("/admin/api/v1/users/{}", other_user.id))
            .add_header(&add_auth_headers(&multi_role_user)[0].0, &add_auth_headers(&multi_role_user)[0].1)
            .add_header(&add_auth_headers(&multi_role_user)[1].0, &add_auth_headers(&multi_role_user)[1].1)
            .await;
        response.assert_status_forbidden();

        // Should NOT be able to create users (neither role has CreateAll)
        let new_user = json!({
            "username": "should_not_work",
            "email": "shouldnotwork@example.com",
            "roles": ["StandardUser"]
        });

        let response = app
            .post("/admin/api/v1/users")
            .add_header(&add_auth_headers(&multi_role_user)[0].0, &add_auth_headers(&multi_role_user)[0].1)
            .add_header(&add_auth_headers(&multi_role_user)[1].0, &add_auth_headers(&multi_role_user)[1].1)
            .json(&new_user)
            .await;
        response.assert_status_forbidden();

        // User with PlatformManager + RequestViewer should have full user management
        let full_admin = create_test_user_with_roles(&pool, vec![Role::PlatformManager, Role::RequestViewer]).await;

        let response = app
            .get("/admin/api/v1/users")
            .add_header(&add_auth_headers(&full_admin)[0].0, &add_auth_headers(&full_admin)[0].1)
            .add_header(&add_auth_headers(&full_admin)[1].0, &add_auth_headers(&full_admin)[1].1)
            .await;
        response.assert_status_ok();

        let response = app
            .post("/admin/api/v1/users")
            .add_header(&add_auth_headers(&full_admin)[0].0, &add_auth_headers(&full_admin)[0].1)
            .add_header(&add_auth_headers(&full_admin)[1].0, &add_auth_headers(&full_admin)[1].1)
            .json(&new_user)
            .await;
        response.assert_status(axum::http::StatusCode::CREATED);
    }

    #[sqlx::test]
    #[test_log::test]
    async fn test_user_access_isolation(pool: PgPool) {
        let (app, _bg_services) = create_test_app(pool.clone(), false).await;
        let user1 = create_test_user(&pool, Role::StandardUser).await;
        let user2 = create_test_user(&pool, Role::StandardUser).await;
        let user3 = create_test_user(&pool, Role::RequestViewer).await;

        // Test that users can only access their own data
        let users = vec![&user1, &user2, &user3];
        let targets = vec![&user1, &user2, &user3];

        for user in &users {
            for target in &targets {
                let response = app
                    .get(&format!("/admin/api/v1/users/{}", target.id))
                    .add_header(&add_auth_headers(user)[0].0, &add_auth_headers(user)[0].1)
                    .add_header(&add_auth_headers(user)[1].0, &add_auth_headers(user)[1].1)
                    .await;

                if user.id == target.id {
                    // Users should be able to access their own data
                    response.assert_status_ok();
                    let user_response: UserResponse = response.json();
                    assert_eq!(user_response.id, target.id);
                } else {
                    // Users should NOT be able to access other users' data
                    response.assert_status_forbidden();
                }
            }
        }
    }

    #[sqlx::test]
    #[test_log::test]
    async fn test_role_layering_user_access(pool: PgPool) {
        let (app, _bg_services) = create_test_app(pool.clone(), false).await;

        // Test different role combinations for user access
        let role_tests = vec![
            (vec![Role::StandardUser], false, true, false, "StandardUser only"),
            (vec![Role::RequestViewer], false, true, false, "RequestViewer only"),
            (vec![Role::PlatformManager], true, true, true, "PlatformManager only"),
            (
                vec![Role::StandardUser, Role::RequestViewer],
                false,
                true,
                false,
                "StandardUser + RequestViewer",
            ),
            (
                vec![Role::PlatformManager, Role::RequestViewer],
                true,
                true,
                true,
                "PlatformManager + RequestViewer",
            ),
            (
                vec![Role::PlatformManager, Role::StandardUser],
                true,
                true,
                true,
                "PlatformManager + StandardUser",
            ),
        ];

        for (roles, can_list_users, can_read_own, can_manage_users, _description) in role_tests {
            let user = create_test_user_with_roles(&pool, roles).await;

            // Test list users access
            let response = app
                .get("/admin/api/v1/users")
                .add_header(&add_auth_headers(&user)[0].0, &add_auth_headers(&user)[0].1)
                .add_header(&add_auth_headers(&user)[1].0, &add_auth_headers(&user)[1].1)
                .await;

            if can_list_users {
                response.assert_status_ok();
            } else {
                response.assert_status_forbidden();
            }

            // Test read own user access
            let response = app
                .get("/admin/api/v1/users/current")
                .add_header(&add_auth_headers(&user)[0].0, &add_auth_headers(&user)[0].1)
                .add_header(&add_auth_headers(&user)[1].0, &add_auth_headers(&user)[1].1)
                .await;

            if can_read_own {
                response.assert_status_ok();
            } else {
                response.assert_status_forbidden();
            }

            // Test user creation access
            let new_user = json!({
                "username": format!("test_user_{}", uuid::Uuid::new_v4()),
                "email": format!("test{}@example.com", uuid::Uuid::new_v4()),
                "roles": ["StandardUser"]
            });

            let response = app
                .post("/admin/api/v1/users")
                .add_header(&add_auth_headers(&user)[0].0, &add_auth_headers(&user)[0].1)
                .add_header(&add_auth_headers(&user)[1].0, &add_auth_headers(&user)[1].1)
                .json(&new_user)
                .await;

            if can_manage_users {
                response.assert_status(axum::http::StatusCode::CREATED);
                // Clean up created user
                let created_user: UserResponse = response.json();
                app.delete(&format!("/admin/api/v1/users/{}", created_user.id))
                    .add_header(&add_auth_headers(&user)[0].0, &add_auth_headers(&user)[0].1)
                    .add_header(&add_auth_headers(&user)[1].0, &add_auth_headers(&user)[1].1)
                    .await
                    .assert_status(axum::http::StatusCode::NO_CONTENT);
            } else {
                response.assert_status_forbidden();
            }
        }
    }

    #[sqlx::test]
    #[test_log::test]
    async fn test_admin_bypass_vs_role_permissions(pool: PgPool) {
        let (app, _bg_services) = create_test_app(pool.clone(), false).await;

        // Test that admin users bypass role restrictions
        let admin_user = create_test_admin_user(&pool, Role::RequestViewer).await; // Admin with minimal role
        let non_admin_pm = create_test_user(&pool, Role::PlatformManager).await; // Non-admin with powerful role

        // Both should be able to list users, but for different reasons:
        // - Admin bypasses permission checks entirely
        // - PlatformManager has ReadAll permission for Users

        let admin_response = app
            .get("/admin/api/v1/users")
            .add_header(&add_auth_headers(&admin_user)[0].0, &add_auth_headers(&admin_user)[0].1)
            .add_header(&add_auth_headers(&admin_user)[1].0, &add_auth_headers(&admin_user)[1].1)
            .await;
        admin_response.assert_status_ok();

        let pm_response = app
            .get("/admin/api/v1/users")
            .add_header(&add_auth_headers(&non_admin_pm)[0].0, &add_auth_headers(&non_admin_pm)[0].1)
            .add_header(&add_auth_headers(&non_admin_pm)[1].0, &add_auth_headers(&non_admin_pm)[1].1)
            .await;
        pm_response.assert_status_ok();

        // Create a StandardUser who should not be able to list users
        let standard_user = create_test_user(&pool, Role::StandardUser).await;
        let standard_response = app
            .get("/admin/api/v1/users")
            .add_header(&add_auth_headers(&standard_user)[0].0, &add_auth_headers(&standard_user)[0].1)
            .add_header(&add_auth_headers(&standard_user)[1].0, &add_auth_headers(&standard_user)[1].1)
            .await;
        standard_response.assert_status_forbidden();
    }

    #[sqlx::test]
    #[test_log::test]
    async fn test_update_user_roles_backend_protection(pool: PgPool) {
        let (app, _bg_services) = create_test_app(pool.clone(), false).await;
        let admin_user = create_test_admin_user(&pool, Role::PlatformManager).await;
        let regular_user = create_test_user_with_roles(&pool, vec![Role::StandardUser, Role::PlatformManager]).await;

        // Try to update user roles to only RequestViewer (omitting StandardUser)
        let update_data = json!({
            "roles": ["RequestViewer"] // Intentionally omitting StandardUser
        });

        let response = app
            .patch(&format!("/admin/api/v1/users/{}", regular_user.id))
            .add_header(&add_auth_headers(&admin_user)[0].0, &add_auth_headers(&admin_user)[0].1)
            .add_header(&add_auth_headers(&admin_user)[1].0, &add_auth_headers(&admin_user)[1].1)
            .json(&update_data)
            .await;

        response.assert_status_ok();
        let updated_user: UserResponse = response.json();

        // Backend should have automatically added StandardUser role
        assert_eq!(updated_user.roles.len(), 2);
        assert!(updated_user.roles.contains(&Role::StandardUser));
        assert!(updated_user.roles.contains(&Role::RequestViewer));
        assert!(!updated_user.roles.contains(&Role::PlatformManager));

        // Try to update with empty roles array
        let update_data = json!({
            "roles": []
        });

        let response = app
            .patch(&format!("/admin/api/v1/users/{}", regular_user.id))
            .add_header(&add_auth_headers(&admin_user)[0].0, &add_auth_headers(&admin_user)[0].1)
            .add_header(&add_auth_headers(&admin_user)[1].0, &add_auth_headers(&admin_user)[1].1)
            .json(&update_data)
            .await;

        response.assert_status_ok();
        let updated_user: UserResponse = response.json();

        // Backend should have automatically added StandardUser role
        assert_eq!(updated_user.roles.len(), 1);
        assert!(updated_user.roles.contains(&Role::StandardUser));
    }

    async fn create_initial_credit_transaction(pool: &PgPool, user_id: UserId, amount: &str) -> Uuid {
        let mut conn = pool.acquire().await.expect("Failed to acquire connection");
        let mut credits_repo = Credits::new(&mut conn);

        let amount_decimal = Decimal::from_str(amount).expect("Invalid decimal amount");
        let request = CreditTransactionCreateDBRequest::admin_grant(
            user_id,
            uuid::Uuid::nil(), // System ID for initial credits
            amount_decimal,
            Some("Initial credit grant".to_string()),
        );

        credits_repo
            .create_transaction(&request)
            .await
            .expect("Failed to create transaction")
            .id
    }

    // Test: GET /users/{user_id}/balance returns own balance for standard user
    #[sqlx::test]
    #[test_log::test]
    async fn test_get_own_balance_as_standard_user(pool: PgPool) {
        let (app, _bg_services) = create_test_app(pool.clone(), false).await;
        let user = create_test_user(&pool, Role::StandardUser).await;

        // Add some credits
        create_initial_credit_transaction(&pool, user.id, "150.0").await;

        let response = app
            .get(&format!("/admin/api/v1/users/{}?include=billing", user.id))
            .add_header(&add_auth_headers(&user)[0].0, &add_auth_headers(&user)[0].1)
            .add_header(&add_auth_headers(&user)[1].0, &add_auth_headers(&user)[1].1)
            .await;

        response.assert_status_ok();
        let balance: UserResponse = response.json();
        assert_eq!(balance.id, user.id);
        assert_eq!(balance.credit_balance, Some(150.0));
    }

    // Test: GET /users/current/balance works for standard user with billing info
    #[sqlx::test]
    #[test_log::test]
    async fn test_get_current_user_balance(pool: PgPool) {
        let (app, _bg_services) = create_test_app(pool.clone(), false).await;
        let user = create_test_user(&pool, Role::StandardUser).await;

        // Add some credits
        create_initial_credit_transaction(&pool, user.id, "125.0").await;

        let response = app
            .get("/admin/api/v1/users/current?include=billing")
            .add_header(&add_auth_headers(&user)[0].0, &add_auth_headers(&user)[0].1)
            .add_header(&add_auth_headers(&user)[1].0, &add_auth_headers(&user)[1].1)
            .await;

        response.assert_status_ok();
        let balance: UserResponse = response.json();
        assert_eq!(balance.id, user.id);
        assert_eq!(balance.credit_balance, Some(125.0));
    }

    // Test: GET /users/{other_user_id} returns 403 for standard user asking for billing
    #[sqlx::test]
    #[test_log::test]
    async fn test_get_other_user_balance_forbidden(pool: PgPool) {
        let (app, _bg_services) = create_test_app(pool.clone(), false).await;
        let user1 = create_test_user(&pool, Role::StandardUser).await;
        let user2 = create_test_user(&pool, Role::StandardUser).await;

        let response = app
            .get(&format!("/admin/api/v1/users/{}?include=billing", user2.id))
            .add_header(&add_auth_headers(&user1)[0].0, &add_auth_headers(&user1)[0].1)
            .add_header(&add_auth_headers(&user1)[1].0, &add_auth_headers(&user1)[1].1)
            .await;

        response.assert_status_forbidden();
    }

    // Test: GET /users/{user_id} works for own balance as RequestViewer
    #[sqlx::test]
    #[test_log::test]
    async fn test_get_own_balance_as_request_viewer(pool: PgPool) {
        let (app, _bg_services) = create_test_app(pool.clone(), false).await;
        let user = create_test_user(&pool, Role::RequestViewer).await;

        // Add some credits
        create_initial_credit_transaction(&pool, user.id, "150.0").await;

        let response = app
            .get(&format!("/admin/api/v1/users/{}?include=billing", user.id))
            .add_header(&add_auth_headers(&user)[0].0, &add_auth_headers(&user)[0].1)
            .add_header(&add_auth_headers(&user)[1].0, &add_auth_headers(&user)[1].1)
            .await;

        response.assert_status_ok();
        let balance: UserResponse = response.json();
        assert_eq!(balance.id, user.id);
        assert_eq!(balance.credit_balance, Some(150.0));
    }

    // Test: GET /users/current works for RequestViewer with billing info
    #[sqlx::test]
    #[test_log::test]
    async fn test_get_current_user_balance_request_viewer(pool: PgPool) {
        let (app, _bg_services) = create_test_app(pool.clone(), false).await;
        let user = create_test_user(&pool, Role::RequestViewer).await;

        // Add some credits
        create_initial_credit_transaction(&pool, user.id, "125.0").await;

        let response = app
            .get("/admin/api/v1/users/current?include=billing")
            .add_header(&add_auth_headers(&user)[0].0, &add_auth_headers(&user)[0].1)
            .add_header(&add_auth_headers(&user)[1].0, &add_auth_headers(&user)[1].1)
            .await;

        response.assert_status_ok();
        let balance: UserResponse = response.json();
        assert_eq!(balance.id, user.id);
        assert_eq!(balance.credit_balance, Some(125.0));
    }

    // Test: GET /users/current works for PlatformManager with billing info
    #[sqlx::test]
    #[test_log::test]
    async fn test_get_current_user_balance_platform_manager(pool: PgPool) {
        let (app, _bg_services) = create_test_app(pool.clone(), false).await;
        let user = create_test_user(&pool, Role::PlatformManager).await;

        // Add some credits
        create_initial_credit_transaction(&pool, user.id, "125.0").await;

        let response = app
            .get("/admin/api/v1/users/current?include=billing")
            .add_header(&add_auth_headers(&user)[0].0, &add_auth_headers(&user)[0].1)
            .add_header(&add_auth_headers(&user)[1].0, &add_auth_headers(&user)[1].1)
            .await;

        response.assert_status_ok();
        let balance: UserResponse = response.json();
        assert_eq!(balance.id, user.id);
        assert_eq!(balance.credit_balance, Some(125.0));
    }

    // Test: PlatformManager can view any user's balance (has ReadAll permission)
    #[sqlx::test]
    #[test_log::test]
    async fn test_platform_manager_can_view_any_balance(pool: PgPool) {
        let (app, _bg_services) = create_test_app(pool.clone(), false).await;
        let platform_manager = create_test_user(&pool, Role::PlatformManager).await;
        let user = create_test_user(&pool, Role::StandardUser).await;

        // Add some credits to user
        create_initial_credit_transaction(&pool, user.id, "300.0").await;

        let response = app
            .get(&format!("/admin/api/v1/users/{}?include=billing", user.id))
            .add_header(&add_auth_headers(&platform_manager)[0].0, &add_auth_headers(&platform_manager)[0].1)
            .add_header(&add_auth_headers(&platform_manager)[1].0, &add_auth_headers(&platform_manager)[1].1)
            .await;

        response.assert_status_ok();
        let balance: UserResponse = response.json();
        assert_eq!(balance.id, user.id);
        assert_eq!(balance.credit_balance, Some(300.0));
    }

    // Test: BillingManager can view any user's balance
    #[sqlx::test]
    #[test_log::test]
    async fn test_billing_manager_can_view_any_balance(pool: PgPool) {
        let (app, _bg_services) = create_test_app(pool.clone(), false).await;
        let billing_manager = create_test_user(&pool, Role::BillingManager).await;
        let user = create_test_user(&pool, Role::StandardUser).await;

        // Add some credits to user
        create_initial_credit_transaction(&pool, user.id, "300.0").await;

        let response = app
            .get(&format!("/admin/api/v1/users/{}?include=billing", user.id))
            .add_header(&add_auth_headers(&billing_manager)[0].0, &add_auth_headers(&billing_manager)[0].1)
            .add_header(&add_auth_headers(&billing_manager)[1].0, &add_auth_headers(&billing_manager)[1].1)
            .await;

        response.assert_status_ok();
        let balance: UserResponse = response.json();
        assert_eq!(balance.id, user.id);
        assert_eq!(balance.credit_balance, Some(300.0));
    }

    #[sqlx::test]
    #[test_log::test]
    async fn test_onboarding_redirect_for_new_user_with_null_last_login(pool: PgPool) {
        let mut config = create_test_config();
        config.onboarding_url = Some("https://onboarding.example.com".to_string());
        let (app, _bg_services) = create_test_app_with_config(pool.clone(), config, false).await;
        let user = create_test_user(&pool, Role::StandardUser).await;

        // New user has null last_login — should get onboarding redirect
        let response = app
            .get("/admin/api/v1/users/current")
            .add_header(&add_auth_headers(&user)[0].0, &add_auth_headers(&user)[0].1)
            .add_header(&add_auth_headers(&user)[1].0, &add_auth_headers(&user)[1].1)
            .await;

        response.assert_status_ok();
        let current_user: UserResponse = response.json();
        assert_eq!(
            current_user.onboarding_redirect_url.as_deref(),
            Some("https://onboarding.example.com"),
        );
    }

    #[sqlx::test]
    #[test_log::test]
    async fn test_onboarding_redirect_for_recently_created_user_with_last_login_set(pool: PgPool) {
        let mut config = create_test_config();
        config.onboarding_url = Some("https://onboarding.example.com".to_string());
        let (app, _bg_services) = create_test_app_with_config(pool.clone(), config, false).await;
        let user = create_test_user(&pool, Role::StandardUser).await;

        // Simulate the race: auth extractor's background task set last_login
        // moments after account creation (within the 10-second window)
        sqlx::query!(
            "UPDATE users SET last_login = created_at + interval '1 second' WHERE id = $1",
            user.id
        )
        .execute(&pool)
        .await
        .unwrap();

        let response = app
            .get("/admin/api/v1/users/current")
            .add_header(&add_auth_headers(&user)[0].0, &add_auth_headers(&user)[0].1)
            .add_header(&add_auth_headers(&user)[1].0, &add_auth_headers(&user)[1].1)
            .await;

        response.assert_status_ok();
        let current_user: UserResponse = response.json();
        assert_eq!(
            current_user.onboarding_redirect_url.as_deref(),
            Some("https://onboarding.example.com"),
            "Should still redirect when last_login is within 10 seconds of created_at"
        );
    }

    #[sqlx::test]
    #[test_log::test]
    async fn test_no_onboarding_redirect_for_returning_user(pool: PgPool) {
        let mut config = create_test_config();
        config.onboarding_url = Some("https://onboarding.example.com".to_string());
        let (app, _bg_services) = create_test_app_with_config(pool.clone(), config, false).await;
        let user = create_test_user(&pool, Role::StandardUser).await;

        // Set last_login to well past the 10-second window (returning user)
        sqlx::query!(
            "UPDATE users SET last_login = created_at + interval '2 hours' WHERE id = $1",
            user.id
        )
        .execute(&pool)
        .await
        .unwrap();

        let response = app
            .get("/admin/api/v1/users/current")
            .add_header(&add_auth_headers(&user)[0].0, &add_auth_headers(&user)[0].1)
            .add_header(&add_auth_headers(&user)[1].0, &add_auth_headers(&user)[1].1)
            .await;

        response.assert_status_ok();
        let current_user: UserResponse = response.json();
        assert!(
            current_user.onboarding_redirect_url.is_none(),
            "Returning user should not get onboarding redirect"
        );
    }

    #[sqlx::test]
    #[test_log::test]
    async fn test_no_onboarding_redirect_when_not_configured(pool: PgPool) {
        // Default test config has onboarding_url: None
        let (app, _bg_services) = create_test_app(pool.clone(), false).await;
        let user = create_test_user(&pool, Role::StandardUser).await;

        let response = app
            .get("/admin/api/v1/users/current")
            .add_header(&add_auth_headers(&user)[0].0, &add_auth_headers(&user)[0].1)
            .add_header(&add_auth_headers(&user)[1].0, &add_auth_headers(&user)[1].1)
            .await;

        response.assert_status_ok();
        let current_user: UserResponse = response.json();
        assert!(
            current_user.onboarding_redirect_url.is_none(),
            "Should not include redirect when onboarding_url is not configured"
        );
    }
}
