package ucca

import (
	"testing"
)

func TestConditionEngine_NilNode(t *testing.T) {
	engine := NewObligationConditionEngine()
	facts := NewUnifiedFacts()
	if !engine.Evaluate(nil, facts) {
		t.Error("nil node should return true (always applies)")
	}
}

func TestConditionEngine_LeafEquals(t *testing.T) {
	engine := NewObligationConditionEngine()

	tests := []struct {
		name     string
		field    string
		value    interface{}
		facts    func() *UnifiedFacts
		expected bool
	}{
		{
			name: "is_controller true",
			field: "data_protection.is_controller", value: true,
			facts: func() *UnifiedFacts {
				f := NewUnifiedFacts()
				f.DataProtection.IsController = true
				return f
			},
			expected: true,
		},
		{
			name: "is_controller false mismatch",
			field: "data_protection.is_controller", value: true,
			facts:    func() *UnifiedFacts { return NewUnifiedFacts() },
			expected: false,
		},
		{
			name: "employee_count equals",
			field: "organization.employee_count", value: float64(50),
			facts: func() *UnifiedFacts {
				f := NewUnifiedFacts()
				f.Organization.EmployeeCount = 50
				return f
			},
			expected: true,
		},
		{
			name: "uses_ai true",
			field: "ai_usage.uses_ai", value: true,
			facts: func() *UnifiedFacts {
				f := NewUnifiedFacts()
				f.AIUsage.UsesAI = true
				return f
			},
			expected: true,
		},
	}

	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {
			node := &ConditionNode{
				Field:    tt.field,
				Operator: "EQUALS",
				Value:    tt.value,
			}
			result := engine.Evaluate(node, tt.facts())
			if result != tt.expected {
				t.Errorf("expected %v, got %v", tt.expected, result)
			}
		})
	}
}

func TestConditionEngine_GreaterThan(t *testing.T) {
	engine := NewObligationConditionEngine()
	facts := NewUnifiedFacts()
	facts.Organization.EmployeeCount = 50

	node := &ConditionNode{
		Field:    "organization.employee_count",
		Operator: "GREATER_THAN",
		Value:    float64(19),
	}
	if !engine.Evaluate(node, facts) {
		t.Error("50 > 19 should be true")
	}

	facts.Organization.EmployeeCount = 10
	if engine.Evaluate(node, facts) {
		t.Error("10 > 19 should be false")
	}
}

func TestConditionEngine_AllOf(t *testing.T) {
	engine := NewObligationConditionEngine()
	facts := NewUnifiedFacts()
	facts.DataProtection.IsController = true
	facts.DataProtection.ProcessesSpecialCategories = true

	node := &ConditionNode{
		AllOf: []ConditionNode{
			{Field: "data_protection.is_controller", Operator: "EQUALS", Value: true},
			{Field: "data_protection.processes_special_categories", Operator: "EQUALS", Value: true},
		},
	}

	if !engine.Evaluate(node, facts) {
		t.Error("all_of with both true should be true")
	}

	facts.DataProtection.ProcessesSpecialCategories = false
	if engine.Evaluate(node, facts) {
		t.Error("all_of with one false should be false")
	}
}

func TestConditionEngine_AnyOf(t *testing.T) {
	engine := NewObligationConditionEngine()
	facts := NewUnifiedFacts()
	facts.DataProtection.RequiresDSBByLaw = false

	node := &ConditionNode{
		AnyOf: []ConditionNode{
			{Field: "data_protection.needs_dpo", Operator: "EQUALS", Value: true},
			{Field: "organization.employee_count", Operator: "GREATER_THAN", Value: float64(19)},
		},
	}

	if engine.Evaluate(node, facts) {
		t.Error("any_of with both false should be false")
	}

	facts.Organization.EmployeeCount = 25
	if !engine.Evaluate(node, facts) {
		t.Error("any_of with one true should be true")
	}
}

func TestConditionEngine_UnknownField(t *testing.T) {
	engine := NewObligationConditionEngine()
	facts := NewUnifiedFacts()

	node := &ConditionNode{
		Field:    "nonexistent.field",
		Operator: "EQUALS",
		Value:    true,
	}

	if engine.Evaluate(node, facts) {
		t.Error("unknown field should return false")
	}
}

func TestConditionEngine_NotEquals(t *testing.T) {
	engine := NewObligationConditionEngine()
	facts := NewUnifiedFacts()
	facts.Organization.Country = "DE"

	node := &ConditionNode{
		Field:    "organization.country",
		Operator: "NOT_EQUALS",
		Value:    "US",
	}
	if !engine.Evaluate(node, facts) {
		t.Error("DE != US should be true")
	}

	node.Value = "DE"
	if engine.Evaluate(node, facts) {
		t.Error("DE != DE should be false")
	}
}
