package automation

import "testing"

// Table-driven tests for evaluateConditionLogic — the public entry point
// the flow engine uses to combine per-condition booleans.
//
// Regression target: issue #2233 — engine previously folded all conditions
// with plain AND, ignoring `(N OR M) AND K` style expressions and silently
// no-op'ing rules whose conditionLogic deviated from "and"/"or".
func TestEvaluateConditionLogic(t *testing.T) {
	cases := []struct {
		name    string
		logic   string
		results []bool
		want    bool
	}{
		// Trivial / legacy cases preserved by the new evaluator.
		{"empty defaults to AND — all true", "", []bool{true, true, true}, true},
		{"empty defaults to AND — one false", "", []bool{true, false, true}, false},
		{"and lowercase legacy — all true", "and", []bool{true, true}, true},
		{"and uppercase — one false", "AND", []bool{true, false}, false},
		{"or lowercase legacy — one true", "or", []bool{false, true, false}, true},
		{"or uppercase — all false", "OR", []bool{false, false}, false},

		// 1-indexed AND
		{"1 AND 2 — all true", "1 AND 2", []bool{true, true}, true},
		{"1 AND 2 — second false", "1 AND 2", []bool{true, false}, false},

		// OR
		{"1 OR 2 — first true", "1 OR 2", []bool{true, false}, true},
		{"1 OR 2 — neither true", "1 OR 2", []bool{false, false}, false},

		// Issue #2233 canonical case: (1 OR 2) AND 3
		{"(1 OR 2) AND 3 — c1 true c3 true", "(1 OR 2) AND 3", []bool{true, false, true}, true},
		{"(1 OR 2) AND 3 — c2 true c3 true", "(1 OR 2) AND 3", []bool{false, true, true}, true},
		{"(1 OR 2) AND 3 — neither c1 nor c2", "(1 OR 2) AND 3", []bool{false, false, true}, false},
		{"(1 OR 2) AND 3 — c1 true c3 false", "(1 OR 2) AND 3", []bool{true, false, false}, false},

		// NOT
		{"NOT 1 — false condition flipped to true", "NOT 1", []bool{false}, true},
		{"NOT 1 — true condition flipped to false", "NOT 1", []bool{true}, false},
		{"NOT 1 AND 2 — c1 false c2 true", "NOT 1 AND 2", []bool{false, true}, true},
		{"NOT 1 AND 2 — c1 true c2 true", "NOT 1 AND 2", []bool{true, true}, false},
		{"NOT (1 OR 2) — both false", "NOT (1 OR 2)", []bool{false, false}, true},
		{"NOT (1 OR 2) — c1 true", "NOT (1 OR 2)", []bool{true, false}, false},

		// Mixed precedence — AND binds tighter than OR.
		{"1 OR 2 AND 3 — c1 true rest false", "1 OR 2 AND 3", []bool{true, false, false}, true},
		{"1 OR 2 AND 3 — c2 c3 true c1 false", "1 OR 2 AND 3", []bool{false, true, true}, true},
		{"1 OR 2 AND 3 — c2 true c3 false c1 false", "1 OR 2 AND 3", []bool{false, true, false}, false},

		// Whitespace tolerance
		{"  1   AND   2  spaces", "  1   AND   2  ", []bool{true, true}, true},

		// Mixed-case keywords (Salesforce admins write any of these in practice)
		{"mixed-case 'and'", "1 AnD 2", []bool{true, true}, true},
		{"mixed-case 'or'", "1 oR 2", []bool{false, true}, true},
		{"mixed-case 'not'", "noT 1", []bool{false}, true},

		// Out-of-range index — fail closed. Validation runs before evaluation
		// so OR / NOT short-circuiting cannot silently swallow a bad ref.
		{"index out of range (AND)", "1 AND 4", []bool{true, true, true}, false},
		{"index out of range (OR short-circuit hidden)", "1 OR 4", []bool{true, true, true}, false},
		{"index out of range (OR right-side)", "4 OR 1", []bool{true, true, true}, false},
		{"index out of range (NOT)", "NOT 5", []bool{true, true, true}, false},
		{"index out of range (nested in OR)", "1 OR (2 AND 9)", []bool{true, true, true}, false},

		// Malformed input — fail closed (rules with broken logic must not fire).
		{"malformed: trailing AND", "1 AND", []bool{true}, false},
		{"malformed: bare paren", "(1 AND 2", []bool{true, true}, false},
		{"malformed: extra close paren", "1 AND 2)", []bool{true, true}, false},
		{"malformed: unknown keyword", "1 XOR 2", []bool{true, true}, false},
		{"malformed: zero index", "0 AND 1", []bool{true, true}, false},
		{"malformed: empty parens", "()", []bool{}, false},
	}

	for _, tc := range cases {
		t.Run(tc.name, func(t *testing.T) {
			got := evaluateConditionLogic(tc.logic, tc.results)
			if got != tc.want {
				t.Errorf("evaluateConditionLogic(%q, %v) = %v, want %v", tc.logic, tc.results, got, tc.want)
			}
		})
	}
}
