# Copyright (c) Microsoft Corporation.
# Licensed under the MIT License.

# Destructuring Pattern Test Suite
# Tests destructuring patterns in assignments, function parameters, and some-in loops
# Note: Set destructuring is not supported by Rego and should produce compilation errors

cases:
  # Basic array destructuring with colon assignment
  - note: array_destructuring_basic
    data: {}
    modules:
      - |
        package test
        main := [a, b] if {
          [a, b] := [1, 2]
        }
    query: data.test.main
    want_result: [1, 2]

  # Array destructuring with equals assignment
  - note: array_destructuring_equals
    data: {}
    modules:
      - |
        package test
        main := [x, y, z] if {
          arr := [10, 20, 30]
          [x, y, z] = arr
        }
    query: data.test.main
    want_result: [10, 20, 30]

  # Object destructuring with colon assignment
  - note: object_destructuring_basic
    data: {}
    modules:
      - |
        package test
        main := [name, age] if {
          {"name": name, "age": age} := {"name": "Alice", "age": 30}
        }
    query: data.test.main
    want_result: ["Alice", 30]

  # Object destructuring with equals assignment  
  - note: object_destructuring_equals
    data: {}
    modules:
      - |
        package test
        main := [x, y] if {
          obj := {"x": 100, "y": 200}
          {"x": x, "y": y} = obj
        }
    query: data.test.main
    want_result: [100, 200]

  # Nested array destructuring
  - note: nested_array_destructuring
    data: {}
    modules:
      - |
        package test
        main := [a, c, d] if {
          [[a, b], [c, d]] := [[1, 2], [3, 4]]
        }
    query: data.test.main
    want_result: [1, 3, 4]

  # Array destructuring in function parameters
  - note: array_destructuring_function_param
    data: {}
    modules:
      - |
        package test
        add_first_two([x, y]) := x + y
        main := add_first_two([5, 7])
    query: data.test.main
    want_result: 12

  # Object destructuring in function parameters
  - note: object_destructuring_function_param
    data: {}
    modules:
      - |
        package test
        get_name({"name": name}) := name
        main := get_name({"name": "Bob", "age": 25})
    query: data.test.main
    want_result: "Bob"

  # Mixed array and object destructuring
  - note: mixed_destructuring
    data: {}
    modules:
      - |
        package test
        main := [name, x, y] if {
          [user, {"x": x, "y": y}] := [{"name": "Grace"}, {"x": 1, "y": 2}]
          {"name": name} = user
        }
    query: data.test.main
    want_result: ["Grace", 1, 2]

  # Destructuring with literal matching
  - note: destructuring_with_literals
    data: {}
    modules:
      - |
        package test
        main := value if {
          [1, value, 3] := [1, 42, 3]
        }
    query: data.test.main
    want_result: 42

  # SET DESTRUCTURING ERROR CASES - These should fail compilation
  # RVM correctly rejects these, but interpreter incorrectly allows them

  # Set destructuring in colon assignment should error
  - note: set_destructuring_colon_error
    data: {}
    modules:
      - |
        package test
        main := result if {
          {a, b} := {1, 2, 3}
          result := [a, b]
        }
    query: data.test.main
    want_error: "assignment operator := requires left-hand side to have bindable variables"
    allow_interpreter_success: true

  # Set destructuring in function parameters should error
  - note: set_destructuring_function_param_error
    data: {}
    modules:
      - |
        package test
        has_element({x, y}, elem) := elem in {x, y}
        main := has_element({10, 20}, 20)
    query: data.test.main
    want_error: "Undefined variable"
    allow_interpreter_success: true

  # Set destructuring in equals assignment should error
  - note: set_destructuring_equals_error
    data: {}
    modules:
      - |
        package test
        main := result if {
          s := {1, 2}
          {x, y} = s
          result := [x, y]
        }
    query: data.test.main
    want_error: "Undefined variable"
    allow_interpreter_success: true

  # Option 2: Function parameter destructuring with multiple definitions and definition-level failure
  - note: function_param_destructuring_multiple_definitions
    data: {}
    modules:
      - |
        package test
        # This function has multiple definitions with different parameter patterns
        # Only the matching definition should succeed, others should fail at definition level
        process_input([x, y]) := sprintf("array: %v, %v", [x, y])
        process_input([x, y, z]) := sprintf("array: %v, %v, %v", [x, y, z])  
        process_input({"name": name, "age": age}) := sprintf("object: %s is %d", [name, age])
        
        # Test with 2-element array - should match first definition
        test_2_elements := process_input([1, 2])
        
        # Test with 3-element array - should match second definition
        test_3_elements := process_input([1, 2, 3])
        
        # Test with object - should match third definition
        test_object := process_input({"name": "Alice", "age": 30})
        
        # Combined result for testing
        main := {
          "test_2_elements": test_2_elements,
          "test_3_elements": test_3_elements,
          "test_object": test_object
        }
    query: data.test.main
    want_result:
      test_2_elements: "array: 1, 2"
      test_3_elements: "array: 1, 2, 3"
      test_object: "object: Alice is 30"


  # Option 2: Complex nested destructuring in function parameters
  - note: function_param_nested_destructuring
    data: {}
    modules:
      - |
        package test
        # Function with nested destructuring patterns
        extract_info({"user": {"name": name, "details": {"age": age, "city": city}}, "active": active}) := {
          "user_name": name,
          "user_age": age,
          "user_city": city,
          "is_active": active
        }
        
        main := extract_info({
          "user": {
            "name": "Bob",
            "details": {
              "age": 25,
              "city": "Seattle"
            }
          },
          "active": true
        })
    query: data.test.main
    want_result:
      user_name: "Bob"
      user_age: 25
      user_city: "Seattle"
      is_active: true

  # Option 2: Mixed destructuring and non-destructuring definitions
  - note: function_mixed_destructuring_and_simple
    data: {}
    modules:
      - |
        package test
        # Function with mixed parameter styles - some with destructuring, some without
        handle_request(method) := sprintf("simple method: %s", [method]) if {
          method in ["GET", "POST", "PUT", "DELETE"]
        }
        handle_request({"method": method, "path": path}) := sprintf("structured request: %s %s", [method, path])
        handle_request({"method": method, "headers": {"auth": token}}) := sprintf("authenticated %s with token %s", [method, token])
        
        # Test simple string parameter - should match first definition
        test_simple := handle_request("GET")
        
        # Test structured request - should match second definition  
        test_structured := handle_request({"method": "POST", "path": "/users"})
        
        # Test with auth header - should match third definition
        test_auth := handle_request({"method": "PUT", "headers": {"auth": "abc123"}})
        
        # Test that fails all patterns - this should be undefined
        test_invalid := handle_request(42)
        
        # Combined result for testing
        main := {
          "test_simple": test_simple,
          "test_structured": test_structured, 
          "test_auth": test_auth,
          "test_invalid": test_invalid
        }
    query: data.test.main
    want_result: "#undefined"