package permissions

import (
	"bytes"
	"reflect"
	"strings"
	"testing"
)

func TestDecodePermissionSetAssignmentPolicyIsStrictAndCanonical(t *testing.T) {
	policy, err := DecodePermissionSetAssignmentPolicy([]byte(`{
		"schema":"nexuscrm.permission-set-assignment-policy/v1",
		"permissionSet":"Sales_User",
		"profiles_any_of":["System Administrator","Standard User"]
	}`))
	if err != nil {
		t.Fatal(err)
	}
	if policy.PermissionSet != "Sales_User" ||
		!reflect.DeepEqual(policy.ProfilesAnyOf, []string{"Standard User", "System Administrator"}) {
		t.Fatalf("policy = %#v", policy)
	}

	for _, payload := range []string{
		`{"schema":"nexuscrm.permission-set-assignment-policy/v1","permissionSet":"P","profiles_any_of":[]}`,
		`{"schema":"nexuscrm.permission-set-assignment-policy/v1","permissionSet":"P","profiles_any_of":["Sales","sales"]}`,
		`{"schema":"nexuscrm.permission-set-assignment-policy/v1","permissionSet":"P","profiles_any_of":["Cafe","Café"]}`,
		`{"schema":"nexuscrm.permission-set-assignment-policy/v1","permissionSet":"P","profiles_any_of":["Sales","Ｓａｌｅｓ"]}`,
		`{"schema":"nexuscrm.permission-set-assignment-policy/v1","permissionSet":"P","profiles_any_of":["Sales"],"allUsers":true}`,
		`{"schema":"wrong","permissionSet":"P","profiles_any_of":["Sales"]}`,
		`{"schema":"nexuscrm.permission-set-assignment-policy/v1","permissionSet":"P","profiles_any_of":[" Standard User"]}`,
		`{"schema":"nexuscrm.permission-set-assignment-policy/v1","permissionSet":"P","profiles_any_of":["Standard User "]}`,
		"{\"schema\":\"nexuscrm.permission-set-assignment-policy/v1\",\"permissionSet\":\"P\",\"profiles_any_of\":[\"Standard\\u0000User\"]}",
		`{"schema":"nexuscrm.permission-set-assignment-policy/v1","permissionSet":"P","profiles_any_of":["Sales"]} {}`,
	} {
		if _, err := DecodePermissionSetAssignmentPolicy([]byte(payload)); err == nil {
			t.Fatalf("DecodePermissionSetAssignmentPolicy(%s) succeeded", payload)
		}
	}
}

func TestAssignmentPolicySourceTargetIsPerPolicyCanonicalAndDelimiterSafe(t *testing.T) {
	first, err := NewPermissionSetAssignmentPolicySource("Sales-Pack", "Policy-A")
	if err != nil {
		t.Fatal(err)
	}
	same, err := NewPermissionSetAssignmentPolicySource("sales-pack", "policy-a")
	if err != nil {
		t.Fatal(err)
	}
	other, err := NewPermissionSetAssignmentPolicySource("Sales-Pack", "Policy-B")
	if err != nil {
		t.Fatal(err)
	}
	if !reflect.DeepEqual(first.ManagedTarget(), same.ManagedTarget()) {
		t.Fatalf("case variants differ: %#v / %#v", first.ManagedTarget(), same.ManagedTarget())
	}
	accentVariant, err := NewPermissionSetAssignmentPolicySource("sales-pack", "policy-á")
	if err != nil {
		t.Fatal(err)
	}
	plainVariant, err := NewPermissionSetAssignmentPolicySource("sales-pack", "policy-a")
	if err != nil {
		t.Fatal(err)
	}
	if !reflect.DeepEqual(accentVariant.ManagedTarget(), plainVariant.ManagedTarget()) {
		t.Fatalf("database-collated variants differ: %#v / %#v", accentVariant.ManagedTarget(), plainVariant.ManagedTarget())
	}
	widthVariant, err := NewPermissionSetAssignmentPolicySource("sales-pack", "ｐｏｌｉｃｙ-a")
	if err != nil {
		t.Fatal(err)
	}
	if !reflect.DeepEqual(widthVariant.ManagedTarget(), plainVariant.ManagedTarget()) {
		t.Fatalf("database-collated width variants differ: %#v / %#v", widthVariant.ManagedTarget(), plainVariant.ManagedTarget())
	}
	if reflect.DeepEqual(first.ManagedTarget(), other.ManagedTarget()) {
		t.Fatalf("independent policies share target %#v", first.ManagedTarget())
	}
	left, err := NewPermissionSetAssignmentPolicySource("a", "b_c")
	if err != nil {
		t.Fatal(err)
	}
	right, err := NewPermissionSetAssignmentPolicySource("a_b", "c")
	if err != nil {
		t.Fatal(err)
	}
	if bytes.Equal(left.ManagedTarget().PhysicalKeyBytes, right.ManagedTarget().PhysicalKeyBytes) {
		t.Fatal("length-delimited source identities collided")
	}
}

func TestAssignmentPolicyManagedTargetsReuseDefinitionIdentity(t *testing.T) {
	source, err := NewPermissionSetAssignmentPolicySource("Sales_Pack", "Policy_A")
	if err != nil {
		t.Fatal(err)
	}
	policy := PermissionSetAssignmentPolicy{
		Schema:        PermissionSetAssignmentPolicySchema,
		PermissionSet: "Sales_User",
		ProfilesAnyOf: []string{"Standard User"},
	}
	targets, err := source.ManagedTargets(policy)
	if err != nil {
		t.Fatal(err)
	}
	definition, err := PermissionSetDefinitionManagedTarget("sales_user")
	if err != nil {
		t.Fatal(err)
	}
	if len(targets) != 2 || !reflect.DeepEqual(targets[0], source.ManagedTarget()) || !reflect.DeepEqual(targets[1], definition) {
		t.Fatalf("targets = %#v", targets)
	}
}

func TestAssignmentPolicySelectorManagedTargetUsesDurableCollationIdentity(t *testing.T) {
	upper, err := assignmentPolicySelectorManagedTarget("Sales")
	if err != nil {
		t.Fatal(err)
	}
	lower, err := assignmentPolicySelectorManagedTarget("sales")
	if err != nil {
		t.Fatal(err)
	}
	other, err := assignmentPolicySelectorManagedTarget("Standard")
	if err != nil {
		t.Fatal(err)
	}
	if !reflect.DeepEqual(upper, lower) {
		t.Fatalf("database-equivalent selectors use different targets: %#v / %#v", upper, lower)
	}
	if reflect.DeepEqual(upper, other) {
		t.Fatalf("independent selectors share target %#v", upper)
	}
}

func TestAssignmentPolicySourceRejectsNonIdentifiers(t *testing.T) {
	for _, test := range []struct{ ownerPack, policyKey string }{
		{"", "Policy"},
		{"Pack", ""},
		{" bad-pack", "Policy"},
		{"Pack", "bad key "},
		{"Pack", "bad\nkey"},
		{strings.Repeat("p", 256), "Policy"},
	} {
		if _, err := NewPermissionSetAssignmentPolicySource(test.ownerPack, test.policyKey); err == nil {
			t.Fatalf("NewPermissionSetAssignmentPolicySource(%q, %q) succeeded", test.ownerPack, test.policyKey)
		}
	}
}
