/*!
 * Role-Based Access Control (RBAC) Integration Tests
 * 
 * Tests comprehensive role-based access control including:
 * - Admin vs User permission boundaries
 * - Resource ownership and isolation
 * - Cross-user access prevention
 * - Privilege escalation prevention
 * - Administrative operations access control
 * - Data visibility and privacy
 * - Role transition scenarios
 * - Security boundary enforcement
 */

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

use readur::models::{CreateUser, LoginRequest, LoginResponse, UserRole};
use readur::routes::documents::types::PaginatedDocumentsResponse;

fn get_base_url() -> String {
    std::env::var("API_URL").unwrap_or_else(|_| "http://localhost:8000".to_string())
}

/// Test client for RBAC scenarios with multiple user contexts
struct RBACTestClient {
    client: Client,
    admin_token: Option<String>,
    admin_user_id: Option<String>,
    user1_token: Option<String>,
    user1_user_id: Option<String>,
    user2_token: Option<String>,
    user2_user_id: Option<String>,
}

impl RBACTestClient {
    fn new() -> Self {
        Self {
            client: Client::new(),
            admin_token: None,
            admin_user_id: None,
            user1_token: None,
            user1_user_id: None,
            user2_token: None,
            user2_user_id: None,
        }
    }
    
    /// Setup all test users (admin, user1, user2)
    async fn setup_all_users(&mut self) -> Result<(), Box<dyn std::error::Error>> {
        // Use UUID for guaranteed uniqueness across concurrent test execution
        let test_id = Uuid::new_v4().simple().to_string();
        let nanos = std::time::SystemTime::now()
            .duration_since(std::time::UNIX_EPOCH)
            .unwrap()
            .as_nanos();
        
        // Setup admin user
        let admin_username = format!("rbac_admin_{}_{}", test_id, nanos);
        let admin_email = format!("rbac_admin_{}@{}.example.com", test_id, nanos);
        let (admin_token, admin_id) = self.register_and_login_user(&admin_username, &admin_email, UserRole::Admin).await?;
        self.admin_token = Some(admin_token);
        self.admin_user_id = admin_id;
        
        // Setup first regular user
        let user1_username = format!("rbac_user1_{}_{}", test_id, nanos);
        let user1_email = format!("rbac_user1_{}@{}.example.com", test_id, nanos);
        let (user1_token, user1_id) = self.register_and_login_user(&user1_username, &user1_email, UserRole::User).await?;
        self.user1_token = Some(user1_token);
        self.user1_user_id = user1_id;
        
        // Setup second regular user
        let user2_username = format!("rbac_user2_{}_{}", test_id, nanos);
        let user2_email = format!("rbac_user2_{}@{}.example.com", test_id, nanos);
        let (user2_token, user2_id) = self.register_and_login_user(&user2_username, &user2_email, UserRole::User).await?;
        self.user2_token = Some(user2_token);
        self.user2_user_id = user2_id;
        
        Ok(())
    }
    
    /// Helper to register and login a single user
    async fn register_and_login_user(&self, username: &str, email: &str, role: UserRole) -> Result<(String, Option<String>), Box<dyn std::error::Error>> {
        // Try up to 3 times with different unique identifiers if we get conflicts
        for attempt in 0..3 {
            let (actual_username, actual_email) = if attempt == 0 {
                (username.to_string(), email.to_string())
            } else {
                let retry_id = Uuid::new_v4().simple().to_string();
                (format!("{}_{}", username, retry_id), format!("retry_{}_{}", retry_id, email))
            };
            
            let password = "rbacpassword123";
            
            // Register user
            let user_data = CreateUser {
                username: actual_username.clone(),
                email: actual_email.clone(),
                password: password.to_string(),
                role: Some(role),
            };
            
            let register_response = self.client
                .post(&format!("{}/api/auth/register", get_base_url()))
                .json(&user_data)
                .send()
                .await?;
            
            if register_response.status().is_success() {
                // Registration successful, now login
                return self.login_user(&actual_username, password).await;
            }
            
            let error_text = register_response.text().await?;
            
            // If it's not a duplicate key error, fail immediately
            if !error_text.contains("duplicate key") && !error_text.contains("already exists") {
                return Err(format!("Registration failed for {}: {}", actual_username, error_text).into());
            }
            
            // If it's a duplicate key error and this was our last attempt, fail
            if attempt == 2 {
                return Err(format!("Registration failed after 3 attempts for {}: {}", username, error_text).into());
            }
            
            // Otherwise, try again with a different unique identifier
        }
        
        Err("Unexpected error in register_and_login_user".into())
    }
    
