package records

import (
	"context"
	"errors"
	"strings"
	"testing"
	"time"

	appErrors "github.com/nexuscrm/kernel/pkg/errors"
	"github.com/nexuscrm/kernel/pkg/schemautil"
	"github.com/nexuscrm/shared/pkg/constants"
	"github.com/nexuscrm/shared/pkg/models"
)

type stubSharingRuleValidationRepo struct {
	findOneFn        func(ctx context.Context, t string, id string) (models.SObject, error)
	getChildrenFn    func(ctx context.Context, childTable string, foreignKey string, parentID string) ([]models.SObject, error)
	checkUniqueFn    func(ctx context.Context, schema *models.ObjectMetadata, f string, v interface{}, excl string) (bool, error)
	checkUniqueCalls int
}

func (r *stubSharingRuleValidationRepo) FindOne(ctx context.Context, t string, id string) (models.SObject, error) {
	if r.findOneFn != nil {
		return r.findOneFn(ctx, t, id)
	}
	return nil, nil
}

func (r *stubSharingRuleValidationRepo) FindOneByField(ctx context.Context, t string, f string, v interface{}) (models.SObject, error) {
	return nil, nil
}
func (r *stubSharingRuleValidationRepo) Exists(ctx context.Context, t string, id string) (bool, error) {
	return false, nil
}
func (r *stubSharingRuleValidationRepo) GetLock(ctx context.Context, t string, id string) (models.SObject, error) {
	return nil, nil
}
func (r *stubSharingRuleValidationRepo) Insert(ctx context.Context, t string, rec models.SObject) error {
	return nil
}
func (r *stubSharingRuleValidationRepo) BulkInsert(ctx context.Context, t string, recs []models.SObject, cols []string, opts interface{}) error {
	return nil
}
func (r *stubSharingRuleValidationRepo) BulkInsertWithLanding(ctx context.Context, t string, recs []models.SObject, cols []string, opts interface{}) ([]bool, error) {
	return nil, nil
}
func (r *stubSharingRuleValidationRepo) Update(ctx context.Context, t string, id string, u models.SObject) error {
	return nil
}
func (r *stubSharingRuleValidationRepo) Delete(ctx context.Context, t string, id string) error {
	return nil
}
func (r *stubSharingRuleValidationRepo) PhysicalDelete(ctx context.Context, t string, id string) error {
	return nil
}
func (r *stubSharingRuleValidationRepo) DeleteByField(ctx context.Context, t string, f string, v interface{}) error {
	return nil
}
func (r *stubSharingRuleValidationRepo) ExistsByField(ctx context.Context, t string, f string, v interface{}) (bool, error) {
	return false, nil
}
func (r *stubSharingRuleValidationRepo) FindAny(ctx context.Context, t string, id string) (models.SObject, error) {
	return nil, nil
}
func (r *stubSharingRuleValidationRepo) FindMany(ctx context.Context, t string, ids []string) (map[string]models.SObject, error) {
	return nil, nil
}
func (r *stubSharingRuleValidationRepo) GetChildren(ctx context.Context, ct string, fk string, pid string) ([]models.SObject, error) {
	if r.getChildrenFn != nil {
		return r.getChildrenFn(ctx, ct, fk, pid)
	}
	return nil, nil
}
func (r *stubSharingRuleValidationRepo) GetDeletedChildren(ctx context.Context, ct string, fk string, pid string) ([]models.SObject, error) {
	return nil, nil
}
func (r *stubSharingRuleValidationRepo) CheckUniqueness(ctx context.Context, schema *models.ObjectMetadata, f string, v interface{}, excl string) (bool, error) {
	r.checkUniqueCalls++
	if r.checkUniqueFn != nil {
		return r.checkUniqueFn(ctx, schema, f, v, excl)
	}
	return false, nil
}
func (r *stubSharingRuleValidationRepo) FindAllRecycleBinItems(ctx context.Context) ([]models.SObject, error) {
	return nil, nil
}
func (r *stubSharingRuleValidationRepo) FindRecycleBinItemsByUserPage(ctx context.Context, deleterID string, afterDeletedDate string, afterID string, limit int) ([]models.SObject, error) {
	return nil, nil
}
func (r *stubSharingRuleValidationRepo) FindAllRecycleBinItemsPage(ctx context.Context, afterDeletedDate string, afterID string, limit int) ([]models.SObject, error) {
	return nil, nil
}
func (r *stubSharingRuleValidationRepo) FindRecycleBinEntry(ctx context.Context, recordID string) (models.SObject, error) {
	return nil, nil
}
func (r *stubSharingRuleValidationRepo) CheckQueueSupport(ctx context.Context, queueID string, objectType string) (bool, error) {
	return false, nil
}
func (r *stubSharingRuleValidationRepo) GetRecordType(ctx context.Context, id string) (string, error) {
	return "", nil
}
func (r *stubSharingRuleValidationRepo) FindObjectTypesForIDs(ctx context.Context, ids []string, tableNames []string) (map[string]string, error) {
	return nil, nil
}

