// form_request_tests3.rs - Comprehensive and Robust Testing

// ========================================================================
// STEEL SCRIPT VALIDATION TESTS (HIGHEST PRIORITY)
// ========================================================================

#[rstest]
#[tokio::test]
async fn test_steel_script_validation_success(#[future] form_test_context: FormTestContext) {
    let mut context = form_test_context.await;
    skip_if_backend_unavailable!();

    // Test with data that should pass script validation
    // Assuming there's a script that validates 'kz' field to start with "KZ" and be 5 chars
    let mut valid_data = HashMap::new();
    valid_data.insert("firma".to_string(), create_string_value("Script Test Company"));
    valid_data.insert("kz".to_string(), create_string_value("KZ123"));
    valid_data.insert("telefon".to_string(), create_string_value("+421123456789"));

    let result = context.client.post_table_data(
        context.profile_name.clone(),
        context.table_name.clone(),
        valid_data,
    ).await;

    match result {
        Ok(response) => {
            assert!(response.success, "Valid data should pass script validation");
            println!("Script Validation Test: Valid data passed - ID {}", response.inserted_id);
        }
        Err(e) => {
            if let Some(status) = e.downcast_ref::<Status>() {
                if status.code() == tonic::Code::Unavailable {
                    println!("Script validation test skipped - backend not available");
                    return;
                }
                // If there are no scripts configured, this might still work
                println!("Script validation test: {}", status.message());
            }
        }
    }
}

#[rstest]
#[tokio::test]
async fn test_steel_script_validation_failure(#[future] form_test_context: FormTestContext) {
    let mut context = form_test_context.await;
    skip_if_backend_unavailable!();

    // Test with data that should fail script validation
    let invalid_script_data = vec![
        ("TooShort", "KZ12"),         // Too short
        ("TooLong", "KZ12345"),       // Too long  
        ("WrongPrefix", "AB123"),     // Wrong prefix
        ("NoPrefix", "12345"),        // No prefix
        ("Empty", ""),                // Empty
    ];

    for (test_case, invalid_kz) in invalid_script_data {
        let mut invalid_data = HashMap::new();
        invalid_data.insert("firma".to_string(), create_string_value("Script Fail Company"));
        invalid_data.insert("kz".to_string(), create_string_value(invalid_kz));

        let result = context.client.post_table_data(
            context.profile_name.clone(),
            context.table_name.clone(),
            invalid_data,
        ).await;

        match result {
            Ok(_) => {
                println!("Script Validation Test: {} passed (no validation script configured)", test_case);
            }
            Err(e) => {
                if let Some(status) = e.downcast_ref::<Status>() {
                    assert_eq!(status.code(), tonic::Code::InvalidArgument, 
                              "Script validation failure should return InvalidArgument for case: {}", test_case);
                    println!("Script Validation Test: {} correctly failed - {}", test_case, status.message());
                }
            }
        }
    }
}

#[rstest]
#[tokio::test]
async fn test_steel_script_validation_on_update(#[future] form_test_context: FormTestContext) {
    let mut context = form_test_context.await;
    skip_if_backend_unavailable!();

    // 1. Create a valid record first
    let mut initial_data = HashMap::new();
    initial_data.insert("firma".to_string(), create_string_value("Update Script Test"));
    initial_data.insert("kz".to_string(), create_string_value("KZ123"));

    let post_result = context.client.post_table_data(
        context.profile_name.clone(),
        context.table_name.clone(),
        initial_data,
    ).await;

    if let Ok(post_response) = post_result {
        let record_id = post_response.inserted_id;

        // 2. Try to update with invalid data
        let mut invalid_update = HashMap::new();
        invalid_update.insert("kz".to_string(), create_string_value("INVALID"));

        let update_result = context.client.put_table_data(
            context.profile_name.clone(),
            context.table_name.clone(),
            record_id,
            invalid_update,
        ).await;

        match update_result {
            Ok(_) => {
                println!("Script Validation on Update: No validation script configured for updates");
            }
            Err(e) => {
                if let Some(status) = e.downcast_ref::<Status>() {
                    assert_eq!(status.code(), tonic::Code::InvalidArgument,
                              "Update with invalid data should fail script validation");
                    println!("Script Validation on Update: Correctly rejected invalid update");
                }
            }
        }
    }
}