    /// Helper to login a user and return token and user ID
    async fn login_user(&self, username: &str, password: &str) -> Result<(String, Option<String>), Box<dyn std::error::Error>> {
        
        // Login to get token
        let login_data = LoginRequest {
            username: username.to_string(),
            password: password.to_string(),
        };
        
        let login_response = self.client
            .post(&format!("{}/api/auth/login", get_base_url()))
            .json(&login_data)
            .send()
            .await?;
        
        if !login_response.status().is_success() {
            return Err(format!("Login failed for {}: {}", username, login_response.text().await?).into());
        }
        
        let login_result: LoginResponse = login_response.json().await?;
        
        // Get user info to extract user ID
        let me_response = self.client
            .get(&format!("{}/api/auth/me", get_base_url()))
            .header("Authorization", format!("Bearer {}", login_result.token))
            .send()
            .await?;
        
        let user_id = if me_response.status().is_success() {
            let user_info: Value = me_response.json().await?;
            user_info["id"].as_str().map(|s| s.to_string())
        } else {
            None
        };
        
        Ok((login_result.token, user_id))
    }
    
    /// Upload a document as a specific user
    async fn upload_document_as_user(&self, user: UserType, content: &str, filename: &str) -> Result<Value, Box<dyn std::error::Error>> {
        let token = match user {
            UserType::Admin => self.admin_token.as_ref(),
            UserType::User1 => self.user1_token.as_ref(),
            UserType::User2 => self.user2_token.as_ref(),
        }.ok_or("User not set up")?;
        
        // Generate unique content to prevent file hash collisions
        let unique_id = Uuid::new_v4();
        let nanos = std::time::SystemTime::now()
            .duration_since(std::time::UNIX_EPOCH)
            .unwrap()
            .as_nanos();
        let unique_content = format!("{}\n\nUnique ID: {}\nTimestamp: {}\nRandom: {}", 
            content, unique_id, nanos, Uuid::new_v4());
        
        let part = reqwest::multipart::Part::text(unique_content)
            .file_name(filename.to_string())
            .mime_str("text/plain")?;
        let form = reqwest::multipart::Form::new()
            .part("file", part);
        
        let response = self.client
            .post(&format!("{}/api/documents", get_base_url()))
            .header("Authorization", format!("Bearer {}", token))
            .multipart(form)
            .send()
            .await?;
        
        if !response.status().is_success() {
            return Err(format!("Upload failed: {}", response.text().await?).into());
        }
        
        let document: Value = response.json().await?;
        Ok(document)
    }
    
    /// Get documents list as a specific user
    async fn get_documents_as_user(&self, user: UserType) -> Result<Vec<Value>, Box<dyn std::error::Error>> {
        let token = match user {
            UserType::Admin => self.admin_token.as_ref(),
            UserType::User1 => self.user1_token.as_ref(),
            UserType::User2 => self.user2_token.as_ref(),
        }.ok_or("User not set up")?;
        
        let response = self.client
            .get(&format!("{}/api/documents", get_base_url()))
            .header("Authorization", format!("Bearer {}", token))
            .send()
            .await?;
        
        if !response.status().is_success() {
            return Err(format!("Get documents failed: {}", response.text().await?).into());
        }
        
        let paginated_response: PaginatedDocumentsResponse = response.json().await?;
        let documents: Vec<Value> = paginated_response.documents
            .into_iter()
            .map(|doc| serde_json::to_value(doc).unwrap())
            .collect();
        Ok(documents)
    }
    