func TestValidateSharingRuleOwnerReferences_MissingTargetReturnsInvalidCrossReference(t *testing.T) {
	ps := &PersistenceService{
		repo: &stubSharingRuleValidationRepo{
			findOneFn: func(ctx context.Context, t string, id string) (models.SObject, error) {
				return nil, nil
			},
		},
	}

	rec := models.SObject{
		constants.FieldSharingRule_Name:              "qa_owner_group_rule",
		constants.FieldSharingRule_ObjectAPIName:     "Account",
		constants.FieldSharingRule_AccessLevel:       "Read",
		constants.FieldSharingRule_SharedFromGroupID: "group_all_internal_users",
		constants.FieldSharingRule_ShareWithGroupID:  "group_all_internal_users",
	}

	err := ps.validateSharingRuleOwnerReferences(context.Background(), constants.TableSharingRule, rec)
	if err == nil {
		t.Fatal("validateSharingRuleOwnerReferences = nil, want Salesforce API error")
	}

	// Engine returns a neutral *DomainWireError carrying the semantic kind and
	// the offending field. The boundary dialect maps WireInvalidReference to the
	// v63 INVALID_CROSS_REFERENCE_KEY at HTTP 400 (covered by the dialect's
	// wire_domain_mapping golden); the engine itself stays dialect-neutral.
	var domainErr *appErrors.DomainWireError
	if !errors.As(err, &domainErr) {
		t.Fatalf("error type = %T (%v), want *appErrors.DomainWireError", err, err)
	}
	if domainErr.Kind != appErrors.WireInvalidReference {
		t.Fatalf("kind = %q, want %q", domainErr.Kind, appErrors.WireInvalidReference)
	}
	if len(domainErr.Fields) != 1 || domainErr.Fields[0] != constants.FieldSharingRule_SharedFromGroupID {
		t.Fatalf("fields = %#v, want [%q]", domainErr.Fields, constants.FieldSharingRule_SharedFromGroupID)
	}
}

func TestValidateSharingRuleOwnerReferences_ExistingTargetsPass(t *testing.T) {
	ps := &PersistenceService{
		repo: &stubSharingRuleValidationRepo{
			findOneFn: func(ctx context.Context, t string, id string) (models.SObject, error) {
				return models.SObject{constants.FieldID: id}, nil
			},
		},
	}

	rec := models.SObject{
		constants.FieldSharingRule_Name:             "qa_owner_role_rule",
		constants.FieldSharingRule_ObjectAPIName:    "Account",
		constants.FieldSharingRule_AccessLevel:      "Read",
		constants.FieldSharingRule_SharedFromRoleID: "00E000000000001",
		constants.FieldSharingRule_ShareWithRoleID:  "00E000000000002",
	}

	if err := ps.validateSharingRuleOwnerReferences(context.Background(), constants.TableSharingRule, rec); err != nil {
		t.Fatalf("validateSharingRuleOwnerReferences = %v, want nil", err)
	}
}