// ========================================================================
// COMPREHENSIVE DATA TYPE TESTS
// ========================================================================

#[rstest]
#[tokio::test]
async fn test_boolean_data_type(#[future] form_test_context: FormTestContext) {
    let mut context = form_test_context.await;
    skip_if_backend_unavailable!();

    // Test valid boolean values
    let boolean_test_cases = vec![
        ("true", true),
        ("false", false),
    ];

    for (case_name, bool_value) in boolean_test_cases {
        let mut data = HashMap::new();
        data.insert("firma".to_string(), create_string_value("Boolean Test Company"));
        // Assuming there's a boolean field called 'active' 
        data.insert("active".to_string(), create_bool_value(bool_value));

        let result = context.client.post_table_data(
            context.profile_name.clone(),
            context.table_name.clone(),
            data,
        ).await;

        match result {
            Ok(response) => {
                println!("Boolean Test: {} value succeeded", case_name);
                
                // Verify the value round-trip
                if let Ok(get_response) = context.client.get_table_data(
                    context.profile_name.clone(),
                    context.table_name.clone(),
                    response.inserted_id,
                ).await {
                    if let Some(retrieved_value) = get_response.data.get("active") {
                        println!("Boolean Test: {} round-trip value: {}", case_name, retrieved_value);
                    }
                }
            }
            Err(e) => {
                println!("Boolean Test: {} failed (field may not exist): {}", case_name, e);
            }
        }
    }
}

#[rstest]
#[tokio::test]
async fn test_numeric_data_types(#[future] form_test_context: FormTestContext) {
    let mut context = form_test_context.await;
    skip_if_backend_unavailable!();

    // Test various numeric values
    let numeric_test_cases = vec![
        ("Zero", 0.0),
        ("Positive", 123.45),
        ("Negative", -67.89),
        ("Large", 999999.99),
        ("SmallDecimal", 0.01),
    ];

    for (case_name, numeric_value) in numeric_test_cases {
        let mut data = HashMap::new();
        data.insert("firma".to_string(), create_string_value("Numeric Test Company"));
        // Assuming there's a numeric field called 'price' or 'amount'
        data.insert("amount".to_string(), create_number_value(numeric_value));

        let result = context.client.post_table_data(
            context.profile_name.clone(),
            context.table_name.clone(),
            data,
        ).await;

        match result {
            Ok(response) => {
                println!("Numeric Test: {} ({}) succeeded", case_name, numeric_value);
                
                // Verify round-trip
                if let Ok(get_response) = context.client.get_table_data(
                    context.profile_name.clone(),
                    context.table_name.clone(),
                    response.inserted_id,
                ).await {
                    if let Some(retrieved_value) = get_response.data.get("amount") {
                        println!("Numeric Test: {} round-trip value: {}", case_name, retrieved_value);
                    }
                }
            }
            Err(e) => {
                println!("Numeric Test: {} failed (field may not exist): {}", case_name, e);
            }
        }
    }
}