    /// Try to access a specific document as a user
    async fn try_access_document(&self, user: UserType, document_id: &str) -> Result<reqwest::StatusCode, Box<dyn std::error::Error>> {
        let token = match user {
            UserType::Admin => self.admin_token.as_ref(),
            UserType::User1 => self.user1_token.as_ref(),
            UserType::User2 => self.user2_token.as_ref(),
        }.ok_or("User not set up")?;
        
        let response = self.client
            .get(&format!("{}/api/documents/{}/ocr", get_base_url(), document_id))
            .header("Authorization", format!("Bearer {}", token))
            .send()
            .await?;
        
        Ok(response.status())
    }
    
    /// Create a source as a specific user
    async fn create_source_as_user(&self, user: UserType, source_name: &str) -> Result<Value, Box<dyn std::error::Error>> {
        let token = match user {
            UserType::Admin => self.admin_token.as_ref(),
            UserType::User1 => self.user1_token.as_ref(),
            UserType::User2 => self.user2_token.as_ref(),
        }.ok_or("User not set up")?;
        
        let source_data = json!({
            "name": source_name,
            "source_type": "webdav",
            "config": {
                "server_url": "https://example.com",
                "username": "testuser",
                "password": "testpass",
                "auto_sync": false,
                "sync_interval_minutes": 60,
                "watch_folders": ["/Documents"],
                "file_extensions": [".pdf"]
            }
        });
        
        let response = self.client
            .post(&format!("{}/api/sources", get_base_url()))
            .header("Authorization", format!("Bearer {}", token))
            .json(&source_data)
            .send()
            .await?;
        
        if !response.status().is_success() {
            return Err(format!("Source creation failed: {}", response.text().await?).into());
        }
        
        let source: Value = response.json().await?;
        Ok(source)
    }
    
    /// Try to access a source as a user
    async fn try_access_source(&self, user: UserType, source_id: &str) -> Result<reqwest::StatusCode, Box<dyn std::error::Error>> {
        let token = match user {
            UserType::Admin => self.admin_token.as_ref(),
            UserType::User1 => self.user1_token.as_ref(),
            UserType::User2 => self.user2_token.as_ref(),
        }.ok_or("User not set up")?;
        
        let response = self.client
            .get(&format!("{}/api/sources/{}", get_base_url(), source_id))
            .header("Authorization", format!("Bearer {}", token))
            .send()
            .await?;
        
        Ok(response.status())
    }
    
    /// Try to access admin endpoints as a user
    async fn try_admin_operation(&self, user: UserType, operation: AdminOperation) -> Result<reqwest::StatusCode, Box<dyn std::error::Error>> {
        let token = match user {
            UserType::Admin => self.admin_token.as_ref(),
            UserType::User1 => self.user1_token.as_ref(),
            UserType::User2 => self.user2_token.as_ref(),
        }.ok_or("User not set up")?;
        
        let response = match operation {
            AdminOperation::ListUsers => {
                self.client
                    .get(&format!("{}/api/users", get_base_url()))
                    .header("Authorization", format!("Bearer {}", token))
                    .send()
                    .await?
            }
            AdminOperation::CreateUser => {
                self.client
                    .post(&format!("{}/api/users", get_base_url()))
                    .header("Authorization", format!("Bearer {}", token))
                    .json(&json!({
                        "username": "test_admin_created",
                        "email": "admin_created@example.com",
                        "password": "password123",
                        "role": "user"
                    }))
                    .send()
                    .await?
            }
            AdminOperation::GetMetrics => {
                self.client
                    .get(&format!("{}/api/metrics", get_base_url()))
                    .header("Authorization", format!("Bearer {}", token))
                    .send()
                    .await?
            }
            AdminOperation::GetQueueStats => {
                self.client
                    .get(&format!("{}/api/queue/stats", get_base_url()))
                    .header("Authorization", format!("Bearer {}", token))
                    .send()
                    .await?
            }
            AdminOperation::RequeueFailedJobs => {
                self.client
                    .post(&format!("{}/api/queue/requeue-failed", get_base_url()))
                    .header("Authorization", format!("Bearer {}", token))
                    .send()
                    .await?
            }
        };
        
        Ok(response.status())
    }
    