func TestValidateGroupUserRoleReferenceContract_RequiresUserRoleForRoleBackedGroups(t *testing.T) {
	ps := &PersistenceService{}

	rec := models.SObject{
		constants.FieldGroup_Name:  "Role Group",
		constants.FieldGroup_Label: "Role Group",
		constants.FieldGroup_Type:  "Role",
	}

	err := ps.validateGroupUserRoleReferenceContract(context.Background(), constants.TableGroup, "", rec)
	if err == nil {
		t.Fatal("validateGroupUserRoleReferenceContract = nil, want validation error")
	}

	var validationErr *appErrors.ValidationError
	if !errors.As(err, &validationErr) {
		t.Fatalf("error type = %T (%v), want *appErrors.ValidationError", err, err)
	}
	if validationErr.Field != constants.FieldGroup_UserRoleID {
		t.Fatalf("field = %q, want %q", validationErr.Field, constants.FieldGroup_UserRoleID)
	}
}

func TestValidateGroupUserRoleReferenceContract_RejectsUserRoleOnNonRoleBackedGroups(t *testing.T) {
	ps := &PersistenceService{}

	rec := models.SObject{
		constants.FieldGroup_Name:       "Queue Group",
		constants.FieldGroup_Label:      "Queue Group",
		constants.FieldGroup_Type:       "Queue",
		constants.FieldGroup_UserRoleID: "00E000000000001",
	}

	err := ps.validateGroupUserRoleReferenceContract(context.Background(), constants.TableGroup, "", rec)
	if err == nil {
		t.Fatal("validateGroupUserRoleReferenceContract = nil, want validation error")
	}

	var validationErr *appErrors.ValidationError
	if !errors.As(err, &validationErr) {
		t.Fatalf("error type = %T (%v), want *appErrors.ValidationError", err, err)
	}
	if validationErr.Field != constants.FieldGroup_UserRoleID {
		t.Fatalf("field = %q, want %q", validationErr.Field, constants.FieldGroup_UserRoleID)
	}
}

func TestValidateGroupUserRoleReferenceContract_AllowsRoleBackedGroupWithUserRole(t *testing.T) {
	ps := &PersistenceService{}

	rec := models.SObject{
		constants.FieldGroup_Name:       "Role And Subs",
		constants.FieldGroup_Label:      "Role And Subs",
		constants.FieldGroup_Type:       "RoleAndSubordinates",
		constants.FieldGroup_UserRoleID: "00E000000000001",
	}

	if err := ps.validateGroupUserRoleReferenceContract(context.Background(), constants.TableGroup, "", rec); err != nil {
		t.Fatalf("validateGroupUserRoleReferenceContract = %v, want nil", err)
	}
}

func TestValidateGroupUserRoleReferenceContract_RejectsRoleBackedGroupWithExistingManualMembers(t *testing.T) {
	ps := &PersistenceService{
		repo: &stubSharingRuleValidationRepo{
			getChildrenFn: func(ctx context.Context, childTable string, foreignKey string, parentID string) ([]models.SObject, error) {
				if childTable != constants.TableGroupMember || foreignKey != constants.FieldGroupMember_GroupID || parentID != "legacy-role-group" {
					t.Fatalf("GetChildren(%q, %q, %q) unexpected", childTable, foreignKey, parentID)
				}
				return []models.SObject{
					{
						constants.FieldID:                        "member-1",
						constants.FieldGroupMember_GroupID:       "legacy-role-group",
						constants.FieldGroupMember_UserOrGroupID: "005000000000001",
					},
				}, nil
			},
		},
	}

	rec := models.SObject{
		constants.FieldID:               "legacy-role-group",
		constants.FieldGroup_Name:       "Legacy Role Group",
		constants.FieldGroup_Label:      "Legacy Role Group",
		constants.FieldGroup_Type:       "Role",
		constants.FieldGroup_UserRoleID: "00E000000000001",
	}

	err := ps.validateGroupUserRoleReferenceContract(context.Background(), constants.TableGroup, "legacy-role-group", rec)
	if err == nil {
		t.Fatal("validateGroupUserRoleReferenceContract = nil, want validation error")
	}

	var validationErr *appErrors.ValidationError
	if !errors.As(err, &validationErr) {
		t.Fatalf("error type = %T (%v), want *appErrors.ValidationError", err, err)
	}
	if validationErr.Field != constants.FieldGroup_UserRoleID {
		t.Fatalf("field = %q, want %q", validationErr.Field, constants.FieldGroup_UserRoleID)
	}
	if !strings.Contains(validationErr.Error(), roleBackedGroupManualMembersMessage) {
		t.Fatalf("error = %v, want message containing %q", err, roleBackedGroupManualMembersMessage)
	}
}