#[rstest]
#[tokio::test]
async fn test_timestamp_data_type(#[future] form_test_context: FormTestContext) {
    let mut context = form_test_context.await;
    skip_if_backend_unavailable!();

    // Test various timestamp formats
    let timestamp_test_cases = vec![
        ("ISO8601", "2024-01-15T10:30:00Z"),
        ("WithTimezone", "2024-01-15T10:30:00+01:00"),
        ("WithMilliseconds", "2024-01-15T10:30:00.123Z"),
    ];

    for (case_name, timestamp_str) in timestamp_test_cases {
        let mut data = HashMap::new();
        data.insert("firma".to_string(), create_string_value("Timestamp Test Company"));
        // Assuming there's a timestamp field called 'created_at'
        data.insert("created_at".to_string(), create_string_value(timestamp_str));

        let result = context.client.post_table_data(
            context.profile_name.clone(),
            context.table_name.clone(),
            data,
        ).await;

        match result {
            Ok(response) => {
                println!("Timestamp Test: {} succeeded", case_name);
                
                // Verify round-trip
                if let Ok(get_response) = context.client.get_table_data(
                    context.profile_name.clone(),
                    context.table_name.clone(),
                    response.inserted_id,
                ).await {
                    if let Some(retrieved_value) = get_response.data.get("created_at") {
                        println!("Timestamp Test: {} round-trip value: {}", case_name, retrieved_value);
                    }
                }
            }
            Err(e) => {
                println!("Timestamp Test: {} failed (field may not exist): {}", case_name, e);
            }
        }
    }
}

#[rstest]
#[tokio::test]
async fn test_invalid_data_types(#[future] form_test_context: FormTestContext) {
    let mut context = form_test_context.await;
    skip_if_backend_unavailable!();

    // Test invalid data type combinations
    let invalid_type_cases = vec![
        ("StringForNumber", "amount", create_string_value("not-a-number")),
        ("NumberForBoolean", "active", create_number_value(123.0)),
        ("StringForBoolean", "active", create_string_value("maybe")),
        ("InvalidTimestamp", "created_at", create_string_value("not-a-date")),
    ];

    for (case_name, field_name, invalid_value) in invalid_type_cases {
        let mut data = HashMap::new();
        data.insert("firma".to_string(), create_string_value("Invalid Type Test"));
        data.insert(field_name.to_string(), invalid_value);

        let result = context.client.post_table_data(
            context.profile_name.clone(),
            context.table_name.clone(),
            data,
        ).await;

        match result {
            Ok(_) => {
                println!("Invalid Type Test: {} passed (no type validation or field doesn't exist)", case_name);
            }
            Err(e) => {
                if let Some(status) = e.downcast_ref::<Status>() {
                    assert_eq!(status.code(), tonic::Code::InvalidArgument,
                              "Invalid data type should return InvalidArgument for case: {}", case_name);
                    println!("Invalid Type Test: {} correctly rejected - {}", case_name, status.message());
                }
            }
        }
    }
}

// ========================================================================
// FOREIGN KEY RELATIONSHIP TESTS
// ========================================================================

#[rstest]
#[tokio::test]
async fn test_foreign_key_valid_relationship(#[future] form_test_context: FormTestContext) {
    let mut context = form_test_context.await;
    skip_if_backend_unavailable!();

    // 1. Create a parent record first (e.g., company)
    let mut parent_data = HashMap::new();
    parent_data.insert("firma".to_string(), create_string_value("Parent Company"));

    let parent_result = context.client.post_table_data(
        context.profile_name.clone(),
        "companies".to_string(), // Assuming companies table exists
        parent_data,
    ).await;

    if let Ok(parent_response) = parent_result {
        let parent_id = parent_response.inserted_id;

        // 2. Create a child record that references the parent
        let mut child_data = HashMap::new();
        child_data.insert("name".to_string(), create_string_value("Child Record"));
        child_data.insert("company_id".to_string(), create_number_value(parent_id as f64));

        let child_result = context.client.post_table_data(
            context.profile_name.clone(),
            "contacts".to_string(), // Assuming contacts table exists
            child_data,
        ).await;

        match child_result {
            Ok(child_response) => {
                assert!(child_response.success, "Valid foreign key relationship should succeed");
                println!("Foreign Key Test: Valid relationship created - Parent ID: {}, Child ID: {}", 
                        parent_id, child_response.inserted_id);
            }
            Err(e) => {
                println!("Foreign Key Test: Failed (tables may not exist or no FK constraint): {}", e);
            }
        }
    } else {
        println!("Foreign Key Test: Could not create parent record");
    }
}

