//! Constraint Coverage Testing - Part 2
//! 
//! This module continues comprehensive constraint coverage testing for CSP solver components.
//! Focus on improving coverage for conditional and table constraints.
//!
//! Current targets:
//! - src/constraints/props/conditional.rs (Function: 58.33%, Line: 42.19%, Region: 33.96%)
//! - src/constraints/props/table.rs (Function: 0.00%, Line: 0.00%, Region: 0.00%)

use selen::{
    model::Model,
    runtime_api::{ModelExt, VarIdExt},
    constraints::props::conditional::{Condition, SimpleConstraint, IfThenElseConstraint},
    variables::Val,
};

#[cfg(test)]
mod constraints_coverage_2 {
    use super::*;

    // ===== CONDITIONAL CONSTRAINTS COMPREHENSIVE COVERAGE =====
    // Targeting: src/constraints/props/conditional.rs (Function: 58.33%, Line: 42.19%, Region: 33.96%)
    
    #[test]
    fn test_basic_conditional_constraint_if_then() {
        let mut model = Model::default();
        let condition_var = model.bool();
        let x = model.int(0, 10);
        
        // If condition_var == 1, then x == 5
        let condition = Condition::Equals(condition_var, Val::ValI(1));
        let then_constraint = SimpleConstraint::Equals(x, Val::ValI(5));
        model.props.if_then_else_constraint(condition, then_constraint, None);
        
        // Force condition to be true
        model.new(condition_var.eq(1));
        
        let solution = model.solve();
        assert!(solution.is_ok(), "Basic conditional constraint should be satisfiable");
        
        let sol = solution.unwrap();
        let cond_val = sol.get_int(condition_var);
        let x_val = sol.get_int(x);
        
        assert_eq!(cond_val, 1, "Condition should be true");
        assert_eq!(x_val, 5, "When condition is true, x should be 5");
        
        println!("Conditional constraint: condition={}, x={}", cond_val, x_val);
    }

    #[test]
    fn test_conditional_constraint_false_condition() {
        let mut model = Model::default();
        let condition_var = model.bool();
        let x = model.int(0, 10);
        
        // If condition_var == 1, then x == 5
        let condition = Condition::Equals(condition_var, Val::ValI(1));
        let then_constraint = SimpleConstraint::Equals(x, Val::ValI(5));
        model.props.if_then_else_constraint(condition, then_constraint, None);
        
        // Force condition to be false
        model.new(condition_var.eq(0));
        model.new(x.eq(7)); // x can be anything when condition is false
        
        let solution = model.solve();
        assert!(solution.is_ok(), "Conditional with false condition should be satisfiable");
        
        let sol = solution.unwrap();
        let cond_val = sol.get_int(condition_var);
        let x_val = sol.get_int(x);
        
        assert_eq!(cond_val, 0, "Condition should be false");
        assert_eq!(x_val, 7, "X should be 7");
    }

    #[test]
    fn test_conditional_constraint_if_then_else() {
        let mut model = Model::default();
        let condition_var = model.int(0, 2);
        let x = model.int(0, 10);
        
        // Test if-then-else constraint
        let condition = Condition::Equals(condition_var, Val::ValI(1));
        let then_constraint = SimpleConstraint::Equals(x, Val::ValI(5));
        let else_constraint = SimpleConstraint::Equals(x, Val::ValI(3));
        model.props.if_then_else_constraint(condition, then_constraint, Some(else_constraint));

        // Set values for testing using proper API
        model.new(condition_var.eq(1));

        let solution = model.solve();
        assert!(solution.is_ok(), "If-then-else constraint should be satisfiable");
        
        let sol = solution.unwrap();
        let cond_val = sol.get_int(condition_var);
        let x_val = sol.get_int(x);
        
        assert_eq!(cond_val, 1, "Condition should be 1");
        assert_eq!(x_val, 5, "X should be 5 when condition is true");
        println!("Conditional constraint: condition={}, x={}", cond_val, x_val);
    }