func TestValidateRoleBackedGroupMemberMutation_RejectsRoleBackedGroups(t *testing.T) {
	ps := &PersistenceService{
		repo: &stubSharingRuleValidationRepo{
			findOneFn: func(ctx context.Context, tableName string, id string) (models.SObject, error) {
				if tableName != constants.TableGroup || id != "group-role" {
					t.Fatalf("FindOne(%q, %q) unexpected", tableName, id)
				}
				return models.SObject{
					constants.FieldID:               "group-role",
					constants.FieldGroup_Type:       "Role",
					constants.FieldGroup_UserRoleID: "00E000000000001",
				}, nil
			},
		},
	}

	rec := models.SObject{
		constants.FieldGroupMember_GroupID:       "group-role",
		constants.FieldGroupMember_UserOrGroupID: "005000000000001",
	}

	err := ps.validateRoleBackedGroupMemberMutation(context.Background(), constants.TableGroupMember, rec)
	if err == nil {
		t.Fatal("validateRoleBackedGroupMemberMutation = nil, want validation error")
	}

	var validationErr *appErrors.ValidationError
	if !errors.As(err, &validationErr) {
		t.Fatalf("error type = %T (%v), want *appErrors.ValidationError", err, err)
	}
	if validationErr.Field != constants.FieldGroupMember_GroupID {
		t.Fatalf("field = %q, want %q", validationErr.Field, constants.FieldGroupMember_GroupID)
	}
}

func TestValidateRoleBackedGroupMemberMutation_AllowsLegacyTypeOnlyRoleGroups(t *testing.T) {
	ps := &PersistenceService{
		repo: &stubSharingRuleValidationRepo{
			findOneFn: func(ctx context.Context, tableName string, id string) (models.SObject, error) {
				return models.SObject{
					constants.FieldID:         id,
					constants.FieldGroup_Type: "Role",
				}, nil
			},
		},
	}

	rec := models.SObject{
		constants.FieldGroupMember_GroupID:       "legacy-role-group",
		constants.FieldGroupMember_UserOrGroupID: "005000000000001",
	}

	if err := ps.validateRoleBackedGroupMemberMutation(context.Background(), constants.TableGroupMember, rec); err != nil {
		t.Fatalf("validateRoleBackedGroupMemberMutation = %v, want nil for legacy type-only role group", err)
	}
}

func TestValidateRoleBackedGroupMemberMutation_AllowsNonRoleBackedGroups(t *testing.T) {
	ps := &PersistenceService{
		repo: &stubSharingRuleValidationRepo{
			findOneFn: func(ctx context.Context, tableName string, id string) (models.SObject, error) {
				return models.SObject{
					constants.FieldID:         id,
					constants.FieldGroup_Type: "Regular",
				}, nil
			},
		},
	}

	rec := models.SObject{
		constants.FieldGroupMember_GroupID:       "group-regular",
		constants.FieldGroupMember_UserOrGroupID: "005000000000001",
	}

	if err := ps.validateRoleBackedGroupMemberMutation(context.Background(), constants.TableGroupMember, rec); err != nil {
		t.Fatalf("validateRoleBackedGroupMemberMutation = %v, want nil", err)
	}
}

