package workflow

import (
	"context"
	"fmt"
	"strings"
	"testing"
)

func newTestEvaluator() *ExpressionEvaluator {
	ctx := &ExecutionContext{
		Variables: map[string]interface{}{
			"$name":    "Alice",
			"$age":     30,
			"$active":  true,
			"$score":   85.5,
			"$items":   []interface{}{"a", "b", "c"},
			"$empty":   "",
			"$zero":    0,
			"$nothing": nil,
			"$user": map[string]interface{}{
				"name": "Bob",
				"age":  25,
				"address": map[string]interface{}{
					"city":    "NYC",
					"zipcode": "10001",
				},
			},
			"$numbers": []interface{}{1, 2, 3, 4, 5},
		},
		LocalVars: map[string]interface{}{
			"_result": map[string]interface{}{
				"status": "success",
				"data":   42,
			},
			"_item":  "current",
			"_index": 2,
		},
	}
	// Use setter method for system variables
	ctx.SetSystemVar("SYSVAR.workflowId", "wf-123")
	ctx.SetSystemVar("SYSVAR.timestamp", 1234567890)
	return NewExpressionEvaluator(ctx)
}

func TestEvaluateValue(t *testing.T) {
	eval := newTestEvaluator()

	t.Run("NonStringTypes", func(t *testing.T) {
		// Non-string types returned as-is
		tests := []struct {
			name     string
			input    interface{}
			expected interface{}
		}{
			{"int", 42, 42},
			{"float", 3.14, 3.14},
			{"bool true", true, true},
			{"bool false", false, false},
			{"nil", nil, nil},
			{"slice", []interface{}{"a", "b"}, nil}, // compared separately
			{"map", map[string]interface{}{"k": "v"}, nil},
		}

		for _, tt := range tests {
			t.Run(tt.name, func(t *testing.T) {
				result, err := eval.EvaluateValue(tt.input)
				if err != nil {
					t.Fatalf("unexpected error: %v", err)
				}
				if tt.name == "slice" || tt.name == "map" {
					// Just check it's returned as-is (same pointer)
					if result == nil {
						t.Errorf("expected non-nil result")
					}
				} else if result != tt.expected {
					t.Errorf("expected %v (%T), got %v (%T)", tt.expected, tt.expected, result, result)
				}
			})
		}
	})

	t.Run("LiteralStrings", func(t *testing.T) {
		// Strings without = prefix are literal
		tests := []struct {
			name     string
			input    string
			expected string
		}{
			{"plain text", "hello world", "hello world"},
			{"empty string", "", ""},
			{"url", "https://example.com", "https://example.com"},
			{"path", "/var/log/app.log", "/var/log/app.log"},
			{"dollar no prefix", "$name", "$name"},
			{"number string", "42", "42"},
		}

		for _, tt := range tests {
			t.Run(tt.name, func(t *testing.T) {
				result, err := eval.EvaluateValue(tt.input)
				if err != nil {
					t.Fatalf("unexpected error: %v", err)
				}
				if result != tt.expected {
					t.Errorf("expected %q, got %v (%T)", tt.expected, result, result)
				}
			})
		}
	})

	t.Run("ExpressionStrings", func(t *testing.T) {
		// Strings with = prefix evaluate the rest as expression
		tests := []struct {
			name     string
			input    string
			expected interface{}
		}{
			{"variable ref", "=$name", "Alice"},
			{"variable int", "=$age", 30},
			{"variable bool", "=$active", true},
			{"expression", "=$age + 5", float64(35)},
			{"comparison", "=$age > 20", true},
			{"nested path", "=$user.name", "Bob"},
			{"string literal expr", `="hello"`, "hello"},
			{"numeric literal", "=42", int64(42)},
		}

		for _, tt := range tests {
			t.Run(tt.name, func(t *testing.T) {
				result, err := eval.EvaluateValue(tt.input)
				if err != nil {
					t.Fatalf("unexpected error: %v", err)
				}
				if result != tt.expected {
					t.Errorf("expected %v (%T), got %v (%T)", tt.expected, tt.expected, result, result)
				}
			})
		}
	})

	t.Run("EscapedEquals", func(t *testing.T) {
		// Strings with == prefix strip one = and return as literal
		tests := []struct {
			name     string
			input    string
			expected string
		}{
			{"escaped equals", "==something", "=something"},
			{"escaped var-like", "==$name", "=$name"},
			{"escaped expression", "==$age + 5", "=$age + 5"},
			{"triple equals", "===foo", "==foo"},
		}

		for _, tt := range tests {
			t.Run(tt.name, func(t *testing.T) {
				result, err := eval.EvaluateValue(tt.input)
				if err != nil {
					t.Fatalf("unexpected error: %v", err)
				}
				if result != tt.expected {
					t.Errorf("expected %q, got %v (%T)", tt.expected, result, result)
				}
			})
		}
	})
}

