// ========================================================================
// ROBUST WORKFLOW AND INTEGRATION TESTS
// ========================================================================

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

    // 1. Create a record with multiple fields
    let mut initial_data = context.create_test_form_data();
    let original_email = "preserve.this@email.com";
    initial_data.insert(
        "email".to_string(),
        create_string_value(original_email),
    );

    let post_res = context
        .client
        .post_table_data(
            context.profile_name.clone(),
            context.table_name.clone(),
            initial_data,
        )
        .await
        .expect("Setup: Failed to create record for partial update test");
    let created_id = post_res.inserted_id;
    println!("Partial Update Test: Created record ID {}", created_id);

    // 2. Update only ONE field
    let mut partial_update = HashMap::new();
    let updated_firma = "Partially Updated Inc.";
    partial_update.insert(
        "firma".to_string(),
        create_string_value(updated_firma),
    );

    context
        .client
        .put_table_data(
            context.profile_name.clone(),
            context.table_name.clone(),
            created_id,
            partial_update,
        )
        .await
        .expect("Partial update failed");
    println!("Partial Update Test: Updated only 'firma' field");

    // 3. Get the record back and verify ALL fields
    let get_res = context
        .client
        .get_table_data(
            context.profile_name.clone(),
            context.table_name.clone(),
            created_id,
        )
        .await
        .expect("Failed to get record after partial update");

    let final_data = get_res.data;
    assert_eq!(
        final_data.get("firma").unwrap(),
        updated_firma,
        "The 'firma' field should be updated"
    );
    assert_eq!(
        final_data.get("email").unwrap(),
        original_email,
        "The 'email' field should have been preserved"
    );
    println!("Partial Update Test: Verified other fields were preserved. OK.");
}

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

    let edge_case_strings = vec![
        ("Unicode", "José María González, Москва, 北京市"),
        ("Emoji", "🚀 Tech Company 🌟"),
        ("Quotes", "Quote\"Test'Apostrophe"),
        ("Symbols", "Price: $1,000.50 (50% off!)"),
        ("Empty", ""),
        ("Whitespace", "   "),
    ];

    for (case_name, test_string) in edge_case_strings {
        let mut data = HashMap::new();
        data.insert("firma".to_string(), create_string_value(test_string));
        data.insert(
            "kz".to_string(),
            create_string_value(&format!("EDGE-{}", case_name)),
        );

        let post_res = context
            .client
            .post_table_data(
                context.profile_name.clone(),
                context.table_name.clone(),
                data,
            )
            .await
            .expect(&format!("POST should succeed for case: {}", case_name));
        let created_id = post_res.inserted_id;

        let get_res = context
            .client
            .get_table_data(
                context.profile_name.clone(),
                context.table_name.clone(),
                created_id,
            )
            .await
            .expect(&format!(
                "GET should succeed for case: {}",
                case_name
            ));

        assert_eq!(
            get_res.data.get("firma").unwrap(),
            test_string,
            "Data should be identical after round-trip for case: {}",
            case_name
        );
        println!("Edge Case Test: '{}' passed.", case_name);
    }
}

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

    // 1. Test NULL value
    let mut null_data = HashMap::new();
    null_data.insert(
        "firma".to_string(),
        create_string_value("Company With Null Phone"),
    );
    null_data.insert("telefon".to_string(), create_null_value());
    let post_res_null = context
        .client
        .post_table_data(
            context.profile_name.clone(),
            context.table_name.clone(),
            null_data,
        )
        .await
        .expect("POST with NULL value should succeed");
    let get_res_null = context
        .client
        .get_table_data(
            context.profile_name.clone(),
            context.table_name.clone(),
            post_res_null.inserted_id,
        )
        .await
        .unwrap();
    // Depending on DB, NULL may come back as empty string or be absent.
    // The important part is that the operation doesn't fail.
    assert!(
        get_res_null.data.get("telefon").unwrap_or(&"".to_string()).is_empty(),
        "NULL value should result in an empty or absent field"
    );
    println!("Edge Case Test: NULL value handled correctly. OK.");

    // 2. Test Zero value for a numeric field (assuming 'age' is numeric)
    let mut zero_data = HashMap::new();
    zero_data.insert(
        "firma".to_string(),
        create_string_value("Newborn Company"),
    );
    // Assuming 'age' is a field in your actual table definition
    // zero_data.insert("age".to_string(), create_number_value(0.0));
    // let post_res_zero = context.client.post_table_data(...).await.expect("POST with zero should succeed");
    // ... then get and verify it's "0"
    println!("Edge Case Test: Zero value test skipped (uncomment if 'age' field exists).");
}

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

    // 1. Create a single record to be updated by all tasks
    let initial_data = context.create_minimal_form_data();
    let post_res = context
        .client
        .post_table_data(
            context.profile_name.clone(),
            context.table_name.clone(),
            initial_data,
        )
        .await
        .expect("Setup: Failed to create record for concurrency test");
    let record_id = post_res.inserted_id;
    println!("Concurrency Test: Target record ID is {}", record_id);

    // 2. Spawn multiple concurrent UPDATE operations
    let mut handles = Vec::new();
    let num_concurrent_tasks = 5;
    let mut final_values = Vec::new();

    for i in 0..num_concurrent_tasks {
        let mut client_clone = context.client.clone();
        let profile_name = context.profile_name.clone();
        let table_name = context.table_name.clone();
        let final_value = format!("Concurrent Update {}", i);
        final_values.push(final_value.clone());

        let handle = tokio::spawn(async move {
            let mut update_data = HashMap::new();
            update_data.insert(
                "firma".to_string(),
                create_string_value(&final_value),
            );
            client_clone
                .put_table_data(profile_name, table_name, record_id, update_data)
                .await
        });
        handles.push(handle);
    }

    // 3. Wait for all tasks to complete and check for panics
    let results = futures::future::join_all(handles).await;
    assert!(
        results.iter().all(|r| r.is_ok()),
        "No concurrent task should panic"
    );
    println!("Concurrency Test: All update tasks completed without panicking.");

    // 4. Get the final state of the record
    let final_get_res = context
        .client
        .get_table_data(
            context.profile_name.clone(),
            context.table_name.clone(),
            record_id,
        )
        .await
        .expect("Should be able to get the record after concurrent updates");

    let final_firma = final_get_res.data.get("firma").unwrap();
    assert!(
        final_values.contains(final_firma),
        "The final state '{}' must be one of the states set by the tasks",
        final_firma
    );
    println!(
        "Concurrency Test: Final state is '{}', which is a valid outcome. OK.",
        final_firma
    );
}