func TestValidateRoleBackedGroupMemberMutation_AllowsDanglingGroupCleanup(t *testing.T) {
	ps := &PersistenceService{
		repo: &stubSharingRuleValidationRepo{
			findOneFn: func(ctx context.Context, tableName string, id string) (models.SObject, error) {
				return nil, nil
			},
		},
	}

	rec := models.SObject{
		constants.FieldGroupMember_GroupID:       "missing-group",
		constants.FieldGroupMember_UserOrGroupID: "005000000000001",
	}

	if err := ps.validateRoleBackedGroupMemberMutation(context.Background(), constants.TableGroupMember, rec); err != nil {
		t.Fatalf("validateRoleBackedGroupMemberMutation = %v, want nil", err)
	}
}

func TestCheckUniquenessSeesPreviewSyntheticRecords(t *testing.T) {
	repo := &stubSharingRuleValidationRepo{}
	ps := &PersistenceService{repo: repo}
	schema := &models.ObjectMetadata{
		APIName: "PreviewObj",
		Fields: []models.FieldMetadata{
			{
				APIName:  "ExternalKey__c",
				IsUnique: true,
			},
		},
	}
	ctx := constants.WithPreviewSyntheticRecordRegistry(context.Background())
	constants.RegisterPreviewSyntheticRecord(ctx, "preview-PreviewObj-1", "PreviewObj", map[string]interface{}{
		constants.FieldID: "preview-PreviewObj-1",
		"ExternalKey__c":  "dup-key",
	})

	err := ps.checkUniqueness(ctx, "PreviewObj", models.SObject{
		"ExternalKey__c": "dup-key",
	}, schema, "")
	if err == nil {
		t.Fatal("checkUniqueness accepted duplicate preview-created value; want conflict")
	}
	if !strings.Contains(err.Error(), "dup-key") {
		t.Fatalf("checkUniqueness error = %v; want duplicate value", err)
	}
	if repo.checkUniqueCalls != 0 {
		t.Fatalf("repo.CheckUniqueness calls = %d; want preview overlay to reject before DB probe", repo.checkUniqueCalls)
	}
}

func TestAreFieldValuesEqual_MultiPicklistAliasUsesSetSemantics(t *testing.T) {
	ps := &PersistenceService{}
	// Declared options A and B are required for the field-aware comparator
	// to disambiguate a JSON-array wire scalar like `["A","B"]` as the
	// two-selection [A, B] set rather than a single declared option whose
	// VALUE happens to be the 5-char literal `["A","B"]`. With options
	// declared, both serializations canonicalize to the same set.
	field := &models.FieldMetadata{
		APIName: "Tags__c",
		Type:    constants.SchemaFieldType("multiselectpicklist"),
		Options: models.PicklistOptionsFromStrings([]string{"A", "B"}),
	}

	if !ps.areFieldValuesEqual(field, `["A","B"]`, "B;A") {
		t.Fatal("areFieldValuesEqual alias multipicklist = false, want set-equal true")
	}
}

