// tests/table_definition/post_table_definition_test4.rs

// NOTE: All 'use' statements are inherited from the parent file that includes this one.

// ========= Category 5: Implementation-Specific Edge Cases =========

#[rstest]
#[tokio::test]
async fn test_fail_on_fk_base_name_collision(#[future] pool: PgPool) {
    // Scenario: Link to two tables (`team1_users`, `team2_users`) that use full table names
    // for FK columns, so no collision occurs - this should succeed.
    let pool = pool.await;

    // Arrange: Create the two prerequisite tables
    let req1 = PostTableDefinitionRequest {
        profile_name: "default".into(),
        table_name: "team1_users".into(),
        ..Default::default()
    };
    post_table_definition(&pool, req1).await.unwrap();

    let req2 = PostTableDefinitionRequest {
        profile_name: "default".into(),
        table_name: "team2_users".into(),
        ..Default::default()
    };
    post_table_definition(&pool, req2).await.unwrap();

    // Arrange: A request that links to both - should succeed with full table names
    let linking_req = PostTableDefinitionRequest {
        profile_name: "default".into(),
        table_name: "tasks".into(),
        links: vec![
            TableLink {
                linked_table_name: "team1_users".into(),
                required: true,
            },
            TableLink {
                linked_table_name: "team2_users".into(),
                required: false,
            },
        ],
        ..Default::default()
    };

    // Act
    let result = post_table_definition(&pool, linking_req).await;

    // Assert - should succeed
    let response = result.unwrap();
    assert!(response.success);

    // Verify the SQL contains both full table name FK columns
    assert!(response.sql.contains("\"team1_users_id\""),
           "SQL should contain team1_users_id column");
    assert!(response.sql.contains("\"team2_users_id\""),
           "SQL should contain team2_users_id column");

    // Verify the references are correct
    assert!(response.sql.contains("REFERENCES \"default\".\"team1_users\"(id)"));
    assert!(response.sql.contains("REFERENCES \"default\".\"team2_users\"(id)"));

    // Verify one is NOT NULL and one is nullable
    assert!(response.sql.contains("\"team1_users_id\" BIGINT NOT NULL"));
    assert!(response.sql.contains("\"team2_users_id\" BIGINT  REFERENCES"));
}

#[rstest]
#[tokio::test]
async fn test_sql_reserved_keywords_as_identifiers_are_allowed(#[future] pool: PgPool) {
    // NOTE: This test confirms that the system currently allows SQL reserved keywords
    // as column names because they are correctly quoted. This is technically correct,
    // but some systems add validation to block this as a policy to prevent user confusion.
    let pool = pool.await;
    let keywords = vec!["user", "select", "group", "order"];

    for (i, keyword) in keywords.into_iter().enumerate() {
        let table_name = format!("keyword_test_{}", i);
        let request = PostTableDefinitionRequest {
            profile_name: "default".into(),
            table_name: table_name.clone(),
            columns: vec![ColumnDefinition {
                name: keyword.into(),
                field_type: "text".into(),
            }],
            ..Default::default()
        };

        // Act & Assert
        let response = post_table_definition(&pool, request)
            .await
            .unwrap_or_else(|e| {
                panic!(
                    "Failed to create table with reserved keyword '{}': {:?}",
                    keyword, e
                )
            });

        assert!(response.success);
        assert!(response.sql.contains(&format!("\"{}\" TEXT", keyword)));

        // FIXED: Added schema parameter
        assert_table_structure_is_correct(&pool, "default", &table_name, &[(keyword, "text")]).await;
    }
}

// ========= Category 6: Environmental and Extreme Edge Cases =========

#[rstest]
#[tokio::test]
async fn test_sanitization_of_unicode_and_special_chars(#[future] pool: PgPool) {
    let pool = pool.await;
    let request = PostTableDefinitionRequest {
        profile_name: "default".into(),
        table_name: "produits_😂".into(), // Invalid unicode
        columns: vec![ColumnDefinition {
            name: "col_with_unicode".into(),
            field_type: "text".into(),
        }],
        ..Default::default()
    };

    // FIXED: Now expect error instead of success
    let result = post_table_definition(&pool, request).await;
    assert!(result.is_err());
    if let Err(status) = result {
        assert!(status.message().contains("Table name contains invalid characters"));
    }
}

#[rstest]
#[tokio::test]
async fn test_fail_gracefully_if_schema_is_missing(#[future] pool: PgPool) {
    // Scenario: The handler relies on schemas existing. This test ensures
    // it fails gracefully if the schema creation fails.
    let pool = pool.await;

    // Arrange: Try to create a table with an invalid schema name that would cause issues
    let request = PostTableDefinitionRequest {
        profile_name: "invalid-schema-name!@#".into(), // This should be sanitized and potentially cause issues
        table_name: "this_will_fail".into(),
        ..Default::default()
    };

    // Act
    let result = post_table_definition(&pool, request).await;

    // Assert - This should either succeed with sanitized name or fail gracefully
    match result {
        Ok(_) => {
            // If it succeeds, the sanitization worked
            // This is actually a valid outcome
        },
        Err(err) => {
            // If it fails, it should be a clear error, not a panic
            assert_eq!(err.code(), Code::InvalidArgument);
        }
    }
}

#[rstest]
#[tokio::test]
async fn test_column_name_with_id_suffix_is_rejected(#[future] pool: PgPool) {
    let pool = pool.await;
    let request = PostTableDefinitionRequest {
        profile_name: "default".into(),
        table_name: "orders".into(),
        columns: vec![ColumnDefinition {
            name: "legacy_order_id".into(),
            field_type: "integer".into(),
        }],
        ..Default::default()
    };
    let result = post_table_definition(&pool, request).await;
    assert!(result.is_err(), "Column names ending with '_id' should be rejected");
    if let Err(status) = result {
        assert_eq!(status.code(), tonic::Code::InvalidArgument);
        // UPDATED: Match the new error message format
        assert!(status.message().contains("Column name 'legacy_order_id' cannot be") &&
                status.message().contains("end with '_id'"));
    }
}

#[rstest]
#[tokio::test]
async fn test_table_name_with_id_suffix_is_rejected(#[future] pool: PgPool) {
    // Test that table names ending with '_id' are properly rejected during input validation
    let pool = pool.await;

    let request = PostTableDefinitionRequest {
        profile_name: "default".into(),
        table_name: "orders_id".into(), // This should be rejected
        columns: vec![ColumnDefinition {
            name: "customer_name".into(), // Valid column name
            field_type: "text".into(),
        }],
        ..Default::default()
    };

    // Act & Assert - should fail validation
    let result = post_table_definition(&pool, request).await;
    assert!(result.is_err(), "Table names ending with '_id' should be rejected");
    if let Err(status) = result {
        assert_eq!(status.code(), tonic::Code::InvalidArgument);
        assert!(status.message().contains("Table name cannot be 'id', 'deleted', 'created_at' or end with '_id'"));
    }
}