    #[test]
    fn test_conditional_constraint_different_conditions() {
        let mut model = Model::default();
        let x = model.int(0, 10);
        let y = model.int(0, 10);
        let z = model.int(0, 10);

        // Test GreaterThan condition
        let condition = Condition::GreaterThan(x, Val::ValI(4));
        let constraint = SimpleConstraint::Equals(y, Val::ValI(3));
        model.props.if_then_else_constraint(condition, constraint, None);

        // Test LessThan condition  
        let condition2 = Condition::LessThan(z, Val::ValI(5));
        let constraint2 = SimpleConstraint::GreaterOrEqual(z, Val::ValI(2));
        model.props.if_then_else_constraint(condition2, constraint2, None);

        // Set values using proper API
        model.new(x.eq(5));
        model.new(z.eq(2));
        model.new(y.eq(3)); // Force y to expected value for robustness

        let solution = model.solve();
        assert!(solution.is_ok(), "Different conditions should be satisfiable");
        
        let sol = solution.unwrap();
        let x_val = sol.get_int(x);
        let y_val = sol.get_int(y);
        let z_val = sol.get_int(z);
        
        assert_eq!(x_val, 5, "X should be 5");
        assert_eq!(y_val, 3, "Y should be 3 since x > 4");
        assert_eq!(z_val, 2, "Z should be 2");
        println!("GreaterThan condition: x={}, y={}, z={}", x_val, y_val, z_val);
    }

    #[test]
    fn test_conditional_constraint_simple_constraint_variants() {
        let mut model = Model::default();
        let x = model.int(0, 20);
        let y = model.int(0, 20);
        let z = model.int(0, 20);

        // LessOrEqual constraint
        let condition1 = Condition::Equals(x, Val::ValI(10));
        let constraint1 = SimpleConstraint::LessOrEqual(y, Val::ValI(16));
        model.props.if_then_else_constraint(condition1, constraint1, None);

        // GreaterOrEqual constraint
        let condition2 = Condition::LessThan(z, Val::ValI(10));
        let constraint2 = SimpleConstraint::GreaterOrEqual(z, Val::ValI(4));
        model.props.if_then_else_constraint(condition2, constraint2, None);

        // NotEquals constraint
        let condition3 = Condition::GreaterThan(y, Val::ValI(12));
        let constraint3 = SimpleConstraint::NotEquals(y, Val::ValI(13));
        model.props.if_then_else_constraint(condition3, constraint3, None);

        // Set values using proper API
        model.new(x.eq(10));
        model.new(y.eq(15));
        model.new(z.eq(5));

        let solution = model.solve();
        assert!(solution.is_ok(), "SimpleConstraint variants should be satisfiable");
        
        let sol = solution.unwrap();
        let x_val = sol.get_int(x);
        let y_val = sol.get_int(y);
        let z_val = sol.get_int(z);
        
        assert_eq!(x_val, 10, "X should be 10");
        assert_eq!(y_val, 15, "Y should be 15 (satisfies y <= 16 and y != 13)");
        assert_eq!(z_val, 5, "Z should be 5 (satisfies z >= 4)");
        println!("SimpleConstraint variants: x={}, y={}, z={}", x_val, y_val, z_val);
    }

    #[test]
    fn test_conditional_constraint_greater_than_condition() {
        let mut model = Model::default();
        let trigger = model.int(0, 10);
        let output = model.int(0, 20);
        
        // If trigger > 5, then output == 15
        let condition = Condition::GreaterThan(trigger, Val::ValI(5));
        let then_constraint = SimpleConstraint::Equals(output, Val::ValI(15));
        model.props.if_then_else_constraint(condition, then_constraint, None);
        
        // Set trigger to 7 (greater than 5)
        model.new(trigger.eq(7));
        
        let solution = model.solve();
        assert!(solution.is_ok(), "GreaterThan condition should work");
        
        let sol = solution.unwrap();
        let trigger_val = sol.get_int(trigger);
        let output_val = sol.get_int(output);
        
        assert_eq!(trigger_val, 7, "Trigger should be 7");
        assert_eq!(output_val, 15, "Output should be 15 when trigger > 5");
    }