func TestAreFieldValuesEqual_DeclaredJSONLookingOptionNoOpUpdate(t *testing.T) {
	ps := &PersistenceService{}
	// Field has a declared option whose value looks like a JSON array literal.
	field := &models.FieldMetadata{
		APIName: "Tags__c",
		Type:    constants.FieldTypeMultiPicklist,
		Options: models.PicklistOptionsFromStrings([]string{`["A","B"]`}),
	}
	schema := &models.ObjectMetadata{
		APIName: "Opportunity",
		Fields:  []models.FieldMetadata{*field},
	}

	// Model the live PATCH call path exactly. Hand-rolled strings on either
	// side mask the regression Codex reported on PR #898 — the prior version
	// of this test compared the storage shape directly against the wire
	// shape, but the live path runs LHS through FromStorageRecord (storage
	// → wire) and RHS through NormalizeSObject (wire → sentinel-wrapped
	// storage). Both projections must converge on the same canonical form
	// inside areFieldValuesEqual; if not, a no-op PATCH triggers a self-
	// update loop (#1683 extension).
	storedRow := models.SObject{constants.FieldID: "001", "Tags__c": `["[\"A\",\"B\"]"]`}
	lhs := schemautil.FromStorageRecord(schema, storedRow, nil)["Tags__c"]

	incoming := models.SObject{"Tags__c": `["A","B"]`}
	rhs := schemautil.NormalizeSObject(schema, incoming)["Tags__c"]

	if !ps.areFieldValuesEqual(field, lhs, rhs) {
		t.Fatalf("areFieldValuesEqual = false for declared JSON-looking option no-op re-PATCH; lhs=%#v rhs=%#v",
			lhs, rhs)
	}
}

func TestAreFieldValuesEqual_DateValuedRollupSummaryUsesNormalizedLockedValue(t *testing.T) {
	ps := &PersistenceService{}
	returnType := models.FieldType(constants.FieldTypeDate)
	field := &models.FieldMetadata{
		APIName:    "Overall_End_Date__c",
		Type:       constants.FieldTypeRollupSummary,
		ReturnType: &returnType,
	}
	schema := &models.ObjectMetadata{
		APIName: "Order",
		Fields:  []models.FieldMetadata{*field},
	}

	locked := schemautil.FromStorageRecord(schema, models.SObject{
		"Overall_End_Date__c": time.Date(2027, time.January, 17, 0, 0, 0, 0, time.FixedZone("UTC+8", 8*60*60)),
	}, nil)["Overall_End_Date__c"]

	if !ps.areFieldValuesEqual(field, locked, "2027-01-17") {
		t.Fatalf("areFieldValuesEqual = false for normalized date rollup no-op; locked=%#v", locked)
	}
}

func staticDependentPicklistTestSchema() *models.ObjectMetadata {
	controllerField := "CountryCode"
	return &models.ObjectMetadata{
		APIName: "Account",
		Fields: []models.FieldMetadata{
			{
				APIName: controllerField,
				Type:    constants.FieldTypePicklist,
				Options: models.PicklistOptionsFromStrings([]string{"CN", "US"}),
			},
			{
				APIName:          "Province__c",
				Type:             constants.FieldTypePicklist,
				ControllingField: &controllerField,
				PicklistDependency: map[string][]string{
					"CN": {"BJ"},
					"US": {"CA"},
				},
				Options: models.PicklistOptionsFromStrings([]string{"BJ", "CA"}),
			},
			{
				APIName:          "Regions__c",
				Type:             constants.FieldTypeMultiPicklist,
				ControllingField: &controllerField,
				PicklistDependency: map[string][]string{
					"CN": {"North", "East"},
					"US": {"West"},
				},
				Options: models.PicklistOptionsFromStrings([]string{"North", "East", "West"}),
			},
		},
	}
}

func TestValidateStaticDependentPicklists_AllowsControllerUpdateWhenHiddenDependentIsBlank(t *testing.T) {
	ps := &PersistenceService{}
	err := ps.validateStaticDependentPicklists(
		staticDependentPicklistTestSchema(),
		models.SObject{
			"CountryCode": "US",
			"Province__c": "",
		},
		models.SObject{
			"CountryCode": "US",
		},
	)
	if err != nil {
		t.Fatalf("validateStaticDependentPicklists = %v, want nil", err)
	}
}