func TestEvaluateLiterals(t *testing.T) {
	eval := newTestEvaluator()

	tests := []struct {
		name     string
		expr     string
		expected interface{}
	}{
		{"empty string", "", nil},
		{"string double quotes", `"hello"`, "hello"},
		{"string single quotes", `'world'`, "world"},
		{"string with spaces", `"hello world"`, "hello world"},
		{"boolean true", "true", true},
		{"boolean false", "false", false},
		{"null", "null", nil},
		{"nil", "nil", nil},
		{"integer", "42", int64(42)},
		{"negative integer", "-5", int64(-5)},
		{"float", "3.14", 3.14},
		{"negative float", "-2.5", -2.5},
	}

	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {
			result, err := eval.Evaluate(tt.expr)
			if err != nil {
				t.Fatalf("unexpected error: %v", err)
			}
			if result != tt.expected {
				t.Errorf("expected %v (%T), got %v (%T)", tt.expected, tt.expected, result, result)
			}
		})
	}
}

func TestEvaluateGlobalVariables(t *testing.T) {
	eval := newTestEvaluator()

	tests := []struct {
		name     string
		expr     string
		expected interface{}
	}{
		{"string var", "$name", "Alice"},
		{"int var", "$age", 30},
		{"bool var", "$active", true},
		{"float var", "$score", 85.5},
		{"nil var", "$nothing", nil},
		{"undefined var", "$undefined", nil},
	}

	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {
			result, err := eval.Evaluate(tt.expr)
			if err != nil {
				t.Fatalf("unexpected error: %v", err)
			}
			if result != tt.expected {
				t.Errorf("expected %v, got %v", tt.expected, result)
			}
		})
	}
}

func TestEvaluateNestedPaths(t *testing.T) {
	eval := newTestEvaluator()

	tests := []struct {
		name     string
		expr     string
		expected interface{}
	}{
		{"nested field", "$user.name", "Bob"},
		{"nested int field", "$user.age", 25},
		{"deep nested field", "$user.address.city", "NYC"},
		{"array index", "$items[0]", "a"},
		{"array index 1", "$items[1]", "b"},
		{"array index 2", "$items[2]", "c"},
		{"numeric array", "$numbers[0]", 1},
		{"numeric array last", "$numbers[4]", 5},
	}

	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {
			result, err := eval.Evaluate(tt.expr)
			if err != nil {
				t.Fatalf("unexpected error: %v", err)
			}
			if result != tt.expected {
				t.Errorf("expected %v, got %v", tt.expected, result)
			}
		})
	}
}

func TestEvaluateSystemVariables(t *testing.T) {
	eval := newTestEvaluator()

	tests := []struct {
		name     string
		expr     string
		expected interface{}
	}{
		{"workflow id", "SYSVAR.workflowId", "wf-123"},
		{"timestamp", "SYSVAR.timestamp", 1234567890},
	}

	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {
			result, err := eval.Evaluate(tt.expr)
			if err != nil {
				t.Fatalf("unexpected error: %v", err)
			}
			if result != tt.expected {
				t.Errorf("expected %v, got %v", tt.expected, result)
			}
		})
	}
}

func TestEvaluateLocalVariables(t *testing.T) {
	eval := newTestEvaluator()

	tests := []struct {
		name     string
		expr     string
		expected interface{}
	}{
		{"local item", "_item", "current"},
		{"local index", "_index", 2},
		{"local result status", "_result.status", "success"},
		{"local result data", "_result.data", 42},
	}

	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {
			result, err := eval.Evaluate(tt.expr)
			if err != nil {
				t.Fatalf("unexpected error: %v", err)
			}
			if result != tt.expected {
				t.Errorf("expected %v, got %v", tt.expected, result)
			}
		})
	}
}

func TestEvaluateComparisons(t *testing.T) {
	eval := newTestEvaluator()

	tests := []struct {
		name     string
		expr     string
		expected bool
	}{
		// Equality
		{"int equals true", "$age == 30", true},
		{"int equals false", "$age == 25", false},
		{"string equals true", "$name == \"Alice\"", true},
		{"string equals false", "$name == \"Bob\"", false},
		{"bool equals true", "$active == true", true},
		{"bool equals false", "$active == false", false},

		// Inequality
		{"not equals true", "$age != 25", true},
		{"not equals false", "$age != 30", false},

		// Greater than
		{"greater than true", "$age > 25", true},
		{"greater than false", "$age > 35", false},
		{"greater than equal", "$age > 30", false},

		// Greater than or equal
		{"gte true greater", "$age >= 25", true},
		{"gte true equal", "$age >= 30", true},
		{"gte false", "$age >= 35", false},

		// Less than
		{"less than true", "$age < 35", true},
		{"less than false", "$age < 25", false},
		{"less than equal", "$age < 30", false},

		// Less than or equal
		{"lte true less", "$age <= 35", true},
		{"lte true equal", "$age <= 30", true},
		{"lte false", "$age <= 25", false},

		// Float comparisons
		{"float greater", "$score > 80", true},
		{"float less", "$score < 90", true},
	}

	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {
			result, err := eval.Evaluate(tt.expr)
			if err != nil {
				t.Fatalf("unexpected error: %v", err)
			}
			if result != tt.expected {
				t.Errorf("expected %v, got %v", tt.expected, result)
			}
		})
	}
}