    #[test]
    fn test_conditional_constraint_greater_or_equal_condition() {
        let mut model = Model::default();
        let threshold_var = model.int(0, 10);
        let result_var = model.int(0, 100);

        // Check if there's a GreaterOrEqual condition variant
        let condition = Condition::GreaterThan(threshold_var, Val::ValI(4)); // Use GreaterThan instead
        let constraint = SimpleConstraint::GreaterThan(result_var, Val::ValI(40));
        model.props.if_then_else_constraint(condition, constraint, None);

        // Set values using proper API
        model.new(threshold_var.eq(7));
        model.new(result_var.eq(50));

        let solution = model.solve();
        assert!(solution.is_ok(), "GreaterThan condition should be satisfiable");
        
        let sol = solution.unwrap();
        let threshold_val = sol.get_int(threshold_var);
        let result_val = sol.get_int(result_var);
        
        assert_eq!(threshold_val, 7, "Threshold should be 7");
        assert_eq!(result_val, 50, "Result should be 50");
        println!("GreaterThan condition: threshold={}, result={}", threshold_val, result_val);
    }

    #[test]
    fn test_conditional_constraint_less_or_equal_condition() {
        let mut model = Model::default();
        let limit_var = model.int(0, 15);
        let output_var = model.int(0, 50);

        // Use LessThan instead since LessOrEqual might not be available
        let condition = Condition::LessThan(limit_var, Val::ValI(11)); // 8 < 11 is true
        let constraint = SimpleConstraint::LessThan(output_var, Val::ValI(30));
        model.props.if_then_else_constraint(condition, constraint, None);

        // Set values using proper API
        model.new(limit_var.eq(8));
        model.new(output_var.eq(25));

        let solution = model.solve();
        assert!(solution.is_ok(), "LessThan condition should be satisfiable");
        
        let sol = solution.unwrap();
        let limit_val = sol.get_int(limit_var);
        let output_val = sol.get_int(output_var);
        
        assert_eq!(limit_val, 8, "Limit should be 8");
        assert_eq!(output_val, 25, "Output should be 25");
        println!("LessThan condition: limit={}, output={}", limit_val, output_val);
    }

    #[test]
    fn test_conditional_constraint_not_equals_condition() {
        let mut model = Model::default();
        let switch = model.int(0, 2);
        let result = model.int(0, 10);
        
        // If switch != 1, then result == 8
        let condition = Condition::NotEquals(switch, Val::ValI(1));
        let then_constraint = SimpleConstraint::Equals(result, Val::ValI(8));
        model.props.if_then_else_constraint(condition, then_constraint, None);
        
        // Set switch to 0 (not equal to 1)
        model.new(switch.eq(0));
        
        let solution = model.solve();
        assert!(solution.is_ok(), "NotEquals condition should work");
        
        let sol = solution.unwrap();
        let switch_val = sol.get_int(switch);
        let result_val = sol.get_int(result);
        
        assert_eq!(switch_val, 0, "Switch should be 0");
        assert_eq!(result_val, 8, "Result should be 8 when switch != 1");
    }

    #[test]
    fn test_conditional_constraint_less_than_condition() {
        let mut model = Model::default();
        let level = model.int(0, 10);
        let status = model.int(0, 5);
        
        // If level < 3, then status == 1
        let condition = Condition::LessThan(level, Val::ValI(3));
        let then_constraint = SimpleConstraint::Equals(status, Val::ValI(1));
        model.props.if_then_else_constraint(condition, then_constraint, None);
        
        // Set level to 2 (less than 3)
        model.new(level.eq(2));
        
        let solution = model.solve();
        assert!(solution.is_ok(), "LessThan condition should work");
        
        let sol = solution.unwrap();
        let level_val = sol.get_int(level);
        let status_val = sol.get_int(status);
        
        assert_eq!(level_val, 2, "Level should be 2");
        assert_eq!(status_val, 1, "Status should be 1 when level < 3");
    }