#[rstest]
#[tokio::test]
async fn test_foreign_key_invalid_relationship(#[future] form_test_context: FormTestContext) {
    let mut context = form_test_context.await;
    skip_if_backend_unavailable!();

    // Try to create a child record with non-existent parent ID
    let mut invalid_child_data = HashMap::new();
    invalid_child_data.insert("name".to_string(), create_string_value("Orphan Record"));
    invalid_child_data.insert("company_id".to_string(), create_number_value(99999.0)); // Non-existent ID

    let result = context.client.post_table_data(
        context.profile_name.clone(),
        "contacts".to_string(),
        invalid_child_data,
    ).await;

    match result {
        Ok(_) => {
            println!("Foreign Key Test: Invalid relationship passed (no FK constraint configured)");
        }
        Err(e) => {
            if let Some(status) = e.downcast_ref::<Status>() {
                // Could be InvalidArgument or NotFound depending on implementation
                assert!(matches!(status.code(), tonic::Code::InvalidArgument | tonic::Code::NotFound),
                       "Invalid foreign key should return InvalidArgument or NotFound");
                println!("Foreign Key Test: Invalid relationship correctly rejected - {}", status.message());
            }
        }
    }
}

// ========================================================================
// DELETED RECORD INTERACTION TESTS
// ========================================================================

#[rstest]
#[tokio::test]
async fn test_update_deleted_record_behavior(#[future] form_test_context: FormTestContext) {
    let mut context = form_test_context.await;
    skip_if_backend_unavailable!();

    // 1. Create a record
    let initial_data = context.create_test_form_data();
    let post_result = context.client.post_table_data(
        context.profile_name.clone(),
        context.table_name.clone(),
        initial_data,
    ).await;

    if let Ok(post_response) = post_result {
        let record_id = post_response.inserted_id;
        println!("Deleted Record Test: Created record ID {}", record_id);

        // 2. Delete the record (soft delete)
        let delete_result = context.client.delete_table_data(
            context.profile_name.clone(),
            context.table_name.clone(),
            record_id,
        ).await;

        assert!(delete_result.is_ok(), "Delete should succeed");
        println!("Deleted Record Test: Soft-deleted record {}", record_id);

        // 3. Try to UPDATE the deleted record
        let mut update_data = HashMap::new();
        update_data.insert("firma".to_string(), create_string_value("Updated Deleted Record"));

        let update_result = context.client.put_table_data(
            context.profile_name.clone(),
            context.table_name.clone(),
            record_id,
            update_data,
        ).await;

        match update_result {
            Ok(_) => {
                // This might be a bug - updating deleted records should probably fail
                println!("Deleted Record Test: UPDATE on deleted record succeeded (potential bug?)");
                
                // Check if the record is still considered deleted
                let get_result = context.client.get_table_data(
                    context.profile_name.clone(),
                    context.table_name.clone(),
                    record_id,
                ).await;
                
                if get_result.is_err() {
                    println!("Deleted Record Test: Record still appears deleted after update");
                } else {
                    println!("Deleted Record Test: Record appears to be undeleted after update");
                }
            }
            Err(e) => {
                if let Some(status) = e.downcast_ref::<Status>() {
                    assert_eq!(status.code(), tonic::Code::NotFound,
                              "UPDATE on deleted record should return NotFound");
                    println!("Deleted Record Test: UPDATE correctly rejected on deleted record");
                }
            }
        }
    }
}