func TestEvaluateLogicalOperators(t *testing.T) {
	eval := newTestEvaluator()

	tests := []struct {
		name     string
		expr     string
		expected bool
	}{
		// AND
		{"and both true", "$active == true && $age > 20", true},
		{"and first false", "$active == false && $age > 20", false},
		{"and second false", "$active == true && $age > 40", false},
		{"and both false", "$active == false && $age > 40", false},

		// OR
		{"or both true", "$active == true || $age > 40", true},
		{"or first true", "$active == true || $age > 40", true},
		{"or second true", "$active == false || $age > 20", true},
		{"or both false", "$active == false || $age > 40", false},

		// Negation
		{"not true", "!false", true},
		{"not false", "!true", false},
		{"not var true", "!$active", false},

		// Combined
		{"complex and or", "$age > 20 && $active == true || $score < 50", true},
	}

	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {
			result, err := eval.Evaluate(tt.expr)
			if err != nil {
				t.Fatalf("unexpected error: %v", err)
			}
			if result != tt.expected {
				t.Errorf("expected %v, got %v", tt.expected, result)
			}
		})
	}
}

func TestEvaluateArithmetic(t *testing.T) {
	eval := newTestEvaluator()

	tests := []struct {
		name     string
		expr     string
		expected float64
	}{
		{"addition", "10 + 5", 15},
		{"subtraction", "10 - 3", 7},
		{"multiplication", "4 * 3", 12},
		{"division", "15 / 3", 5},
		{"var addition", "$age + 5", 35},
		{"var subtraction", "$age - 10", 20},
		{"float arithmetic", "$score + 4.5", 90},
	}

	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {
			result, err := eval.Evaluate(tt.expr)
			if err != nil {
				t.Fatalf("unexpected error: %v", err)
			}
			if result != tt.expected {
				t.Errorf("expected %v, got %v", tt.expected, result)
			}
		})
	}
}

func TestEvaluateStringConcatenation(t *testing.T) {
	eval := newTestEvaluator()

	tests := []struct {
		name     string
		expr     string
		expected string
	}{
		{"concat strings", `"hello" + " world"`, "hello world"},
		{"concat var and string", `$name + " Smith"`, "Alice Smith"},
		{"concat string and var", `"User: " + $name`, "User: Alice"},
	}

	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {
			result, err := eval.Evaluate(tt.expr)
			if err != nil {
				t.Fatalf("unexpected error: %v", err)
			}
			if result != tt.expected {
				t.Errorf("expected %v, got %v", tt.expected, result)
			}
		})
	}
}

func TestEvaluateDivisionByZero(t *testing.T) {
	eval := newTestEvaluator()

	_, err := eval.Evaluate("10 / 0")
	if err == nil {
		t.Fatal("expected division by zero error")
	}
}

func TestEvaluateArrayIndexOutOfRange(t *testing.T) {
	eval := newTestEvaluator()

	_, err := eval.Evaluate("$items[10]")
	if err == nil {
		t.Fatal("expected index out of range error")
	}
}

func TestSetVariable(t *testing.T) {
	eval := newTestEvaluator()

	tests := []struct {
		name     string
		path     string
		value    interface{}
		checkVar string
		expected interface{}
	}{
		{"set simple var", "$newVar", "test value", "$newVar", "test value"},
		{"set nested field", "$user.email", "bob@test.com", "$user.email", "bob@test.com"},
		{"set int value", "$count", 100, "$count", 100},
		{"set bool value", "$flag", false, "$flag", false},
	}

	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {
			err := eval.SetVariable(tt.path, tt.value)
			if err != nil {
				t.Fatalf("unexpected error: %v", err)
			}
			result, err := eval.Evaluate(tt.checkVar)
			if err != nil {
				t.Fatalf("unexpected error reading back: %v", err)
			}
			if result != tt.expected {
				t.Errorf("expected %v, got %v", tt.expected, result)
			}
		})
	}
}