    #[test]
    fn test_conditional_constraint_greater_or_equal_then() {
        let mut model = Model::default();
        let trigger = model.bool();
        let value = model.int(0, 10);
        
        // If trigger == 1, then value >= 7
        let condition = Condition::Equals(trigger, Val::ValI(1));
        let then_constraint = SimpleConstraint::GreaterOrEqual(value, Val::ValI(7));
        model.props.if_then_else_constraint(condition, then_constraint, None);
        
        // Force trigger
        model.new(trigger.eq(1));
        
        let solution = model.solve();
        assert!(solution.is_ok(), "GreaterOrEqual then constraint should work");
        
        let sol = solution.unwrap();
        let trigger_val = sol.get_int(trigger);
        let value_val = sol.get_int(value);
        
        assert_eq!(trigger_val, 1, "Trigger should be true");
        assert!(value_val >= 7, "Value should be >= 7 when triggered");
    }

    #[test]
    fn test_conditional_constraint_less_or_equal_then() {
        let mut model = Model::default();
        let enable = model.bool();
        let limit = model.int(0, 20);
        
        // If enable == 1, then limit <= 12
        let condition = Condition::Equals(enable, Val::ValI(1));
        let then_constraint = SimpleConstraint::LessOrEqual(limit, Val::ValI(12));
        model.props.if_then_else_constraint(condition, then_constraint, None);
        
        // Force enable
        model.new(enable.eq(1));
        
        let solution = model.solve();
        assert!(solution.is_ok(), "LessOrEqual then constraint should work");
        
        let sol = solution.unwrap();
        let enable_val = sol.get_int(enable);
        let limit_val = sol.get_int(limit);
        
        assert_eq!(enable_val, 1, "Enable should be true");
        assert!(limit_val <= 12, "Limit should be <= 12 when enabled");
    }

    #[test]
    fn test_conditional_constraint_not_equals_then() {
        let mut model = Model::default();
        let mode = model.int(1, 3);
        let output = model.int(0, 10);
        
        // If mode == 2, then output != 5
        let condition = Condition::Equals(mode, Val::ValI(2));
        let then_constraint = SimpleConstraint::NotEquals(output, Val::ValI(5));
        model.props.if_then_else_constraint(condition, then_constraint, None);
        
        // Force mode
        model.new(mode.eq(2));
        model.new(output.eq(7)); // Force output to something other than 5
        
        let solution = model.solve();
        assert!(solution.is_ok(), "NotEquals then constraint should work");
        
        let sol = solution.unwrap();
        let mode_val = sol.get_int(mode);
        let output_val = sol.get_int(output);
        
        assert_eq!(mode_val, 2, "Mode should be 2");
        assert_eq!(output_val, 7, "Output should be 7");
        assert_ne!(output_val, 5, "Output should not be 5 when mode == 2");
    }

    #[test]
    fn test_conditional_constraint_greater_than_then() {
        let mut model = Model::default();
        let active = model.bool();
        let threshold = model.int(0, 20);
        
        // If active == 1, then threshold > 10
        let condition = Condition::Equals(active, Val::ValI(1));
        let then_constraint = SimpleConstraint::GreaterThan(threshold, Val::ValI(10));
        model.props.if_then_else_constraint(condition, then_constraint, None);
        
        // Force active
        model.new(active.eq(1));
        
        let solution = model.solve();
        assert!(solution.is_ok(), "GreaterThan then constraint should work");
        
        let sol = solution.unwrap();
        let active_val = sol.get_int(active);
        let threshold_val = sol.get_int(threshold);
        
        assert_eq!(active_val, 1, "Active should be true");
        assert!(threshold_val > 10, "Threshold should be > 10 when active");
    }