    /// Try to modify another user's resource
    async fn try_modify_user_resource(&self, actor: UserType, target_user_id: &str) -> Result<reqwest::StatusCode, Box<dyn std::error::Error>> {
        let token = match actor {
            UserType::Admin => self.admin_token.as_ref(),
            UserType::User1 => self.user1_token.as_ref(),
            UserType::User2 => self.user2_token.as_ref(),
        }.ok_or("User not set up")?;
        
        let response = self.client
            .put(&format!("{}/api/users/{}", get_base_url(), target_user_id))
            .header("Authorization", format!("Bearer {}", token))
            .json(&json!({
                "username": "modified_user",
                "email": "modified@example.com",
                "role": "user"
            }))
            .send()
            .await?;
        
        Ok(response.status())
    }
}

#[derive(Clone, Copy)]
enum UserType {
    Admin,
    User1,
    User2,
}

#[derive(Clone, Copy)]
enum AdminOperation {
    ListUsers,
    CreateUser,
    GetMetrics,
    GetQueueStats,
    RequeueFailedJobs,
}

#[tokio::test]
async fn test_document_ownership_isolation() {
    println!("📄 Testing document ownership and isolation...");
    
    let mut client = RBACTestClient::new();
    client.setup_all_users().await
        .expect("Failed to setup test users");
    
    println!("✅ Setup complete: admin, user1, user2");
    
    // User1 uploads a document
    let user1_doc = client.upload_document_as_user(
        UserType::User1,
        "User1's private document content",
        "user1_private.txt"
    ).await.expect("Failed to upload User1 document");
    
    let user1_doc_id = user1_doc["id"].as_str().expect("Document should have document_id");
    println!("✅ User1 uploaded document: {}", user1_doc_id);
    
    // User2 uploads a document
    let user2_doc = client.upload_document_as_user(
        UserType::User2,
        "User2's private document content",
        "user2_private.txt"
    ).await.expect("Failed to upload User2 document");
    
    let user2_doc_id = user2_doc["id"].as_str().expect("Document should have document_id");
    println!("✅ User2 uploaded document: {}", user2_doc_id);
    
    // Test document list isolation
    let user1_docs = client.get_documents_as_user(UserType::User1).await
        .expect("Failed to get User1 documents");
    
    let user2_docs = client.get_documents_as_user(UserType::User2).await
        .expect("Failed to get User2 documents");
    
    // User1 should only see their own document
    let user1_sees_own = user1_docs.iter().any(|d| d["id"] == user1_doc_id);
    let user1_sees_user2 = user1_docs.iter().any(|d| d["id"] == user2_doc_id);
    
    assert!(user1_sees_own, "User1 should see their own document");
    assert!(!user1_sees_user2, "User1 should NOT see User2's document");
    
    // User2 should only see their own document
    let user2_sees_own = user2_docs.iter().any(|d| d["id"] == user2_doc_id);
    let user2_sees_user1 = user2_docs.iter().any(|d| d["id"] == user1_doc_id);
    
    assert!(user2_sees_own, "User2 should see their own document");
    assert!(!user2_sees_user1, "User2 should NOT see User1's document");
    
    println!("✅ Document list isolation verified");
    
    // Test direct document access
    let user1_access_own = client.try_access_document(UserType::User1, user1_doc_id).await
        .expect("Failed to test User1 access to own document");
    
    let user1_access_user2 = client.try_access_document(UserType::User1, user2_doc_id).await
        .expect("Failed to test User1 access to User2 document");
    
    assert!(user1_access_own.is_success(), "User1 should access their own document");
    assert!(!user1_access_user2.is_success(), "User1 should NOT access User2's document");
    
    let user2_access_own = client.try_access_document(UserType::User2, user2_doc_id).await
        .expect("Failed to test User2 access to own document");
    
    let user2_access_user1 = client.try_access_document(UserType::User2, user1_doc_id).await
        .expect("Failed to test User2 access to User1 document");
    
    assert!(user2_access_own.is_success(), "User2 should access their own document");
    assert!(!user2_access_user1.is_success(), "User2 should NOT access User1's document");
    
    println!("✅ Direct document access isolation verified");
    
    // Test admin access to all documents
    let admin_access_user1 = client.try_access_document(UserType::Admin, user1_doc_id).await
        .expect("Failed to test admin access to User1 document");
    
    let admin_access_user2 = client.try_access_document(UserType::Admin, user2_doc_id).await
        .expect("Failed to test admin access to User2 document");
    
    // Admin access depends on implementation - might have access or might not
    println!("ℹ️  Admin access to User1 doc: {}", admin_access_user1);
    println!("ℹ️  Admin access to User2 doc: {}", admin_access_user2);
    
    println!("🎉 Document ownership isolation test passed!");
}