func TestSetVariableDeepSet(t *testing.T) {
	t.Run("array index then field - auto-create from scratch", func(t *testing.T) {
		// Simulates: $generated[0].name = "hello" with $generated not existing
		ctx := &ExecutionContext{
			Variables: map[string]interface{}{},
			LocalVars: map[string]interface{}{},
		}
		eval := NewExpressionEvaluator(ctx)

		err := eval.SetVariable("$generated[0].name", "hello")
		if err != nil {
			t.Fatalf("unexpected error: %v", err)
		}

		result, err := eval.Evaluate("$generated[0].name")
		if err != nil {
			t.Fatalf("unexpected error reading back: %v", err)
		}
		if result != "hello" {
			t.Errorf("expected 'hello', got %v", result)
		}
	})

	t.Run("array index then field - auto-grow existing array", func(t *testing.T) {
		// Simulates: $generated[2].name = "third" when $generated has only 1 element
		ctx := &ExecutionContext{
			Variables: map[string]interface{}{
				"$generated": []interface{}{
					map[string]interface{}{"name": "first"},
				},
			},
			LocalVars: map[string]interface{}{},
		}
		eval := NewExpressionEvaluator(ctx)

		err := eval.SetVariable("$generated[2].name", "third")
		if err != nil {
			t.Fatalf("unexpected error: %v", err)
		}

		result, err := eval.Evaluate("$generated[2].name")
		if err != nil {
			t.Fatalf("unexpected error reading back: %v", err)
		}
		if result != "third" {
			t.Errorf("expected 'third', got %v", result)
		}

		// First element should be untouched
		first, err := eval.Evaluate("$generated[0].name")
		if err != nil {
			t.Fatalf("unexpected error: %v", err)
		}
		if first != "first" {
			t.Errorf("expected 'first', got %v", first)
		}
	})

	t.Run("multiple fields on same array element", func(t *testing.T) {
		// Simulates loop iteration writing: $generated[1].name and $generated[1].code
		ctx := &ExecutionContext{
			Variables: map[string]interface{}{},
			LocalVars: map[string]interface{}{},
		}
		eval := NewExpressionEvaluator(ctx)

		if err := eval.SetVariable("$generated[1].name", "component"); err != nil {
			t.Fatalf("unexpected error: %v", err)
		}
		if err := eval.SetVariable("$generated[1].code", "export default {}"); err != nil {
			t.Fatalf("unexpected error: %v", err)
		}

		name, err := eval.Evaluate("$generated[1].name")
		if err != nil {
			t.Fatalf("unexpected error: %v", err)
		}
		if name != "component" {
			t.Errorf("expected 'component', got %v", name)
		}

		code, err := eval.Evaluate("$generated[1].code")
		if err != nil {
			t.Fatalf("unexpected error: %v", err)
		}
		if code != "export default {}" {
			t.Errorf("expected 'export default {}', got %v", code)
		}
	})

	t.Run("nested map auto-creation", func(t *testing.T) {
		// $config.database.host = "localhost"
		ctx := &ExecutionContext{
			Variables: map[string]interface{}{},
			LocalVars: map[string]interface{}{},
		}
		eval := NewExpressionEvaluator(ctx)

		err := eval.SetVariable("$config.database.host", "localhost")
		if err != nil {
			t.Fatalf("unexpected error: %v", err)
		}

		result, err := eval.Evaluate("$config.database.host")
		if err != nil {
			t.Fatalf("unexpected error: %v", err)
		}
		if result != "localhost" {
			t.Errorf("expected 'localhost', got %v", result)
		}
	})
}

func TestSetVariableErrors(t *testing.T) {
	eval := newTestEvaluator()

	tests := []struct {
		name  string
		path  string
		value interface{}
	}{
		{"empty path", "", "value"},
		{"local var", "_local", "value"},
	}

	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {
			err := eval.SetVariable(tt.path, tt.value)
			if err == nil {
				t.Fatal("expected error")
			}
		})
	}
}

func TestToBool(t *testing.T) {
	tests := []struct {
		name     string
		value    interface{}
		expected bool
	}{
		{"nil", nil, false},
		{"true", true, true},
		{"false", false, false},
		{"zero int", 0, false},
		{"nonzero int", 5, true},
		{"zero float", 0.0, false},
		{"nonzero float", 3.14, true},
		{"empty string", "", false},
		{"nonempty string", "hello", true},
		{"map", map[string]interface{}{}, true},
		{"slice", []interface{}{}, true},
	}

	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {
			result := toBool(tt.value)
			if result != tt.expected {
				t.Errorf("expected %v, got %v", tt.expected, result)
			}
		})
	}
}

func TestToFloat64(t *testing.T) {
	tests := []struct {
		name     string
		value    interface{}
		expected float64
	}{
		{"nil", nil, 0},
		{"int", 42, 42},
		{"int64", int64(100), 100},
		{"float64", 3.14, 3.14},
		{"float32", float32(2.5), 2.5},
		{"string number", "123", 123},
		{"string float", "45.67", 45.67},
		{"invalid string", "abc", 0},
	}

	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {
			result := toFloat64(tt.value)
			if result != tt.expected {
				t.Errorf("expected %v, got %v", tt.expected, result)
			}
		})
	}
}

func TestToString(t *testing.T) {
	tests := []struct {
		name     string
		value    interface{}
		expected string
	}{
		{"nil", nil, ""},
		{"string", "hello", "hello"},
		{"int", 42, "42"},
		{"float", 3.14, "3.14"},
		{"bool true", true, "true"},
		{"bool false", false, "false"},
	}

	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {
			result := toString(tt.value)
			if result != tt.expected {
				t.Errorf("expected %v, got %v", tt.expected, result)
			}
		})
	}
}

func TestIsString(t *testing.T) {
	tests := []struct {
		name     string
		value    interface{}
		expected bool
	}{
		{"string", "hello", true},
		{"int", 42, false},
		{"nil", nil, false},
		{"bool", true, false},
	}

	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {
			result := isString(tt.value)
			if result != tt.expected {
				t.Errorf("expected %v, got %v", tt.expected, result)
			}
		})
	}
}

