package salesforce

import "testing"

func TestStandardRelationshipForeignKey(t *testing.T) {
	tests := []struct {
		name     string
		expected string
		ok       bool
	}{
		{name: "Account", expected: "AccountId", ok: true},
		{name: "RecordType", expected: "RecordTypeId", ok: true},
		// Standard User references — required by 2-hop traversal of
		// `$Record.Owner.UserRole.Name`, `$Record.Owner.Profile.Name`,
		// `$Record.Owner.Manager.Name` when per-field metadata for User is
		// not warm in the cache (issue #2093).
		{name: "UserRole", expected: "UserRoleId", ok: true},
		{name: "Profile", expected: "ProfileId", ok: true},
		{name: "Manager", expected: "ManagerId", ok: true},
		{name: "Lead", expected: "", ok: false},
		{name: "Unknown", expected: "", ok: false},
	}

	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {
			got, ok := StandardRelationshipForeignKey(tt.name)
			if got != tt.expected || ok != tt.ok {
				t.Fatalf("StandardRelationshipForeignKey(%q) = (%q, %v), want (%q, %v)", tt.name, got, ok, tt.expected, tt.ok)
			}
		})
	}
}

func TestStandardObjectForForeignKey(t *testing.T) {
	tests := []struct {
		fk       string
		expected string
		ok       bool
	}{
		{fk: "OwnerId", expected: "User", ok: true},
		{fk: "ContractId", expected: "Contract", ok: true},
		// Standard User reference FKs (#2093). Mirror the relationship-name
		// table above so the loadRelatedRecord cache-miss fallback resolves
		// the same target the resolver picked.
		{fk: "UserRoleId", expected: "UserRole", ok: true},
		{fk: "ProfileId", expected: "Profile", ok: true},
		{fk: "ManagerId", expected: "User", ok: true},
		{fk: "ParentId", expected: "", ok: false},
	}

	for _, tt := range tests {
		t.Run(tt.fk, func(t *testing.T) {
			got, ok := StandardObjectForForeignKey(tt.fk)
			if got != tt.expected || ok != tt.ok {
				t.Fatalf("StandardObjectForForeignKey(%q) = (%q, %v), want (%q, %v)", tt.fk, got, ok, tt.expected, tt.ok)
			}
		})
	}
}

func TestStandardKeyPrefixLookups(t *testing.T) {
	tests := []struct {
		prefix string
		object string
		ok     bool
	}{
		{prefix: "006", object: "Opportunity", ok: true},
		{prefix: "800", object: "Contract", ok: true},
		// Tooling API SObjects — Salesforce reserved prefixes.
		{prefix: "300", object: "FlowDefinition", ok: true},
		{prefix: "301", object: "Flow", ok: true},
		{prefix: "XYZ", object: "", ok: false},
	}

	for _, tt := range tests {
		t.Run(tt.prefix, func(t *testing.T) {
			got, ok := StandardObjectForKeyPrefix(tt.prefix)
			if got != tt.object || ok != tt.ok {
				t.Fatalf("StandardObjectForKeyPrefix(%q) = (%q, %v), want (%q, %v)", tt.prefix, got, ok, tt.object, tt.ok)
			}
		})
	}

	key, ok := StandardKeyPrefixForObject("Task")
	if !ok || key != "00T" {
		t.Fatalf("StandardKeyPrefixForObject(Task) = (%q, %v), want (00T, true)", key, ok)
	}

	// Flow Tooling API objects — Salesforce standard key prefixes.
	if key, ok := StandardKeyPrefixForObject("FlowDefinition"); !ok || key != "300" {
		t.Fatalf("StandardKeyPrefixForObject(FlowDefinition) = (%q, %v), want (300, true)", key, ok)
	}
	if key, ok := StandardKeyPrefixForObject("Flow"); !ok || key != "301" {
		t.Fatalf("StandardKeyPrefixForObject(Flow) = (%q, %v), want (301, true)", key, ok)
	}
}

func TestStandardKeyPrefixMapsReturnCopies(t *testing.T) {
	prefixToObject := StandardKeyPrefixToObjectMap()
	objectToPrefix := StandardObjectToKeyPrefixMap()

	prefixToObject["001"] = "Mutated"
	objectToPrefix["Account"] = "mut"

	if got, _ := StandardObjectForKeyPrefix("001"); got != "Account" {
		t.Fatalf("mutating StandardKeyPrefixToObjectMap must not change canonical map, got %q", got)
	}
	if got, _ := StandardKeyPrefixForObject("Account"); got != "001" {
		t.Fatalf("mutating StandardObjectToKeyPrefixMap must not change canonical map, got %q", got)
	}
}