#[tokio::test]
async fn test_source_ownership_isolation() {
    println!("🗂️ Testing source ownership and isolation...");
    
    let mut client = RBACTestClient::new();
    client.setup_all_users().await
        .expect("Failed to setup test users");
    
    println!("✅ Setup complete: admin, user1, user2");
    
    // User1 creates a source
    let user1_source = client.create_source_as_user(UserType::User1, "User1 WebDAV Source").await
        .expect("Failed to create User1 source");
    
    let user1_source_id = user1_source["id"].as_str().expect("Source should have ID");
    println!("✅ User1 created source: {}", user1_source_id);
    
    // User2 creates a source
    let user2_source = client.create_source_as_user(UserType::User2, "User2 WebDAV Source").await
        .expect("Failed to create User2 source");
    
    let user2_source_id = user2_source["id"].as_str().expect("Source should have ID");
    println!("✅ User2 created source: {}", user2_source_id);
    
    // Test cross-user source access
    let user1_access_user2_source = client.try_access_source(UserType::User1, user2_source_id).await
        .expect("Failed to test User1 access to User2 source");
    
    let user2_access_user1_source = client.try_access_source(UserType::User2, user1_source_id).await
        .expect("Failed to test User2 access to User1 source");
    
    assert!(!user1_access_user2_source.is_success(), "User1 should NOT access User2's source");
    assert!(!user2_access_user1_source.is_success(), "User2 should NOT access User1's source");
    
    println!("✅ Source cross-access prevention verified");
    
    // Test own source access
    let user1_access_own_source = client.try_access_source(UserType::User1, user1_source_id).await
        .expect("Failed to test User1 access to own source");
    
    let user2_access_own_source = client.try_access_source(UserType::User2, user2_source_id).await
        .expect("Failed to test User2 access to own source");
    
    assert!(user1_access_own_source.is_success(), "User1 should access their own source");
    assert!(user2_access_own_source.is_success(), "User2 should access their own source");
    
    println!("✅ Own source access verified");
    
    // Test admin access to user sources
    let admin_access_user1_source = client.try_access_source(UserType::Admin, user1_source_id).await
        .expect("Failed to test admin access to User1 source");
    
    let admin_access_user2_source = client.try_access_source(UserType::Admin, user2_source_id).await
        .expect("Failed to test admin access to User2 source");
    
    println!("ℹ️  Admin access to User1 source: {}", admin_access_user1_source);
    println!("ℹ️  Admin access to User2 source: {}", admin_access_user2_source);
    
    println!("🎉 Source ownership isolation test passed!");
}

#[tokio::test]
async fn test_admin_only_operations() {
    println!("👨‍💼 Testing admin-only operations...");
    
    let mut client = RBACTestClient::new();
    client.setup_all_users().await
        .expect("Failed to setup test users");
    
    println!("✅ Setup complete: admin, user1, user2");
    
    let admin_operations = vec![
        AdminOperation::ListUsers,
        AdminOperation::CreateUser,
        AdminOperation::GetMetrics,
        AdminOperation::GetQueueStats,
        AdminOperation::RequeueFailedJobs,
    ];
    
    for operation in admin_operations {
        let operation_name = match operation {
            AdminOperation::ListUsers => "List Users",
            AdminOperation::CreateUser => "Create User",
            AdminOperation::GetMetrics => "Get Metrics",
            AdminOperation::GetQueueStats => "Get Queue Stats",
            AdminOperation::RequeueFailedJobs => "Requeue Failed Jobs",
        };
        
        println!("🔍 Testing operation: {}", operation_name);
        
        // Test admin access
        let admin_result = client.try_admin_operation(UserType::Admin, operation).await
            .expect("Failed to test admin operation as admin");
        
        // Test regular user access
        let user1_result = client.try_admin_operation(UserType::User1, operation).await
            .expect("Failed to test admin operation as user1");
        
        let user2_result = client.try_admin_operation(UserType::User2, operation).await
            .expect("Failed to test admin operation as user2");
        
        println!("  Admin access: {}", admin_result);
        println!("  User1 access: {}", user1_result);
        println!("  User2 access: {}", user2_result);
        
        // Admin should have access (or at least not be forbidden due to role)
        // Regular users should be denied (401 Unauthorized or 403 Forbidden)
        if user1_result.is_success() || user2_result.is_success() {
            println!("⚠️  WARNING: Regular users have access to admin operation: {}", operation_name);
        } else {
            println!("✅ Regular users properly denied access to: {}", operation_name);
        }
        
        // Users should get 401 (Unauthorized) or 403 (Forbidden)
        assert!(
            user1_result == reqwest::StatusCode::UNAUTHORIZED || 
            user1_result == reqwest::StatusCode::FORBIDDEN,
            "User1 should be denied access to {}", operation_name
        );
        
        assert!(
            user2_result == reqwest::StatusCode::UNAUTHORIZED || 
            user2_result == reqwest::StatusCode::FORBIDDEN,
            "User2 should be denied access to {}", operation_name
        );
    }
    
    println!("🎉 Admin-only operations test passed!");
}