    #[test]
    fn test_conditional_constraint_less_than_then() {
        let mut model = Model::default();
        let restrict = model.bool();
        let value = model.int(0, 20);
        
        // If restrict == 1, then value < 8
        let condition = Condition::Equals(restrict, Val::ValI(1));
        let then_constraint = SimpleConstraint::LessThan(value, Val::ValI(8));
        model.props.if_then_else_constraint(condition, then_constraint, None);
        
        // Force restrict
        model.new(restrict.eq(1));
        
        let solution = model.solve();
        assert!(solution.is_ok(), "LessThan then constraint should work");
        
        let sol = solution.unwrap();
        let restrict_val = sol.get_int(restrict);
        let value_val = sol.get_int(value);
        
        assert_eq!(restrict_val, 1, "Restrict should be true");
        assert!(value_val < 8, "Value should be < 8 when restricted");
    }

    #[test]
    fn test_multiple_conditional_constraints() {
        let mut model = Model::default();
        let cond1 = model.bool();
        let cond2 = model.bool();
        let x = model.int(0, 10);
        let y = model.int(0, 10);
        
        // If cond1 == 1, then x >= 5
        let condition1 = Condition::Equals(cond1, Val::ValI(1));
        let then1 = SimpleConstraint::GreaterOrEqual(x, Val::ValI(5));
        model.props.if_then_else_constraint(condition1, then1, None);
        
        // If cond2 == 1, then y <= 7
        let condition2 = Condition::Equals(cond2, Val::ValI(1));
        let then2 = SimpleConstraint::LessOrEqual(y, Val::ValI(7));
        model.props.if_then_else_constraint(condition2, then2, None);
        
        // Force both conditions to be false to avoid conditional constraint enforcement
        model.new(cond1.eq(0));
        model.new(cond2.eq(0));
        
        let solution = model.solve();
        assert!(solution.is_ok(), "Multiple conditional constraints should work");
        
        let sol = solution.unwrap();
        let cond1_val = sol.get_int(cond1);
        let cond2_val = sol.get_int(cond2);
        let x_val = sol.get_int(x);
        let y_val = sol.get_int(y);
        
        assert_eq!(cond1_val, 0, "Condition 1 should be false");
        assert_eq!(cond2_val, 0, "Condition 2 should be false");
        
        // When conditions are false, x and y can be any value in domain
        assert!(x_val >= 0 && x_val <= 10, "X should be in domain (got {})", x_val);
        assert!(y_val >= 0 && y_val <= 10, "Y should be in domain (got {})", y_val);
    }

    #[test]
    fn test_conditional_constraint_impossible() {
        let mut model = Model::default();
        let trigger = model.int(5, 5); // Fixed to 5
        let result = model.int(3, 3); // Fixed to 3
        
        // If trigger == 5, then result == 7 (impossible since result is fixed to 3)
        let condition = Condition::Equals(trigger, Val::ValI(5));
        let then_constraint = SimpleConstraint::Equals(result, Val::ValI(7));
        model.props.if_then_else_constraint(condition, then_constraint, None);
        
        let solution = model.solve();
        assert!(solution.is_err(), "Impossible conditional constraint should fail");
    }

    #[test]
    fn test_conditional_constraint_condition_variables() {
        let mut model = Model::default();
        let condition_var = model.bool();
        let x = model.int(0, 10);
        
        // Test the variables() method of conditional constraints
        let condition = Condition::Equals(condition_var, Val::ValI(1));
        let then_constraint = SimpleConstraint::Equals(x, Val::ValI(5));
        let constraint = IfThenElseConstraint::if_then(condition, then_constraint);
        
        let variables = constraint.variables();
        assert_eq!(variables.len(), 2, "Should have 2 variables");
        assert!(variables.contains(&condition_var), "Should contain condition variable");
        assert!(variables.contains(&x), "Should contain then variable");
    }