func TestSetVariableObjectTypeConversionIntegration(t *testing.T) {
	t.Run("workflow with OBJECT type variable", func(t *testing.T) {
		// Create a workflow with an OBJECT type variable in the registry
		workflow := &Workflow{
			Version: "3.6",
			Name:    "TestOBJECTConversion",
			Registry: Registry{
				Vars: []string{
					"$config(OBJECT)",
					"$name(STRING)",
				},
			},
			Steps: []Step{
				{
					ID:     "Set_Config",
					Target: "$config",
					Value:  `{"host": "localhost", "port": 8080, "enabled": true}`,
					Next:   "Stop_End",
				},
				{
					ID: "Stop_End",
				},
			},
		}

		// Create engine and execute
		engine, err := NewEngine(workflow)
		if err != nil {
			t.Fatalf("failed to create engine: %v", err)
		}

		ctx := context.Background()
		adapters := &Adapters{}

		result, err := engine.Execute(ctx, map[string]interface{}{}, adapters)
		if err != nil {
			t.Fatalf("failed to execute workflow: %v", err)
		}

		// Wait for completion
		for event := range result.RunEventStream {
			if event.Type == RunEventWorkflowDone {
				break
			}
		}

		// Verify the config was converted to a map
		config, ok := result.Context.Variables["$config"]
		if !ok {
			t.Fatal("$config variable not set")
		}

		configMap, ok := config.(map[string]interface{})
		if !ok {
			t.Fatalf("expected $config to be map[string]interface{}, got %T", config)
		}

		if configMap["host"] != "localhost" {
			t.Errorf("expected host=localhost, got %v", configMap["host"])
		}
		if configMap["port"] != float64(8080) {
			t.Errorf("expected port=8080, got %v", configMap["port"])
		}
		if configMap["enabled"] != true {
			t.Errorf("expected enabled=true, got %v", configMap["enabled"])
		}
	})

	t.Run("workflow with invalid JSON for OBJECT type should fail", func(t *testing.T) {
		workflow := &Workflow{
			Version: "3.6",
			Name:    "TestOBJECTConversionError",
			Registry: Registry{
				Vars: []string{
					"$config(OBJECT)",
				},
			},
			Steps: []Step{
				{
					ID:     "Set_Config",
					Target: "$config",
					Value:  "invalid json string",
					Next:   "Stop_End",
				},
				{
					ID: "Stop_End",
				},
			},
		}

		engine, err := NewEngine(workflow)
		if err != nil {
			t.Fatalf("failed to create engine: %v", err)
		}

		ctx := context.Background()
		adapters := &Adapters{}

		result, err := engine.Execute(ctx, map[string]interface{}{}, adapters)
		if err != nil {
			t.Fatalf("failed to execute workflow: %v", err)
		}

		// Wait for failure
		foundError := false
		for event := range result.RunEventStream {
			if event.Type == RunEventWorkflowFailed {
				if strings.Contains(fmt.Sprintf("%v", event.Payload), "failed to convert string to OBJECT") {
					foundError = true
				}
				break
			}
		}

		if !foundError {
			t.Error("expected workflow to fail with conversion error")
		}
	})
}

func TestParamReferences(t *testing.T) {
	t.Run("read parameter value", func(t *testing.T) {
		ctx := &ExecutionContext{
			Params: map[string]interface{}{
				"userId": "user123",
				"limit":  10,
			},
			Variables: map[string]interface{}{},
			LocalVars: map[string]interface{}{},
		}
		eval := NewExpressionEvaluator(ctx)

		// Evaluate parameter reference
		result, err := eval.Evaluate("userId")
		if err != nil {
			t.Fatalf("unexpected error: %v", err)
		}

		if result != "user123" {
			t.Errorf("expected 'user123', got %v", result)
		}

		// Evaluate numeric parameter
		result, err = eval.Evaluate("limit")
		if err != nil {
			t.Fatalf("unexpected error: %v", err)
		}

		if result != 10 {
			t.Errorf("expected 10, got %v", result)
		}
	})

	t.Run("use parameter in expression", func(t *testing.T) {
		ctx := &ExecutionContext{
			Params: map[string]interface{}{
				"maxCount": 100,
			},
			Variables: map[string]interface{}{},
			LocalVars: map[string]interface{}{},
		}
		eval := NewExpressionEvaluator(ctx)

		// Use parameter in arithmetic
		result, err := eval.Evaluate("maxCount + 50")
		if err != nil {
			t.Fatalf("unexpected error: %v", err)
		}

		if result != float64(150) {
			t.Errorf("expected 150, got %v", result)
		}
	})

	t.Run("access nested parameter fields", func(t *testing.T) {
		ctx := &ExecutionContext{
			Params: map[string]interface{}{
				"config": map[string]interface{}{
					"host": "localhost",
					"port": 8080,
				},
			},
			Variables: map[string]interface{}{},
			LocalVars: map[string]interface{}{},
		}
		eval := NewExpressionEvaluator(ctx)

		// Access nested field
		result, err := eval.Evaluate("config.host")
		if err != nil {
			t.Fatalf("unexpected error: %v", err)
		}

		if result != "localhost" {
			t.Errorf("expected 'localhost', got %v", result)
		}
	})

	t.Run("cannot modify parameter", func(t *testing.T) {
		ctx := &ExecutionContext{
			Params: map[string]interface{}{
				"userId": "user123",
			},
			Variables: map[string]interface{}{},
			LocalVars: map[string]interface{}{},
		}
		eval := NewExpressionEvaluator(ctx)

		// Try to set a parameter value
		err := eval.SetVariable("userId", "newValue")
		if err == nil {
			t.Fatal("expected error when trying to modify parameter")
		}

		if !strings.Contains(err.Error(), "cannot modify parameter") {
			t.Errorf("expected 'cannot modify parameter' error, got: %v", err)
		}

		// Verify parameter unchanged
		if ctx.Params["userId"] != "user123" {
			t.Errorf("parameter was modified")
		}
	})

	t.Run("error on undefined parameter", func(t *testing.T) {
		ctx := &ExecutionContext{
			Params:    map[string]interface{}{},
			Variables: map[string]interface{}{},
			LocalVars: map[string]interface{}{},
		}
		eval := NewExpressionEvaluator(ctx)

		// Try to access undefined parameter
		_, err := eval.Evaluate("undefinedParam")
		if err == nil {
			t.Fatal("expected error for undefined parameter")
		}

		if !strings.Contains(err.Error(), "parameter not found") {
			t.Errorf("expected 'parameter not found' error, got: %v", err)
		}
	})
}