#[tokio::test]
async fn test_privilege_escalation_prevention() {
    println!("🔐 Testing privilege escalation prevention...");
    
    let mut client = RBACTestClient::new();
    client.setup_all_users().await
        .expect("Failed to setup test users");
    
    println!("✅ Setup complete: admin, user1, user2");
    
    // Get user IDs for testing
    let user1_id = client.user1_user_id.as_ref().expect("User1 ID should be set");
    let user2_id = client.user2_user_id.as_ref().expect("User2 ID should be set");
    let admin_id = client.admin_user_id.as_ref().expect("Admin ID should be set");
    
    // Test 1: Regular user trying to modify another user
    println!("🔍 Testing user1 trying to modify user2...");
    
    let user1_modify_user2 = client.try_modify_user_resource(UserType::User1, user2_id).await
        .expect("Failed to test user1 modifying user2");
    
    assert!(
        user1_modify_user2 == reqwest::StatusCode::UNAUTHORIZED || 
        user1_modify_user2 == reqwest::StatusCode::FORBIDDEN ||
        user1_modify_user2 == reqwest::StatusCode::NOT_FOUND,
        "User1 should not be able to modify User2"
    );
    
    println!("✅ User1 cannot modify User2: {}", user1_modify_user2);
    
    // Test 2: Regular user trying to modify admin
    println!("🔍 Testing user1 trying to modify admin...");
    
    let user1_modify_admin = client.try_modify_user_resource(UserType::User1, admin_id).await
        .expect("Failed to test user1 modifying admin");
    
    assert!(
        user1_modify_admin == reqwest::StatusCode::UNAUTHORIZED || 
        user1_modify_admin == reqwest::StatusCode::FORBIDDEN ||
        user1_modify_admin == reqwest::StatusCode::NOT_FOUND,
        "User1 should not be able to modify Admin"
    );
    
    println!("✅ User1 cannot modify Admin: {}", user1_modify_admin);
    
    // Test 3: Admin can modify users (should succeed)
    println!("🔍 Testing admin modifying user1...");
    
    let admin_modify_user1 = client.try_modify_user_resource(UserType::Admin, user1_id).await
        .expect("Failed to test admin modifying user1");
    
    // Admin should have permission (200 OK or similar success)
    println!("ℹ️  Admin modifying User1: {}", admin_modify_user1);
    
    // Test 4: Try to create admin user as regular user
    println!("🔍 Testing regular user trying to create admin user...");
    
    let user1_token = client.user1_token.as_ref().unwrap();
    let create_admin_attempt = client.client
        .post(&format!("{}/api/users", get_base_url()))
        .header("Authorization", format!("Bearer {}", user1_token))
        .json(&json!({
            "username": "malicious_admin",
            "email": "malicious@example.com",
            "password": "password123",
            "role": "admin"  // Trying to create admin user
        }))
        .send()
        .await
        .expect("Create admin attempt should complete");
    
    assert!(
        !create_admin_attempt.status().is_success(),
        "Regular user should not be able to create admin users"
    );
    
    println!("✅ User1 cannot create admin user: {}", create_admin_attempt.status());
    
    // Test 5: Try to promote self to admin
    println!("🔍 Testing self-promotion attempt...");
    
    // This would typically be done through updating own user profile
    // The exact endpoint depends on the API design
    let self_promotion_attempt = client.client
        .put(&format!("{}/api/users/{}", get_base_url(), user1_id))
        .header("Authorization", format!("Bearer {}", user1_token))
        .json(&json!({
            "username": "user1_promoted",
            "email": "user1@example.com",
            "role": "admin"  // Trying to promote self
        }))
        .send()
        .await
        .expect("Self promotion attempt should complete");
    
    assert!(
        !self_promotion_attempt.status().is_success(),
        "User should not be able to promote themselves to admin"
    );
    
    println!("✅ User1 cannot promote self: {}", self_promotion_attempt.status());
    
    println!("🎉 Privilege escalation prevention test passed!");
}