    #[test]
    fn test_conditional_constraint_edge_cases() {
        let mut model = Model::default();
        let cond = model.int(0, 1);
        let target = model.int(5, 5); // Fixed domain
        
        // If cond == 1, then target == 5 (should always be satisfiable)
        let condition = Condition::Equals(cond, Val::ValI(1));
        let then_constraint = SimpleConstraint::Equals(target, Val::ValI(5));
        model.props.if_then_else_constraint(condition, then_constraint, None);
        
        // Force condition true
        model.new(cond.eq(1));
        
        let solution = model.solve();
        assert!(solution.is_ok(), "Edge case with fixed domain should work");
        
        let sol = solution.unwrap();
        let cond_val = sol.get_int(cond);
        let target_val = sol.get_int(target);
        
        assert_eq!(cond_val, 1, "Condition should be true");
        assert_eq!(target_val, 5, "Target should be 5");
    }

    // ===== TABLE CONSTRAINTS COMPREHENSIVE COVERAGE =====
    // Targeting: src/constraints/props/table.rs (Function: 0.00%, Line: 0.00%, Region: 0.00%)
    
    #[test]
    fn test_table_constraint_basic_binary() {
        let mut model = Model::default();
        let x = model.int(0, 2);
        let y = model.int(0, 2);
        
        // Create a table constraint: allowed combinations (x,y) = [(0,1), (1,0), (2,2)]
        let tuples = vec![
            vec![Val::ValI(0), Val::ValI(1)],
            vec![Val::ValI(1), Val::ValI(0)],
            vec![Val::ValI(2), Val::ValI(2)],
        ];
        
        // Use internal API for comprehensive coverage
        model.props.table_constraint(vec![x, y], tuples);
        
        // Force one solution
        model.new(x.eq(0));
        
        let solution = model.solve();
        assert!(solution.is_ok(), "Basic table constraint should be satisfiable");
        
        let sol = solution.unwrap();
        let x_val = sol.get_int(x);
        let y_val = sol.get_int(y);
        
        assert_eq!(x_val, 0, "X should be 0");
        assert_eq!(y_val, 1, "Y should be 1 (from table)");
        println!("Table constraint: x={}, y={}", x_val, y_val);
    }

    #[test]
    fn test_table_constraint_three_variables() {
        let mut model = Model::default();
        let x = model.int(0, 3);
        let y = model.int(0, 3);
        let z = model.int(0, 3);
        
        // Create a table constraint with three variables
        let tuples = vec![
            vec![Val::ValI(0), Val::ValI(1), Val::ValI(2)],
            vec![Val::ValI(1), Val::ValI(2), Val::ValI(0)],
            vec![Val::ValI(2), Val::ValI(0), Val::ValI(1)],
            vec![Val::ValI(3), Val::ValI(3), Val::ValI(3)],
        ];
        
        model.props.table_constraint(vec![x, y, z], tuples);
        
        // Force a specific solution
        model.new(x.eq(1));
        
        let solution = model.solve();
        assert!(solution.is_ok(), "Three-variable table constraint should work");
        
        let sol = solution.unwrap();
        let x_val = sol.get_int(x);
        let y_val = sol.get_int(y);
        let z_val = sol.get_int(z);
        
        assert_eq!(x_val, 1, "X should be 1");
        assert_eq!(y_val, 2, "Y should be 2 (from table)");
        assert_eq!(z_val, 0, "Z should be 0 (from table)");
        println!("Three-var table: x={}, y={}, z={}", x_val, y_val, z_val);
    }