func TestParamIntegration(t *testing.T) {
	t.Run("OBJECT parameter type conversion on init", func(t *testing.T) {
		workflow := &Workflow{
			Version: "3.6",
			Name:    "TestParamOBJECTConversion",
			Registry: Registry{
				Params: []string{
					"config(OBJECT)",
				},
				Vars: []string{
					"$result(STRING)",
				},
			},
			Steps: []Step{
				{
					ID:     "Set_Result",
					Target: "$result",
					Value:  "=config.host",
					Next:   "Stop_End",
				},
				{
					ID: "Stop_End",
				},
			},
		}

		engine, err := NewEngine(workflow)
		if err != nil {
			t.Fatalf("failed to create engine: %v", err)
		}

		ctx := context.Background()
		adapters := &Adapters{}

		// Pass config as JSON string - should be converted to map
		result, err := engine.Execute(ctx, map[string]interface{}{
			"config": `{"host": "api.example.com", "port": 443}`,
		}, adapters)
		if err != nil {
			t.Fatalf("failed to execute workflow: %v", err)
		}

		// Wait for completion
		for event := range result.RunEventStream {
			if event.Type == RunEventWorkflowDone {
				break
			}
		}

		// Verify parameter was converted to map
		config, ok := result.Context.Params["config"]
		if !ok {
			t.Fatal("config parameter not set")
		}

		configMap, ok := config.(map[string]interface{})
		if !ok {
			t.Fatalf("expected config to be map[string]interface{}, got %T", config)
		}

		if configMap["host"] != "api.example.com" {
			t.Errorf("expected host=api.example.com, got %v", configMap["host"])
		}

		// Verify the nested access worked in expression
		if result.Context.Variables["$result"] != "api.example.com" {
			t.Errorf("expected $result=api.example.com, got %v", result.Context.Variables["$result"])
		}
	})

	t.Run("workflow with parameters", func(t *testing.T) {
		workflow := &Workflow{
			Version: "3.6",
			Name:    "TestParams",
			Registry: Registry{
				Params: []string{
					"userId(STRING)",
					"maxLimit(INT)",
				},
				Vars: []string{
					"$result(STRING)",
				},
			},
			Steps: []Step{
				{
					ID:     "Set_Result",
					Target: "$result",
					Value:  "=userId",
					Next:   "Stop_End",
				},
				{
					ID: "Stop_End",
				},
			},
		}

		engine, err := NewEngine(workflow)
		if err != nil {
			t.Fatalf("failed to create engine: %v", err)
		}

		ctx := context.Background()
		adapters := &Adapters{}

		// Pass parameters through initialVars
		result, err := engine.Execute(ctx, map[string]interface{}{
			"userId":   "user123",
			"maxLimit": 100,
		}, adapters)
		if err != nil {
			t.Fatalf("failed to execute workflow: %v", err)
		}

		// Wait for completion
		for event := range result.RunEventStream {
			if event.Type == RunEventWorkflowDone {
				break
			}
		}

		// Verify parameter was accessible and result was set
		if result.Context.Params["userId"] != "user123" {
			t.Errorf("expected userId=user123, got %v", result.Context.Params["userId"])
		}

		if result.Context.Variables["$result"] != "user123" {
			t.Errorf("expected $result=user123, got %v", result.Context.Variables["$result"])
		}
	})

	t.Run("invalid JSON for OBJECT parameter on init", func(t *testing.T) {
		workflow := &Workflow{
			Version: "3.6",
			Name:    "TestParamOBJECTConversionError",
			Registry: Registry{
				Params: []string{
					"config(OBJECT)",
				},
			},
			Steps: []Step{
				{
					ID: "Stop_End",
				},
			},
		}

		engine, err := NewEngine(workflow)
		if err != nil {
			t.Fatalf("failed to create engine: %v", err)
		}

		ctx := context.Background()
		adapters := &Adapters{}

		// Pass invalid JSON for OBJECT parameter
		_, err = engine.Execute(ctx, map[string]interface{}{
			"config": "not valid json",
		}, adapters)

		if err == nil {
			t.Fatal("expected error for invalid JSON in OBJECT parameter")
		}

		if !strings.Contains(err.Error(), "failed to convert parameter config to OBJECT") {
			t.Errorf("expected conversion error, got: %v", err)
		}
	})

	t.Run("workflow cannot modify parameter", func(t *testing.T) {
		workflow := &Workflow{
			Version: "3.6",
			Name:    "TestParamReadOnly",
			Registry: Registry{
				Params: []string{
					"userId(STRING)",
				},
			},
			Steps: []Step{
				{
					ID:     "Set_Param",
					Target: "userId",
					Value:  "newValue",
					Next:   "Stop_End",
				},
				{
					ID: "Stop_End",
				},
			},
		}

		engine, err := NewEngine(workflow)
		if err != nil {
			t.Fatalf("failed to create engine: %v", err)
		}

		ctx := context.Background()
		adapters := &Adapters{}

		result, err := engine.Execute(ctx, map[string]interface{}{
			"userId": "user123",
		}, adapters)
		if err != nil {
			t.Fatalf("failed to execute workflow: %v", err)
		}

		// Wait for failure
		foundError := false
		for event := range result.RunEventStream {
			if event.Type == RunEventWorkflowFailed {
				if strings.Contains(fmt.Sprintf("%v", event.Payload), "cannot modify parameter") {
					foundError = true
				}
				break
			}
		}

		if !foundError {
			t.Error("expected workflow to fail when trying to modify parameter")
		}
	})
}