func TestValidateStaticDependentPicklists_AllowsControllerUpdateWhenStoredDependentRemainsValid(t *testing.T) {
	ps := &PersistenceService{}
	err := ps.validateStaticDependentPicklists(
		staticDependentPicklistTestSchema(),
		models.SObject{
			"CountryCode": "US",
			"Province__c": "CA",
		},
		models.SObject{
			"CountryCode": "US",
		},
	)
	if err != nil {
		t.Fatalf("validateStaticDependentPicklists = %v, want nil", err)
	}
}

func TestValidateStaticDependentPicklists_RejectsControllerUpdateWhenStoredDependentBecomesInvalid(t *testing.T) {
	ps := &PersistenceService{}
	err := ps.validateStaticDependentPicklists(
		staticDependentPicklistTestSchema(),
		models.SObject{
			"CountryCode": "US",
			"Province__c": "BJ",
		},
		models.SObject{
			"CountryCode": "US",
		},
	)
	if err == nil {
		t.Fatal("validateStaticDependentPicklists = nil, want invalid dependent error")
	}
	if !strings.Contains(err.Error(), `validation error on field 'Province__c': value is not valid for CountryCode`) {
		t.Fatalf("validateStaticDependentPicklists error = %v", err)
	}
}

func TestValidateStaticDependentPicklists_RejectsInvalidStoredMultiPicklistSelection(t *testing.T) {
	ps := &PersistenceService{}
	err := ps.validateStaticDependentPicklists(
		staticDependentPicklistTestSchema(),
		models.SObject{
			"CountryCode": "US",
			"Regions__c":  "West;North",
		},
		models.SObject{
			"CountryCode": "US",
		},
	)
	if err == nil {
		t.Fatal("validateStaticDependentPicklists = nil, want invalid dependent error")
	}
	if !strings.Contains(err.Error(), `validation error on field 'Regions__c': value is not valid for CountryCode`) {
		t.Fatalf("validateStaticDependentPicklists error = %v", err)
	}
}

func TestValidateStaticDependentPicklists_RejectsUndeclaredStoredControllerWithoutLeakingValue(t *testing.T) {
	ps := &PersistenceService{}
	err := ps.validateStaticDependentPicklists(
		staticDependentPicklistTestSchema(),
		models.SObject{
			"CountryCode": "InternalOnly",
			"Province__c": "BJ",
		},
		models.SObject{
			"Province__c": "BJ",
		},
	)
	if err == nil {
		t.Fatal("validateStaticDependentPicklists = nil, want invalid controller rejection")
	}
	if !strings.Contains(err.Error(), `validation error on field 'Province__c': value is not valid for CountryCode`) {
		t.Fatalf("validateStaticDependentPicklists error = %v", err)
	}
	if strings.Contains(err.Error(), "InternalOnly") {
		t.Fatalf("validateStaticDependentPicklists leaked hidden controller value: %v", err)
	}
}

func TestValidateStaticDependentPicklists_IgnoresUnsupportedDependencyShapesHiddenFromDescribe(t *testing.T) {
	ps := &PersistenceService{}
	controllerField := "CountryCode"
	schema := &models.ObjectMetadata{
		APIName: "Account",
		Fields: []models.FieldMetadata{
			{
				APIName: controllerField,
				Type:    constants.FieldTypePicklist,
				Options: models.PicklistOptionsFromStrings([]string{"CN", "US"}),
			},
			{
				APIName:          "Province__c",
				Type:             constants.FieldTypePicklist,
				ControllingField: &controllerField,
				PicklistDependency: map[string][]string{
					"CN": {"BJ"},
					"US": {"CA"},
				},
				Options: models.PicklistOptionsFromStrings([]string{"BJ", "CA", "TX"}),
			},
		},
	}

	err := ps.validateStaticDependentPicklists(
		schema,
		models.SObject{
			"CountryCode": "US",
			"Province__c": "BJ",
		},
		models.SObject{
			"CountryCode": "US",
		},
	)
	if err != nil {
		t.Fatalf("validateStaticDependentPicklists = %v, want nil for unsupported hidden contract", err)
	}
}