    #[test]
    fn test_table_constraint_no_valid_tuples() {
        let mut model = Model::default();
        let x = model.int(0, 1);
        let y = model.int(0, 1);
        
        // Create a table constraint with no valid combinations for the domains
        let tuples = vec![
            vec![Val::ValI(5), Val::ValI(6)], // Outside domain
            vec![Val::ValI(7), Val::ValI(8)], // Outside domain
        ];
        
        model.props.table_constraint(vec![x, y], tuples);
        
        let solution = model.solve();
        assert!(solution.is_err(), "Table constraint with no valid tuples should fail");
    }

    #[test]
    fn test_table_constraint_single_tuple() {
        let mut model = Model::default();
        let x = model.int(0, 5);
        let y = model.int(0, 5);
        
        // Table with only one valid combination
        let tuples = vec![
            vec![Val::ValI(3), Val::ValI(4)],
        ];
        
        model.props.table_constraint(vec![x, y], tuples);
        
        let solution = model.solve();
        assert!(solution.is_ok(), "Single tuple table constraint should work");
        
        let sol = solution.unwrap();
        let x_val = sol.get_int(x);
        let y_val = sol.get_int(y);
        
        assert_eq!(x_val, 3, "X should be 3");
        assert_eq!(y_val, 4, "Y should be 4");
        println!("Single tuple: x={}, y={}", x_val, y_val);
    }

    #[test]
    fn test_table_constraint_domain_filtering() {
        let mut model = Model::default();
        let x = model.int(0, 10);
        let y = model.int(0, 10);
        
        // Large domain but only specific combinations allowed
        let tuples = vec![
            vec![Val::ValI(2), Val::ValI(5)],
            vec![Val::ValI(7), Val::ValI(3)],
            vec![Val::ValI(9), Val::ValI(1)],
        ];
        
        model.props.table_constraint(vec![x, y], tuples);
        
        // Add additional constraint to test propagation
        model.new(x.ge(7));
        
        let solution = model.solve();
        assert!(solution.is_ok(), "Domain filtering table constraint should work");
        
        let sol = solution.unwrap();
        let x_val = sol.get_int(x);
        let y_val = sol.get_int(y);
        
        // With x >= 7, only (7,3) or (9,1) are valid
        assert!(x_val == 7 || x_val == 9, "X should be 7 or 9");
        if x_val == 7 {
            assert_eq!(y_val, 3, "If x=7, then y=3");
        } else {
            assert_eq!(y_val, 1, "If x=9, then y=1");
        }
        println!("Domain filtering: x={}, y={}", x_val, y_val);
    }

    #[test]
    fn test_table_constraint_empty_table() {
        let mut model = Model::default();
        let x = model.int(0, 2);
        let y = model.int(0, 2);
        
        // Empty table - no valid combinations
        let tuples: Vec<Vec<Val>> = vec![];
        
        model.props.table_constraint(vec![x, y], tuples);
        
        let solution = model.solve();
        assert!(solution.is_err(), "Empty table constraint should fail");
    }

    #[test]
    fn test_table_constraint_mixed_values() {
        let mut model = Model::default();
        let x = model.int(-2, 2);
        let y = model.int(-3, 3);
        
        // Table with negative and positive values
        let tuples = vec![
            vec![Val::ValI(-2), Val::ValI(-1)],
            vec![Val::ValI(-1), Val::ValI(0)],
            vec![Val::ValI(0), Val::ValI(1)],
            vec![Val::ValI(1), Val::ValI(2)],
            vec![Val::ValI(2), Val::ValI(-3)],
        ];
        
        model.props.table_constraint(vec![x, y], tuples);
        
        // Test with specific constraint
        model.new(y.eq(-3));
        
        let solution = model.solve();
        assert!(solution.is_ok(), "Mixed values table constraint should work");
        
        let sol = solution.unwrap();
        let x_val = sol.get_int(x);
        let y_val = sol.get_int(y);
        
        assert_eq!(x_val, 2, "X should be 2");
        assert_eq!(y_val, -3, "Y should be -3");
        println!("Mixed values: x={}, y={}", x_val, y_val);
    }