#[rstest]
#[tokio::test]
async fn test_delete_already_deleted_record(#[future] form_test_context: FormTestContext) {
    let mut context = form_test_context.await;
    skip_if_backend_unavailable!();

    // 1. Create and delete a record
    let initial_data = context.create_test_form_data();
    let post_result = context.client.post_table_data(
        context.profile_name.clone(),
        context.table_name.clone(),
        initial_data,
    ).await;

    if let Ok(post_response) = post_result {
        let record_id = post_response.inserted_id;

        // First deletion
        let delete_result1 = context.client.delete_table_data(
            context.profile_name.clone(),
            context.table_name.clone(),
            record_id,
        ).await;
        assert!(delete_result1.is_ok(), "First delete should succeed");

        // Second deletion (idempotent)
        let delete_result2 = context.client.delete_table_data(
            context.profile_name.clone(),
            context.table_name.clone(),
            record_id,
        ).await;

        assert!(delete_result2.is_ok(), "Second delete should succeed (idempotent)");
        if let Ok(response) = delete_result2 {
            assert!(response.success, "Delete should report success even for already-deleted record");
        }
        println!("Double Delete Test: Both deletions succeeded (idempotent behavior)");
    }
}

// ========================================================================
// VALIDATION AND BOUNDARY TESTS
// ========================================================================

#[rstest]
#[tokio::test]
async fn test_large_data_handling(#[future] form_test_context: FormTestContext) {
    let mut context = form_test_context.await;
    skip_if_backend_unavailable!();

    // Test with very large string values
    let large_string = "A".repeat(10000); // 10KB string
    let very_large_string = "B".repeat(100000); // 100KB string

    let test_cases = vec![
        ("Large", large_string),
        ("VeryLarge", very_large_string),
    ];

    for (case_name, large_value) in test_cases {
        let mut data = HashMap::new();
        data.insert("firma".to_string(), create_string_value(&large_value));

        let result = context.client.post_table_data(
            context.profile_name.clone(),
            context.table_name.clone(),
            data,
        ).await;

        match result {
            Ok(response) => {
                println!("Large Data Test: {} string handled successfully", case_name);
                
                // Verify round-trip
                if let Ok(get_response) = context.client.get_table_data(
                    context.profile_name.clone(),
                    context.table_name.clone(),
                    response.inserted_id,
                ).await {
                    if let Some(retrieved_value) = get_response.data.get("firma") {
                        assert_eq!(retrieved_value.len(), large_value.len(),
                                  "Large string should survive round-trip for case: {}", case_name);
                    }
                }
            }
            Err(e) => {
                println!("Large Data Test: {} failed (may hit size limits): {}", case_name, e);
            }
        }
    }
}

#[rstest]
#[tokio::test]
async fn test_sql_injection_attempts(#[future] form_test_context: FormTestContext) {
    let mut context = form_test_context.await;
    skip_if_backend_unavailable!();

    // Test potential SQL injection strings
    let injection_attempts = vec![
        ("SingleQuote", "'; DROP TABLE users; --"),
        ("DoubleQuote", "\"; DROP TABLE users; --"),
        ("Union", "' UNION SELECT * FROM users --"),
        ("Comment", "/* malicious comment */"),
        ("Semicolon", "; DELETE FROM users;"),
    ];

    for (case_name, injection_string) in injection_attempts {
        let mut data = HashMap::new();
        data.insert("firma".to_string(), create_string_value(injection_string));
        data.insert("kz".to_string(), create_string_value("KZ123"));

        let result = context.client.post_table_data(
            context.profile_name.clone(),
            context.table_name.clone(),
            data,
        ).await;

        match result {
            Ok(response) => {
                println!("SQL Injection Test: {} handled safely (parameterized queries)", case_name);
                
                // Verify the malicious string was stored as-is (not executed)
                if let Ok(get_response) = context.client.get_table_data(
                    context.profile_name.clone(),
                    context.table_name.clone(),
                    response.inserted_id,
                ).await {
                    if let Some(retrieved_value) = get_response.data.get("firma") {
                        assert_eq!(retrieved_value, injection_string,
                                  "Injection string should be stored literally for case: {}", case_name);
                    }
                }
            }
            Err(e) => {
                println!("SQL Injection Test: {} rejected: {}", case_name, e);
            }
        }
    }
}