#[tokio::test]
async fn test_data_visibility_boundaries() {
    println!("👁️ Testing data visibility boundaries...");
    
    let mut client = RBACTestClient::new();
    client.setup_all_users().await
        .expect("Failed to setup test users");
    
    println!("✅ Setup complete: admin, user1, user2");
    
    // Create data for each user
    let user1_doc = client.upload_document_as_user(
        UserType::User1,
        "User1 confidential data",
        "user1_confidential.txt"
    ).await.expect("Failed to upload User1 document");
    
    let user2_doc = client.upload_document_as_user(
        UserType::User2,
        "User2 confidential data", 
        "user2_confidential.txt"
    ).await.expect("Failed to upload User2 document");
    
    let user1_source = client.create_source_as_user(UserType::User1, "User1 Confidential Source").await
        .expect("Failed to create User1 source");
    
    let user2_source = client.create_source_as_user(UserType::User2, "User2 Confidential Source").await
        .expect("Failed to create User2 source");
    
    println!("✅ Created test data for both users");
    
    // Test document visibility
    let user1_docs = client.get_documents_as_user(UserType::User1).await
        .expect("Failed to get User1 documents");
    
    let user2_docs = client.get_documents_as_user(UserType::User2).await
        .expect("Failed to get User2 documents");
    
    // Verify isolation
    let user1_doc_id = user1_doc["id"].as_str().unwrap();
    let user2_doc_id = user2_doc["id"].as_str().unwrap();
    
    let user1_sees_only_own = user1_docs.iter().all(|d| {
        // Check if this document belongs to user1 by checking if it's the one they uploaded
        // or by checking user association if available in the response
        d["id"] == user1_doc_id || 
        d.get("user_id").and_then(|uid| uid.as_str()) == client.user1_user_id.as_deref()
    });
    
    let user2_sees_only_own = user2_docs.iter().all(|d| {
        d["id"] == user2_doc_id || 
        d.get("user_id").and_then(|uid| uid.as_str()) == client.user2_user_id.as_deref()
    });
    
    assert!(user1_sees_only_own, "User1 should only see their own documents");
    assert!(user2_sees_only_own, "User2 should only see their own documents");
    
    println!("✅ Document visibility boundaries verified");
    
    // Test search isolation (if available)
    let search_response = client.client
        .get(&format!("{}/api/search", get_base_url()))
        .header("Authorization", format!("Bearer {}", client.user1_token.as_ref().unwrap()))
        .query(&[("query", "confidential")])
        .send()
        .await;
    
    if let Ok(response) = search_response {
        let status = response.status();
        if let Ok(user1_search) = response.json::<Value>().await {
            if let Some(results) = user1_search["documents"].as_array() {
                let user1_search_sees_user2 = results.iter().any(|doc| {
                    doc["id"] == user2_doc_id
                });
                
                assert!(!user1_search_sees_user2, "User1 search should not return User2 documents");
                println!("✅ Search isolation verified");
            }
        }
    }
    
    // Test that users cannot enumerate other users' resources through API exploration
    println!("🔍 Testing API enumeration prevention...");
    
    // Try to access source with incremental IDs (if predictable)
    let user1_source_id = user1_source["id"].as_str().unwrap();
    let user2_source_id = user2_source["id"].as_str().unwrap();
    
    // User1 tries to access User2's source
    let cross_access_result = client.try_access_source(UserType::User1, user2_source_id).await
        .expect("Failed to test cross-source access");
    
    assert!(!cross_access_result.is_success(), "Cross-user source access should be denied");
    
    // Try with non-existent but valid UUID format
    let fake_id = Uuid::new_v4().to_string();
    let fake_access_result = client.try_access_source(UserType::User1, &fake_id).await
        .expect("Failed to test fake source access");
    
    // Should return 404 Not Found, not 403 Forbidden (to avoid information leakage)
    assert_eq!(fake_access_result, reqwest::StatusCode::NOT_FOUND, "Non-existent resource should return 404");
    
    println!("✅ API enumeration prevention verified");
    
    println!("🎉 Data visibility boundaries test passed!");
}