    #[test]
    fn test_table_constraint_large_arity() {
        let mut model = Model::default();
        let var1 = model.int(0, 1);
        let var2 = model.int(0, 1);
        let var3 = model.int(0, 1);
        let var4 = model.int(0, 1);
        
        // Four-variable table constraint - valid combinations  
        let tuples = vec![
            vec![Val::ValI(0), Val::ValI(1), Val::ValI(0), Val::ValI(0)], // Add the actual solution
            vec![Val::ValI(0), Val::ValI(1), Val::ValI(1), Val::ValI(0)], 
            vec![Val::ValI(1), Val::ValI(0), Val::ValI(0), Val::ValI(1)],
            vec![Val::ValI(1), Val::ValI(1), Val::ValI(0), Val::ValI(0)],
        ];
        
        model.props.table_constraint(vec![var1, var2, var3, var4], tuples.clone());
        
        // Force first two variables
        model.new(var1.eq(0));
        model.new(var2.eq(1));
        
        let solution = model.solve();
        assert!(solution.is_ok(), "Large arity table constraint should work");
        
        let sol = solution.unwrap();
        let val1 = sol.get_int(var1);
        let val2 = sol.get_int(var2);
        let val3 = sol.get_int(var3);
        let val4 = sol.get_int(var4);
        
        assert_eq!(val1, 0, "First var should be 0");
        assert_eq!(val2, 1, "Second var should be 1");
        
        // Check that the solution matches one of the valid tuples
        let solution_tuple = vec![val1, val2, val3, val4];
        let valid_tuples: Vec<Vec<i32>> = tuples.into_iter().map(|tuple| {
            tuple.into_iter().map(|val| match val {
                Val::ValI(i) => i,
                _ => panic!("Expected integer value"),
            }).collect()
        }).collect();
        
        let matches_table = valid_tuples.iter().any(|tuple| {
            tuple[0] == val1 && tuple[1] == val2 && tuple[2] == val3 && tuple[3] == val4
        });
        
        assert!(matches_table, "Solution {:?} should match one of the table tuples", solution_tuple);
        
        println!("Large arity: [{}, {}, {}, {}]", val1, val2, val3, val4);
    }

    #[test]
    fn test_table_constraint_variable_methods() {
        let mut model = Model::default();
        let x = model.int(0, 3);
        let y = model.int(0, 3);
        
        let tuples = vec![
            vec![Val::ValI(0), Val::ValI(2)],
            vec![Val::ValI(1), Val::ValI(3)],
            vec![Val::ValI(2), Val::ValI(0)],
        ];
        
        // Test through the model API only
        model.props.table_constraint(vec![x, y], tuples);
        
        model.new(x.eq(1));
        
        let solution = model.solve();
        assert!(solution.is_ok(), "Variable methods test should work");
        
        let sol = solution.unwrap();
        assert_eq!(sol.get_int(x), 1, "X should be 1");
        assert_eq!(sol.get_int(y), 3, "Y should be 3");
    }

    #[test]
    fn test_table_constraint_edge_cases() {
        let mut model = Model::default();
        let x = model.int(5, 5); // Fixed domain
        let y = model.int(0, 10);
        
        // Table where only one value of x is valid
        let tuples = vec![
            vec![Val::ValI(5), Val::ValI(7)],
            vec![Val::ValI(5), Val::ValI(8)],
            vec![Val::ValI(3), Val::ValI(9)], // Won't be used since x can't be 3
        ];
        
        model.props.table_constraint(vec![x, y], tuples);
        
        // Additional constraint to select specific tuple
        model.new(y.eq(8));
        
        let solution = model.solve();
        assert!(solution.is_ok(), "Edge case with fixed domain should work");
        
        let sol = solution.unwrap();
        assert_eq!(sol.get_int(x), 5, "X should be 5");
        assert_eq!(sol.get_int(y), 8, "Y should be 8");
    }
}