#[rstest]
#[tokio::test]
async fn test_concurrent_operations_with_same_data(#[future] form_test_context: FormTestContext) {
    let context = form_test_context.await;
    skip_if_backend_unavailable!();

    // Test multiple concurrent operations with identical data
    let mut handles = Vec::new();
    let num_tasks = 10;

    for i in 0..num_tasks {
        let mut context_clone = context.clone();
        let handle = tokio::spawn(async move {
            let mut data = HashMap::new();
            data.insert("firma".to_string(), create_string_value("Concurrent Identical"));
            data.insert("kz".to_string(), create_string_value(&format!("SAME{:02}", i)));
            
            context_clone.client.post_table_data(
                context_clone.profile_name,
                context_clone.table_name,
                data,
            ).await
        });
        handles.push(handle);
    }

    // Wait for all to complete
    let mut success_count = 0;
    let mut inserted_ids = Vec::new();

    for (i, handle) in handles.into_iter().enumerate() {
        match handle.await {
            Ok(Ok(response)) => {
                success_count += 1;
                inserted_ids.push(response.inserted_id);
                println!("Concurrent Identical Data: Task {} succeeded with ID {}", i, response.inserted_id);
            }
            Ok(Err(e)) => {
                println!("Concurrent Identical Data: Task {} failed: {}", i, e);
            }
            Err(e) => {
                println!("Concurrent Identical Data: Task {} panicked: {}", i, e);
            }
        }
    }

    assert!(success_count > 0, "At least some concurrent operations should succeed");
    
    // Verify all IDs are unique
    let unique_ids: std::collections::HashSet<_> = inserted_ids.iter().collect();
    assert_eq!(unique_ids.len(), inserted_ids.len(), "All inserted IDs should be unique");
    
    println!("Concurrent Identical Data: {}/{} operations succeeded with unique IDs", 
             success_count, num_tasks);
}

// ========================================================================
// PERFORMANCE AND STRESS TESTS
// ========================================================================

#[rstest]
#[tokio::test]
async fn test_bulk_operations_performance(#[future] form_test_context: FormTestContext) {
    let mut context = form_test_context.await;
    skip_if_backend_unavailable!();

    let operation_count = 50;
    let start_time = std::time::Instant::now();
    
    let mut successful_operations = 0;
    let mut created_ids = Vec::new();

    // Bulk create
    for i in 0..operation_count {
        let mut data = HashMap::new();
        data.insert("firma".to_string(), create_string_value(&format!("Bulk Company {}", i)));
        data.insert("kz".to_string(), create_string_value(&format!("BLK{:02}", i)));

        if let Ok(response) = context.client.post_table_data(
            context.profile_name.clone(),
            context.table_name.clone(),
            data,
        ).await {
            successful_operations += 1;
            created_ids.push(response.inserted_id);
        }
    }

    let create_duration = start_time.elapsed();
    println!("Bulk Performance: Created {} records in {:?}", successful_operations, create_duration);

    // Bulk read
    let read_start = std::time::Instant::now();
    let mut successful_reads = 0;

    for &record_id in &created_ids {
        if context.client.get_table_data(
            context.profile_name.clone(),
            context.table_name.clone(),
            record_id,
        ).await.is_ok() {
            successful_reads += 1;
        }
    }

    let read_duration = read_start.elapsed();
    println!("Bulk Performance: Read {} records in {:?}", successful_reads, read_duration);

    // Performance assertions
    assert!(successful_operations > operation_count * 8 / 10, 
           "At least 80% of operations should succeed");
    assert!(create_duration.as_secs() < 60, 
           "Bulk operations should complete in reasonable time");

    println!("Bulk Performance Test: {}/{} creates, {}/{} reads successful", 
             successful_operations, operation_count, successful_reads, created_ids.len());
}