#[tokio::test]
async fn test_token_and_session_security() {
    println!("🎫 Testing token and session security...");
    
    let mut client = RBACTestClient::new();
    client.setup_all_users().await
        .expect("Failed to setup test users");
    
    println!("✅ Setup complete: admin, user1, user2");
    
    // Test 1: Invalid token format
    println!("🔍 Testing invalid token formats...");
    
    let invalid_tokens = vec![
        "invalid-token",
        "Bearer invalid-token",
        "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.invalid.signature",
        "",
        "null",
        "undefined",
    ];
    
    for invalid_token in invalid_tokens {
        let response = client.client
            .get(&format!("{}/api/documents", get_base_url()))
            .header("Authorization", format!("Bearer {}", invalid_token))
            .send()
            .await
            .expect("Invalid token request should complete");
        
        assert_eq!(response.status(), reqwest::StatusCode::UNAUTHORIZED, 
                  "Invalid token '{}' should return 401", invalid_token);
    }
    
    println!("✅ Invalid tokens properly rejected");
    
    // Test 2: Token for one user accessing another user's resources
    println!("🔍 Testing token cross-contamination...");
    
    let _user1_token = client.user1_token.as_ref().unwrap();
    let user2_token = client.user2_token.as_ref().unwrap();
    
    // Upload documents with each user
    let user1_doc = client.upload_document_as_user(
        UserType::User1,
        "User1 token test doc",
        "user1_token_test.txt"
    ).await.expect("Failed to upload User1 doc");
    
    let user1_doc_id = user1_doc["id"].as_str().unwrap();
    
    // Try to access User1's document with User2's token
    let cross_token_access = client.client
        .get(&format!("{}/api/documents/{}/ocr", get_base_url(), user1_doc_id))
        .header("Authorization", format!("Bearer {}", user2_token))
        .send()
        .await
        .expect("Cross-token access should complete");
    
    assert!(!cross_token_access.status().is_success(), 
           "User2 token should not access User1 document");
    
    println!("✅ Token cross-contamination prevention verified");
    
    // Test 3: Expired/revoked token simulation
    println!("🔍 Testing token revocation scenarios...");
    
    // This test would require actual token expiration or revocation mechanisms
    // For now, we test that a completely invalid token structure is rejected
    let malformed_jwt = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.malformed_signature";
    
    let malformed_response = client.client
        .get(&format!("{}/api/documents", get_base_url()))
        .header("Authorization", format!("Bearer {}", malformed_jwt))
        .send()
        .await
        .expect("Malformed JWT request should complete");
    
    assert_eq!(malformed_response.status(), reqwest::StatusCode::UNAUTHORIZED,
              "Malformed JWT should be rejected");
    
    println!("✅ Malformed JWT properly rejected");
    
    // Test 4: Missing Authorization header
    println!("🔍 Testing missing authorization...");
    
    let no_auth_response = client.client
        .get(&format!("{}/api/documents", get_base_url()))
        .send()
        .await
        .expect("No auth request should complete");
    
    assert_eq!(no_auth_response.status(), reqwest::StatusCode::UNAUTHORIZED,
              "Missing authorization should return 401");
    
    println!("✅ Missing authorization properly handled");
    
    println!("🎉 Token and session security test passed!");
}