func TestSetVariableObjectTypeConversion(t *testing.T) {
	t.Run("convert string to map for OBJECT type", func(t *testing.T) {
		ctx := &ExecutionContext{
			Variables: map[string]interface{}{},
			LocalVars: map[string]interface{}{},
			VarTypes: map[string]string{
				"$config": "OBJECT",
			},
		}
		eval := NewExpressionEvaluator(ctx)

		// Set a string value to an OBJECT type variable
		jsonStr := `{"host": "localhost", "port": 8080}`
		err := eval.SetVariable("$config", jsonStr)
		if err != nil {
			t.Fatalf("unexpected error: %v", err)
		}

		// Verify it was converted to a map
		result, ok := ctx.Variables["$config"]
		if !ok {
			t.Fatal("variable not set")
		}

		resultMap, ok := result.(map[string]interface{})
		if !ok {
			t.Fatalf("expected map[string]interface{}, got %T", result)
		}

		if resultMap["host"] != "localhost" {
			t.Errorf("expected host=localhost, got %v", resultMap["host"])
		}
		if resultMap["port"] != float64(8080) {
			t.Errorf("expected port=8080, got %v", resultMap["port"])
		}
	})

	t.Run("error on invalid JSON for OBJECT type", func(t *testing.T) {
		ctx := &ExecutionContext{
			Variables: map[string]interface{}{},
			LocalVars: map[string]interface{}{},
			VarTypes: map[string]string{
				"$config": "OBJECT",
			},
		}
		eval := NewExpressionEvaluator(ctx)

		// Try to set an invalid JSON string
		err := eval.SetVariable("$config", "not valid json")
		if err == nil {
			t.Fatal("expected error for invalid JSON")
		}

		if !strings.Contains(err.Error(), "failed to convert string to OBJECT") {
			t.Errorf("expected conversion error, got: %v", err)
		}
	})

	t.Run("no conversion for non-string values", func(t *testing.T) {
		ctx := &ExecutionContext{
			Variables: map[string]interface{}{},
			LocalVars: map[string]interface{}{},
			VarTypes: map[string]string{
				"$config": "OBJECT",
			},
		}
		eval := NewExpressionEvaluator(ctx)

		// Set a map directly (no conversion needed)
		mapValue := map[string]interface{}{"key": "value"}
		err := eval.SetVariable("$config", mapValue)
		if err != nil {
			t.Fatalf("unexpected error: %v", err)
		}

		// Verify it's the same map
		result, ok := ctx.Variables["$config"]
		if !ok {
			t.Fatal("variable not set")
		}

		resultMap, ok := result.(map[string]interface{})
		if !ok {
			t.Fatalf("expected map[string]interface{}, got %T", result)
		}

		if resultMap["key"] != "value" {
			t.Errorf("expected key=value, got %v", resultMap["key"])
		}
	})

	t.Run("no conversion for non-OBJECT types", func(t *testing.T) {
		ctx := &ExecutionContext{
			Variables: map[string]interface{}{},
			LocalVars: map[string]interface{}{},
			VarTypes: map[string]string{
				"$name": "STRING",
			},
		}
		eval := NewExpressionEvaluator(ctx)

		// Set a string value to a STRING type variable (no conversion)
		err := eval.SetVariable("$name", `{"not": "converted"}`)
		if err != nil {
			t.Fatalf("unexpected error: %v", err)
		}

		// Verify it's still a string
		result, ok := ctx.Variables["$name"]
		if !ok {
			t.Fatal("variable not set")
		}

		if _, ok := result.(string); !ok {
			t.Fatalf("expected string, got %T", result)
		}
	})

	t.Run("no conversion when VarTypes is nil", func(t *testing.T) {
		ctx := &ExecutionContext{
			Variables: map[string]interface{}{},
			LocalVars: map[string]interface{}{},
			VarTypes:  nil,
		}
		eval := NewExpressionEvaluator(ctx)

		// Set a string value (no conversion without type info)
		err := eval.SetVariable("$config", `{"key": "value"}`)
		if err != nil {
			t.Fatalf("unexpected error: %v", err)
		}

		// Verify it's still a string
		result, ok := ctx.Variables["$config"]
		if !ok {
			t.Fatal("variable not set")
		}

		if _, ok := result.(string); !ok {
			t.Fatalf("expected string, got %T", result)
		}
	})
}

