package formula

import (
	"testing"
)

// ---------------------------------------------------------------------------
// ExtractPermissionKeys — unit tests (Issue #609)
// ---------------------------------------------------------------------------

func TestExtractPermissionKeys_SingleKey(t *testing.T) {
	keys := ExtractPermissionKeys("$Permission.ActivateOrder == true")
	if len(keys) != 1 || keys[0] != "ActivateOrder" {
		t.Errorf("got %v; want [ActivateOrder]", keys)
	}
}

func TestExtractPermissionKeys_MultipleDistinctKeys(t *testing.T) {
	expr := "AND($Permission.ActivateOrder, $Permission.ActivateContract)"
	keys := ExtractPermissionKeys(expr)
	if len(keys) != 2 {
		t.Fatalf("got %d keys; want 2: %v", len(keys), keys)
	}
	seen := map[string]bool{}
	for _, k := range keys {
		seen[k] = true
	}
	if !seen["ActivateOrder"] || !seen["ActivateContract"] {
		t.Errorf("expected ActivateOrder and ActivateContract; got %v", keys)
	}
}

func TestExtractPermissionKeys_Deduplication(t *testing.T) {
	expr := "AND($Permission.Foo, $Permission.Foo, $Permission.Bar)"
	keys := ExtractPermissionKeys(expr)
	if len(keys) != 2 {
		t.Errorf("got %d keys after dedup; want 2: %v", len(keys), keys)
	}
}

func TestExtractPermissionKeys_InsideStringLiteral_NotMatched(t *testing.T) {
	// $Permission.X inside a quoted string must NOT be extracted.
	expr := `"$Permission.ShouldNotMatch" == "literal"`
	keys := ExtractPermissionKeys(expr)
	if len(keys) != 0 {
		t.Errorf("extracted keys from string literal; want none: %v", keys)
	}
}

func TestExtractPermissionKeys_NoPermission(t *testing.T) {
	keys := ExtractPermissionKeys("$User.Name == 'Alice'")
	if len(keys) != 0 {
		t.Errorf("got %v; want nil/empty for expression without $Permission", keys)
	}
}

func TestExtractPermissionKeys_Empty(t *testing.T) {
	keys := ExtractPermissionKeys("")
	if len(keys) != 0 {
		t.Errorf("got %v; want nil/empty for empty expression", keys)
	}
}

// ---------------------------------------------------------------------------
// InjectSuperUserPermissions — unit tests (Issue #609)
// ---------------------------------------------------------------------------

func TestInjectSuperUserPermissions_SuperUser_InjectsKeys(t *testing.T) {
	vars := map[string]interface{}{}
	InjectSuperUserPermissions(vars, "$Permission.CustomPerm == true", true)

	permMap, ok := vars["__Permission"].(map[string]bool)
	if !ok {
		t.Fatalf("__Permission not a map[string]bool after inject; got %T", vars["__Permission"])
	}
	if !permMap["CustomPerm"] {
		t.Errorf("__Permission[CustomPerm] = false; want true for super-user")
	}
}

func TestInjectSuperUserPermissions_NonSuperUser_NoOp(t *testing.T) {
	vars := map[string]interface{}{}
	InjectSuperUserPermissions(vars, "$Permission.CustomPerm == true", false)

	if _, ok := vars["__Permission"]; ok {
		t.Errorf("__Permission was set for non-super-user; want absent (no-op)")
	}
}

func TestInjectSuperUserPermissions_NoPermissionKeys_NoOp(t *testing.T) {
	vars := map[string]interface{}{}
	InjectSuperUserPermissions(vars, "$User.Name == 'Alice'", true)

	if _, ok := vars["__Permission"]; ok {
		t.Errorf("__Permission was set for expression with no $Permission refs; want absent")
	}
}

func TestInjectSuperUserPermissions_ExistingPermMap_Merged(t *testing.T) {
	// Pre-existing __Permission map should be extended, not replaced.
	vars := map[string]interface{}{
		"__Permission": map[string]bool{
			"ExistingPerm": true,
		},
	}
	InjectSuperUserPermissions(vars, "$Permission.NewPerm", true)

	permMap := vars["__Permission"].(map[string]bool)
	if !permMap["ExistingPerm"] {
		t.Errorf("ExistingPerm was removed; merge must preserve existing entries")
	}
	if !permMap["NewPerm"] {
		t.Errorf("NewPerm not added; merge must inject new super-user keys")
	}
}

func TestInjectSuperUserPermissions_MultipleKeys_AllTrue(t *testing.T) {
	vars := map[string]interface{}{}
	expr := "AND($Permission.Perm_A, $Permission.Perm_B, $Permission.Perm_C)"
	InjectSuperUserPermissions(vars, expr, true)

	permMap, ok := vars["__Permission"].(map[string]bool)
	if !ok {
		t.Fatalf("__Permission not a map[string]bool; got %T", vars["__Permission"])
	}
	for _, key := range []string{"Perm_A", "Perm_B", "Perm_C"} {
		if !permMap[key] {
			t.Errorf("__Permission[%s] = false; want true for super-user", key)
		}
	}
}