func TestEvaluateJSONLiterals(t *testing.T) {
	eval := newTestEvaluator()

	t.Run("array of objects", func(t *testing.T) {
		result, err := eval.Evaluate(`[{"label":"Alpha"},{"label":"Beta"},{"label":"Gamma"}]`)
		if err != nil {
			t.Fatalf("unexpected error: %v", err)
		}

		arr, ok := result.([]interface{})
		if !ok {
			t.Fatalf("expected []interface{}, got %T", result)
		}
		if len(arr) != 3 {
			t.Fatalf("expected 3 elements, got %d", len(arr))
		}

		first, ok := arr[0].(map[string]interface{})
		if !ok {
			t.Fatalf("expected map[string]interface{}, got %T", arr[0])
		}
		if first["label"] != "Alpha" {
			t.Errorf("expected Alpha, got %v", first["label"])
		}
	})

	t.Run("simple array", func(t *testing.T) {
		result, err := eval.Evaluate(`[1, 2, 3]`)
		if err != nil {
			t.Fatalf("unexpected error: %v", err)
		}

		arr, ok := result.([]interface{})
		if !ok {
			t.Fatalf("expected []interface{}, got %T", result)
		}
		if len(arr) != 3 {
			t.Fatalf("expected 3 elements, got %d", len(arr))
		}
		if arr[0] != float64(1) {
			t.Errorf("expected 1, got %v", arr[0])
		}
	})

	t.Run("object literal", func(t *testing.T) {
		result, err := eval.Evaluate(`{"key":"value","count":42}`)
		if err != nil {
			t.Fatalf("unexpected error: %v", err)
		}

		obj, ok := result.(map[string]interface{})
		if !ok {
			t.Fatalf("expected map[string]interface{}, got %T", result)
		}
		if obj["key"] != "value" {
			t.Errorf("expected 'value', got %v", obj["key"])
		}
		if obj["count"] != float64(42) {
			t.Errorf("expected 42, got %v", obj["count"])
		}
	})

	t.Run("empty array", func(t *testing.T) {
		result, err := eval.Evaluate(`[]`)
		if err != nil {
			t.Fatalf("unexpected error: %v", err)
		}

		arr, ok := result.([]interface{})
		if !ok {
			t.Fatalf("expected []interface{}, got %T", result)
		}
		if len(arr) != 0 {
			t.Errorf("expected empty array, got %d elements", len(arr))
		}
	})

	t.Run("empty object", func(t *testing.T) {
		result, err := eval.Evaluate(`{}`)
		if err != nil {
			t.Fatalf("unexpected error: %v", err)
		}

		obj, ok := result.(map[string]interface{})
		if !ok {
			t.Fatalf("expected map[string]interface{}, got %T", result)
		}
		if len(obj) != 0 {
			t.Errorf("expected empty object, got %d keys", len(obj))
		}
	})

	t.Run("via EvaluateValue with = prefix", func(t *testing.T) {
		result, err := eval.EvaluateValue(`=[{"label":"Alpha"},{"label":"Beta"},{"label":"Gamma"}]`)
		if err != nil {
			t.Fatalf("unexpected error: %v", err)
		}

		arr, ok := result.([]interface{})
		if !ok {
			t.Fatalf("expected []interface{}, got %T", result)
		}
		if len(arr) != 3 {
			t.Fatalf("expected 3 elements, got %d", len(arr))
		}
	})

	t.Run("nested array of objects", func(t *testing.T) {
		result, err := eval.Evaluate(`[{"items":[1,2,3]},{"items":[4,5,6]}]`)
		if err != nil {
			t.Fatalf("unexpected error: %v", err)
		}

		arr, ok := result.([]interface{})
		if !ok {
			t.Fatalf("expected []interface{}, got %T", result)
		}
		if len(arr) != 2 {
			t.Fatalf("expected 2 elements, got %d", len(arr))
		}

		first, ok := arr[0].(map[string]interface{})
		if !ok {
			t.Fatalf("expected map, got %T", arr[0])
		}
		items, ok := first["items"].([]interface{})
		if !ok {
			t.Fatalf("expected []interface{}, got %T", first["items"])
		}
		if len(items) != 3 {
			t.Errorf("expected 3 items, got %d", len(items))
		}
	})
}
