package analytics

import (
	"context"
	"reflect"
	"strings"
	"testing"

	"github.com/nexuscrm/kernel/pkg/ports"
	domainrls "github.com/nexuscrm/kernel/pkg/rls"
	"github.com/nexuscrm/metadata"
	"github.com/nexuscrm/permissions"
	"github.com/nexuscrm/shared/pkg/constants"
	"github.com/nexuscrm/shared/pkg/models"
	"github.com/nexuscrm/shared/pkg/queryspec"
	"github.com/nexuscrm/shared/pkg/referenceidentity"
)

func TestParseDotNotationChildren(t *testing.T) {
	accountRel := "Account"
	schema := &models.ObjectMetadata{
		APIName: "Junction__c",
		Fields: []models.FieldMetadata{
			{
				APIName:          "AccountId",
				Type:             constants.FieldTypeReference,
				ReferenceTo:      []string{"Account"},
				RelationshipName: &accountRel,
			},
			{APIName: "DisplayCode__c", Type: constants.FieldTypeString},
		},
	}

	tests := []struct {
		name   string
		fields []string
		want   map[string][]string
	}{
		{
			name:   "relationship name form",
			fields: []string{"Account.ExternalId__c"},
			want:   map[string][]string{"AccountId": {"ExternalId__c"}},
		},
		{
			name:   "lookup field form",
			fields: []string{"AccountId.ExternalId__c"},
			want:   map[string][]string{"AccountId": {"ExternalId__c"}},
		},
		{
			name:   "deduplicates case-insensitively",
			fields: []string{"Account.ExternalId__c", "AccountId.externalid__c"},
			want:   map[string][]string{"AccountId": {"ExternalId__c"}},
		},
		{
			name:   "ignores Name child handled by legacy lookup display path",
			fields: []string{"Account.Name"},
			want:   nil,
		},
		{
			name:   "ignores scalar parent",
			fields: []string{"DisplayCode__c.Value"},
			want:   nil,
		},
		{
			name:   "ignores multi-hop",
			fields: []string{"Account.Owner.Name"},
			want:   nil,
		},
	}

	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {
			if got := parseDotNotationChildren(schema, tt.fields); !reflect.DeepEqual(got, tt.want) {
				t.Fatalf("parseDotNotationChildren() = %#v, want %#v", got, tt.want)
			}
		})
	}
}

func TestBuildQueryFieldsAddsLookupForDotNotationSelect(t *testing.T) {
	accountRel := "Account"
	schema := &models.ObjectMetadata{
		APIName: "Junction__c",
		Fields: []models.FieldMetadata{
			{APIName: constants.FieldID, Type: constants.FieldTypeString, IsSystem: true},
			{APIName: constants.FieldName, Type: constants.FieldTypeString, IsNameField: true},
			{
				APIName:          "AccountId",
				Type:             constants.FieldTypeReference,
				ReferenceTo:      []string{"Account"},
				RelationshipName: &accountRel,
			},
		},
	}

	got := buildQueryFields(schema, models.QueryRequest{
		SelectFields: []string{"Account.ExternalId__c"},
	}, []string{constants.FieldID, constants.FieldName, "AccountId"})
	want := []string{constants.FieldID, "AccountId"}
	if !equalAnalyticsStringSlices(got, want) {
		t.Fatalf("query fields = %#v, want %#v", got, want)
	}
}

func TestQueryHydratesDotNotationChildWithoutExplicitLookupSelect(t *testing.T) {
	accountRel := "Account"
	junctionSchema := &models.ObjectMetadata{
		APIName:      "Junction__c",
		SharingModel: constants.SharingModelPublicReadWrite,
		Fields: []models.FieldMetadata{
			{APIName: constants.FieldID, Type: constants.FieldTypeString, IsSystem: true},
			{APIName: constants.FieldName, Type: constants.FieldTypeString, IsNameField: true},
			{
				APIName:          "AccountId",
				Type:             constants.FieldTypeReference,
				ReferenceTo:      []string{"Account"},
				RelationshipName: &accountRel,
			},
		},
	}
	accountSchema := &models.ObjectMetadata{
		APIName:      "Account",
		SharingModel: constants.SharingModelPublicReadWrite,
		Fields: []models.FieldMetadata{
			{APIName: constants.FieldID, Type: constants.FieldTypeString, IsSystem: true},
			{APIName: constants.FieldName, Type: constants.FieldTypeString, IsNameField: true},
			{APIName: "ExternalId__c", Type: constants.FieldTypeString},
		},
	}
	metaRepo := &displayNameMetadataRepository{schemas: []*models.ObjectMetadata{junctionSchema, accountSchema}}
	metadataSvc := metadata.NewMetadataService(metaRepo, nil, nil)
	permissionSvc := permissions.NewPermissionService(&searchPermissionRepository{}, metadataSvc, nil)
	repo := &displayNameQueryRepository{}
	qs := NewQueryService(repo, metadataSvc, permissionSvc, nil)

	result, err := qs.QueryWithSpec(context.Background(), queryspec.QuerySpec{
		ObjectAPIName: "Junction__c",
		SelectFields:  []string{"Account.externalid__c"},
	}, &models.UserSession{ID: "u1", ProfileID: "p1", IsSystemAdmin: true})
	if err != nil {
		t.Fatalf("Query: %v", err)
	}

	if want := []string{constants.FieldID, "AccountId"}; !equalAnalyticsStringSlices(repo.findSelectFields, want) {
		t.Fatalf("repo select fields = %#v, want %#v", repo.findSelectFields, want)
	}
	if want := []string{constants.FieldID, constants.FieldName, "ExternalId__c"}; !equalAnalyticsStringSlices(repo.lookupFetchFields, want) {
		t.Fatalf("lookup fetch fields = %#v, want %#v", repo.lookupFetchFields, want)
	}
	if len(result.Records) != 1 {
		t.Fatalf("records = %d, want 1", len(result.Records))
	}
	account, ok := result.Records[0]["Account"].(map[string]interface{})
	if !ok {
		t.Fatalf("Account nested relationship missing: %#v", result.Records[0])
	}
	if account["ExternalId__c"] != "EXT-1" {
		t.Fatalf("Account.ExternalId__c = %#v, want EXT-1", account["ExternalId__c"])
	}
	if _, ok := account[constants.FieldName]; ok {
		t.Fatalf("unexpected support-only Account.Name in nested relationship: %#v", account)
	}
	if _, ok := result.Records[0]["AccountId"]; ok {
		t.Fatalf("unexpected support-only AccountId on backend response: %#v", result.Records[0])
	}
	if _, ok := result.Records[0]["AccountId_Name"]; ok {
		t.Fatalf("unexpected support-only AccountId_Name on backend response: %#v", result.Records[0])
	}
	if _, ok := result.Records[0]["AccountId_ExternalId__c"]; ok {
		t.Fatalf("unexpected flat relationship child key on backend response: %#v", result.Records[0])
	}
}

func TestQueryExplicitOnlySkipsImplicitLookupDisplayHydration(t *testing.T) {
	accountRel := "Account"
	junctionSchema := &models.ObjectMetadata{
		APIName:      "Junction__c",
		SharingModel: constants.SharingModelPublicReadWrite,
		Fields: []models.FieldMetadata{
			{APIName: constants.FieldID, Type: constants.FieldTypeString, IsSystem: true},
			{
				APIName:          "AccountId",
				Type:             constants.FieldTypeReference,
				ReferenceTo:      []string{"Account"},
				RelationshipName: &accountRel,
			},
		},
	}
	accountSchema := &models.ObjectMetadata{
		APIName:      "Account",
		SharingModel: constants.SharingModelPublicReadWrite,
		Fields: []models.FieldMetadata{
			{APIName: constants.FieldID, Type: constants.FieldTypeString, IsSystem: true},
			{APIName: constants.FieldName, Type: constants.FieldTypeString, IsNameField: true},
		},
	}
	metadataSvc := metadata.NewMetadataService(
		&displayNameMetadataRepository{schemas: []*models.ObjectMetadata{junctionSchema, accountSchema}}, nil, nil,
	)
	repo := &displayNameQueryRepository{}
	qs := NewQueryService(repo, metadataSvc, permissions.NewPermissionService(&searchPermissionRepository{}, metadataSvc, nil), nil)

	result, err := qs.QueryWithSpec(context.Background(), queryspec.QuerySpec{
		ObjectAPIName:      "Junction__c",
		SelectFields:       []string{constants.FieldID, "AccountId"},
		ReferenceHydration: queryspec.ReferenceHydrationExplicitOnly,
	}, &models.UserSession{ID: "u1", ProfileID: "p1", IsSystemAdmin: true})
	if err != nil {
		t.Fatalf("QueryWithSpec: %v", err)
	}
	if repo.lookupFetchFields != nil || repo.lookupFetchIDs != nil {
		t.Fatalf("implicit lookup hydration reached repository: fields=%#v ids=%#v", repo.lookupFetchFields, repo.lookupFetchIDs)
	}
	if len(result.Records) != 1 || result.Records[0]["AccountId"] != "acc-1" {
		t.Fatalf("root reference projection = %#v, want AccountId preserved", result.Records)
	}
	if _, exists := result.Records[0]["AccountId_Name"]; exists {
		t.Fatalf("implicit AccountId_Name was projected: %#v", result.Records[0])
	}
}

func TestQueryExplicitOnlyPreservesExplicitRelationshipHydration(t *testing.T) {
	accountRel := "Account"
	junctionSchema := &models.ObjectMetadata{
		APIName:      "Junction__c",
		SharingModel: constants.SharingModelPublicReadWrite,
		Fields: []models.FieldMetadata{
			{APIName: constants.FieldID, Type: constants.FieldTypeString, IsSystem: true},
			{
				APIName:          "AccountId",
				Type:             constants.FieldTypeReference,
				ReferenceTo:      []string{"Account"},
				RelationshipName: &accountRel,
			},
		},
	}
	accountSchema := &models.ObjectMetadata{
		APIName:      "Account",
		SharingModel: constants.SharingModelPublicReadWrite,
		Fields: []models.FieldMetadata{
			{APIName: constants.FieldID, Type: constants.FieldTypeString, IsSystem: true},
			{APIName: constants.FieldName, Type: constants.FieldTypeString, IsNameField: true},
		},
	}
	metadataSvc := metadata.NewMetadataService(
		&displayNameMetadataRepository{schemas: []*models.ObjectMetadata{junctionSchema, accountSchema}}, nil, nil,
	)
	repo := &displayNameQueryRepository{}
	qs := NewQueryService(repo, metadataSvc, permissions.NewPermissionService(&searchPermissionRepository{}, metadataSvc, nil), nil)

	result, err := qs.QueryWithSpec(context.Background(), queryspec.QuerySpec{
		ObjectAPIName:      "Junction__c",
		SelectFields:       []string{"Account.Name"},
		ReferenceHydration: queryspec.ReferenceHydrationExplicitOnly,
	}, &models.UserSession{ID: "u1", ProfileID: "p1", IsSystemAdmin: true})
	if err != nil {
		t.Fatalf("QueryWithSpec: %v", err)
	}
	if want := []string{constants.FieldID, constants.FieldName}; !equalAnalyticsStringSlices(repo.lookupFetchFields, want) {
		t.Fatalf("lookup fetch fields = %#v, want %#v", repo.lookupFetchFields, want)
	}
	account, ok := result.Records[0]["Account"].(map[string]interface{})
	if !ok || account[constants.FieldName] != "Acme" {
		t.Fatalf("explicit Account.Name relationship = %#v", result.Records[0])
	}
	if _, exists := result.Records[0]["AccountId"]; exists {
		t.Fatalf("support-only AccountId leaked: %#v", result.Records[0])
	}
}

func TestQueryRejectsUnknownReferenceHydrationMode(t *testing.T) {
	repo := &displayNameQueryRepository{}
	qs := NewQueryService(repo, nil, nil, nil)
	_, err := qs.QueryWithSpec(context.Background(), queryspec.QuerySpec{
		ObjectAPIName:      "Junction__c",
		ReferenceHydration: queryspec.ReferenceHydrationMode(255),
	}, nil)
	if err == nil || !strings.Contains(err.Error(), "ReferenceHydration") {
		t.Fatalf("QueryWithSpec error = %v, want ReferenceHydration validation error", err)
	}
	if repo.findSelectFields != nil {
		t.Fatalf("repository was called for invalid hydration mode: %#v", repo.findSelectFields)
	}
}

func TestQueryHydratesPrivateLookupNameForOwnedReferencedRecord(t *testing.T) {
	accountRel := "Account"
	junctionSchema := &models.ObjectMetadata{
		APIName:      "Junction__c",
		SharingModel: constants.SharingModelPublicReadWrite,
		Fields: []models.FieldMetadata{
			{APIName: constants.FieldID, Type: constants.FieldTypeString, IsSystem: true},
			{APIName: constants.FieldName, Type: constants.FieldTypeString, IsNameField: true},
			{
				APIName:          "AccountId",
				Type:             constants.FieldTypeReference,
				ReferenceTo:      []string{"Account"},
				RelationshipName: &accountRel,
			},
		},
	}
	accountSchema := &models.ObjectMetadata{
		APIName:      "Account",
		SharingModel: constants.SharingModelPrivate,
		Fields: []models.FieldMetadata{
			{APIName: constants.FieldID, Type: constants.FieldTypeString, IsSystem: true},
			{APIName: constants.FieldName, Type: constants.FieldTypeString, IsNameField: true},
			{APIName: constants.FieldOwnerID, Type: constants.FieldTypeReference, ReferenceTo: []string{constants.TableUser}, IsSystem: true},
		},
	}
	metaRepo := &displayNameMetadataRepository{schemas: []*models.ObjectMetadata{junctionSchema, accountSchema}}
	metadataSvc := metadata.NewMetadataService(metaRepo, nil, nil)
	permissionSvc := permissions.NewPermissionService(&searchPermissionRepository{}, metadataSvc, nil)
	repo := &displayNameQueryRepository{}
	qs := NewQueryService(repo, metadataSvc, permissionSvc, nil)

	result, err := qs.QueryWithSpec(context.Background(), queryspec.QuerySpec{
		ObjectAPIName: "Junction__c",
		SelectFields:  []string{"AccountId"},
	}, &models.UserSession{ID: "u1", ProfileID: "p1"})
	if err != nil {
		t.Fatalf("Query: %v", err)
	}

	if want := []string{constants.FieldID, constants.FieldName, constants.FieldOwnerID}; !equalAnalyticsStringSlices(repo.lookupFetchFields, want) {
		t.Fatalf("lookup fetch fields = %#v, want %#v", repo.lookupFetchFields, want)
	}
	if len(result.Records) != 1 {
		t.Fatalf("records = %d, want 1", len(result.Records))
	}
	if got := result.Records[0]["AccountId_Name"]; got != "Acme" {
		t.Fatalf("AccountId_Name = %#v, want Acme", got)
	}
}

func TestQueryHydratesPlatformLookupNameWithoutDeclaredReferenceTarget(t *testing.T) {
	recordTypeRel := constants.ObjectRecordType
	accountSchema := &models.ObjectMetadata{
		APIName:      "Account",
		SharingModel: constants.SharingModelPublicReadWrite,
		Fields: []models.FieldMetadata{
			{APIName: constants.FieldID, Type: constants.FieldTypeString, IsSystem: true},
			{APIName: constants.FieldName, Type: constants.FieldTypeString, IsNameField: true},
			{
				APIName:          constants.FieldRecordTypeID,
				Type:             constants.FieldTypeReference,
				RelationshipName: &recordTypeRel,
			},
		},
	}
	recordTypeSchema := &models.ObjectMetadata{
		APIName:      constants.ObjectRecordType,
		SharingModel: constants.SharingModelPublicReadWrite,
		Fields: []models.FieldMetadata{
			{APIName: constants.FieldID, Type: constants.FieldTypeString, IsSystem: true},
			{APIName: constants.FieldName, Type: constants.FieldTypeString, IsNameField: true},
		},
	}
	metaRepo := &displayNameMetadataRepository{schemas: []*models.ObjectMetadata{accountSchema, recordTypeSchema}}
	metadataSvc := metadata.NewMetadataService(metaRepo, nil, nil)
	permissionSvc := permissions.NewPermissionService(&searchPermissionRepository{}, metadataSvc, nil)
	repo := &platformLookupNameQueryRepository{}
	qs := NewQueryService(repo, metadataSvc, permissionSvc, nil)

	result, err := qs.QueryWithSpec(context.Background(), queryspec.QuerySpec{
		ObjectAPIName: "Account",
		SelectFields:  []string{constants.FieldRecordTypeID},
	}, &models.UserSession{ID: "u1", ProfileID: "p1", IsSystemAdmin: true})
	if err != nil {
		t.Fatalf("Query: %v", err)
	}

	if repo.lookupObject != constants.ObjectRecordType {
		t.Fatalf("lookup object = %q, want %q", repo.lookupObject, constants.ObjectRecordType)
	}
	if len(result.Records) != 1 {
		t.Fatalf("records = %d, want 1", len(result.Records))
	}
	if got := result.Records[0][constants.FieldRecordTypeID+"_Name"]; got != "Business Account" {
		t.Fatalf("RecordTypeId_Name = %#v, want Business Account; record=%#v", got, result.Records[0])
	}
}

func TestLookupRefObjectHandlesPolymorphicFieldsBeforeReferenceTargets(t *testing.T) {
	tests := []struct {
		name  string
		field models.FieldMetadata
		want  string
	}{
		{
			name: "owner always resolves to user despite target order",
			field: models.FieldMetadata{
				APIName:       constants.FieldOwnerID,
				Type:          constants.FieldTypeReference,
				ReferenceTo:   []string{"Group", constants.TableUser},
				IsPolymorphic: true,
			},
			want: constants.TableUser,
		},
		{
			name: "non owner multi target polymorphic is skipped without discriminator",
			field: models.FieldMetadata{
				APIName:       "WhatId",
				Type:          constants.FieldTypeReference,
				ReferenceTo:   []string{"Account", "Opportunity"},
				IsPolymorphic: true,
			},
			want: "",
		},
		{
			name: "non owner single target polymorphic remains safe",
			field: models.FieldMetadata{
				APIName:       constants.FieldProcessInstanceHistory_ActorID,
				Type:          constants.FieldTypeReference,
				ReferenceTo:   []string{constants.TableUser},
				IsPolymorphic: true,
			},
			want: constants.TableUser,
		},
		{
			name: "non polymorphic explicit target still passes through",
			field: models.FieldMetadata{
				APIName:     "AccountId",
				Type:        constants.FieldTypeReference,
				ReferenceTo: []string{"Account"},
			},
			want: "Account",
		},
		{
			name: "non polymorphic platform fallback applies when target is absent",
			field: models.FieldMetadata{
				APIName: constants.FieldRecordTypeID,
				Type:    constants.FieldTypeReference,
			},
			want: constants.ObjectRecordType,
		},
	}

	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {
			if got := lookupRefObject(tt.field); got != tt.want {
				t.Fatalf("lookupRefObject(%+v) = %q, want %q", tt.field, got, tt.want)
			}
		})
	}
}

func TestProjectRelationshipSelectFieldsUsesRecordAccessInputsForPrivateTarget(t *testing.T) {
	accountRel := "Account"
	junctionSchema := &models.ObjectMetadata{
		APIName:      "Junction__c",
		SharingModel: constants.SharingModelPublicReadWrite,
		Fields: []models.FieldMetadata{
			{APIName: constants.FieldID, Type: constants.FieldTypeString, IsSystem: true},
			{
				APIName:          "AccountId",
				Type:             constants.FieldTypeReference,
				ReferenceTo:      []string{"Account"},
				RelationshipName: &accountRel,
			},
		},
	}
	accountSchema := &models.ObjectMetadata{
		APIName:      "Account",
		SharingModel: constants.SharingModelPrivate,
		Fields: []models.FieldMetadata{
			{APIName: constants.FieldID, Type: constants.FieldTypeString, IsSystem: true},
			{APIName: constants.FieldName, Type: constants.FieldTypeString, IsNameField: true},
			{APIName: constants.FieldOwnerID, Type: constants.FieldTypeReference, ReferenceTo: []string{constants.TableUser}, IsSystem: true},
			{APIName: "ExternalId__c", Type: constants.FieldTypeString},
		},
	}
	metaRepo := &displayNameMetadataRepository{schemas: []*models.ObjectMetadata{junctionSchema, accountSchema}}
	metadataSvc := metadata.NewMetadataService(metaRepo, nil, nil)
	permissionSvc := permissions.NewPermissionService(&searchPermissionRepository{}, metadataSvc, nil)
	repo := &displayNameQueryRepository{}
	qs := NewQueryService(repo, metadataSvc, permissionSvc, nil)
	rows := []models.SObject{{
		constants.FieldID: "jnc-1",
		"AccountId":       "acc-1",
	}}

	if err := qs.projectRelationshipSelectFields(context.Background(), junctionSchema, rows, []string{"Account.ExternalId__c"}, &models.UserSession{ID: "u1", ProfileID: "p1"}); err != nil {
		t.Fatalf("projectRelationshipSelectFields: %v", err)
	}

	if want := []string{constants.FieldID, "ExternalId__c", constants.FieldName, constants.FieldOwnerID}; !equalAnalyticsStringSlices(repo.lookupFetchFields, want) {
		t.Fatalf("lookup fetch fields = %#v, want %#v", repo.lookupFetchFields, want)
	}
	account, ok := rows[0]["Account"].(map[string]interface{})
	if !ok {
		t.Fatalf("Account nested relationship missing: %#v", rows[0])
	}
	if account["ExternalId__c"] != "EXT-1" {
		t.Fatalf("Account.ExternalId__c = %#v, want EXT-1", account["ExternalId__c"])
	}
}

type relationshipReferenceAuthorityStub struct {
	object  string
	records map[string]models.SObject
	unowned map[string]struct{}
}

func (s relationshipReferenceAuthorityStub) ResolveReferenceIdentities(
	_ context.Context, objectName string, ids []string, _ []string,
) (referenceidentity.Resolution, error) {
	if objectName != s.object {
		return referenceidentity.Resolution{}, nil
	}
	result := referenceidentity.Resolution{Identities: make(map[string]referenceidentity.IdentityResolution, len(ids))}
	for _, id := range ids {
		if _, ok := s.unowned[id]; ok {
			continue
		}
		if row := s.records[id]; row != nil {
			result.Identities[id] = referenceidentity.IdentityResolution{Disposition: referenceidentity.Immutable, Record: row}
		} else {
			result.Identities[id] = referenceidentity.IdentityResolution{Disposition: referenceidentity.OwnedMissing}
		}
	}
	return result, nil
}

func TestProjectRelationshipSelectFieldsUsesImmutableReferenceAuthority(t *testing.T) {
	definitionRel := "ProcessDefinition"
	instanceSchema := &models.ObjectMetadata{
		APIName: "ProcessInstance", SharingModel: constants.SharingModelPublicReadWrite,
		Fields: []models.FieldMetadata{
			{APIName: constants.FieldID, Type: constants.FieldTypeString, IsSystem: true},
			{APIName: "ProcessDefinitionId", Type: constants.FieldTypeReference,
				ReferenceTo: []string{"ProcessDefinition"}, RelationshipName: &definitionRel},
		},
	}
	definitionSchema := &models.ObjectMetadata{
		APIName: "ProcessDefinition", SharingModel: constants.SharingModelPublicReadWrite,
		Fields: []models.FieldMetadata{
			{APIName: constants.FieldID, Type: constants.FieldTypeString, IsSystem: true},
			{APIName: constants.FieldName, Type: constants.FieldTypeString, IsNameField: true},
		},
	}
	metadataSvc := metadata.NewMetadataService(
		&displayNameMetadataRepository{schemas: []*models.ObjectMetadata{instanceSchema, definitionSchema}}, nil, nil,
	)
	repo := &displayNameQueryRepository{}
	qs := NewQueryService(repo, metadataSvc, permissions.NewPermissionService(&searchPermissionRepository{
		objectReads: map[string]bool{strings.ToLower(constants.TableProcessDefinition): false},
	}, metadataSvc, nil), nil)
	rows := []models.SObject{{constants.FieldID: "pi-1", "ProcessDefinitionId": "catalog-definition-1"}}
	ctx := t.Context()
	ctx = referenceidentity.WithAuthority(ctx, relationshipReferenceAuthorityStub{
		object: "ProcessDefinition",
		records: map[string]models.SObject{
			"catalog-definition-1": {constants.FieldID: "catalog-definition-1", constants.FieldName: "Catalog Approval"},
		},
	})
	if err := qs.projectRelationshipSelectFields(
		ctx, instanceSchema, rows, []string{"ProcessDefinition.Name"}, &models.UserSession{ID: "u1", ProfileID: "p1"},
	); err != nil {
		t.Fatalf("projectRelationshipSelectFields: %v", err)
	}
	if repo.lookupFetchFields != nil {
		t.Fatalf("physical relationship lookup fields = %#v, want no physical lookup", repo.lookupFetchFields)
	}
	definition, ok := rows[0]["ProcessDefinition"].(map[string]interface{})
	if !ok || definition[constants.FieldName] != "Catalog Approval" {
		t.Fatalf("ProcessDefinition relationship = %#v", rows[0]["ProcessDefinition"])
	}
}

func TestQueryWithSpecUsesImmutableReferenceAuthorityForLookupName(t *testing.T) {
	definitionRel := "ProcessDefinition"
	instanceSchema := &models.ObjectMetadata{
		APIName: "ProcessInstance", SharingModel: constants.SharingModelPublicReadWrite,
		Fields: []models.FieldMetadata{
			{APIName: constants.FieldID, Type: constants.FieldTypeString, IsSystem: true},
			{APIName: "ProcessDefinitionId", Type: constants.FieldTypeReference,
				ReferenceTo: []string{"ProcessDefinition"}, RelationshipName: &definitionRel},
		},
	}
	definitionSchema := &models.ObjectMetadata{
		APIName: "ProcessDefinition", SharingModel: constants.SharingModelPublicReadWrite,
		Fields: []models.FieldMetadata{
			{APIName: constants.FieldID, Type: constants.FieldTypeString, IsSystem: true},
			{APIName: constants.FieldName, Type: constants.FieldTypeString, IsNameField: true},
		},
	}
	metadataSvc := metadata.NewMetadataService(
		&displayNameMetadataRepository{schemas: []*models.ObjectMetadata{instanceSchema, definitionSchema}}, nil, nil,
	)
	repo := &catalogRelationshipQueryRepository{}
	qs := NewQueryService(repo, metadataSvc, permissions.NewPermissionService(&searchPermissionRepository{}, metadataSvc, nil), nil)
	ctx := referenceidentity.WithAuthority(t.Context(), relationshipReferenceAuthorityStub{
		object: "ProcessDefinition",
		records: map[string]models.SObject{
			"l2.approval.Quote.NA_DBaaS_250502": {
				constants.FieldID:   "l2.approval.Quote.NA_DBaaS_250502",
				constants.FieldName: "NA DBaaS 250502",
			},
		},
	})

	result, err := qs.QueryWithSpec(ctx, queryspec.QuerySpec{
		ObjectAPIName: "ProcessInstance",
		SelectFields:  []string{constants.FieldID, "ProcessDefinitionId", "ProcessDefinition.Name"},
	}, &models.UserSession{ID: "u1", ProfileID: "p1", IsSystemAdmin: true})
	if err != nil {
		t.Fatalf("QueryWithSpec: %v", err)
	}
	if repo.physicalLookupAttempted {
		t.Fatal("Catalog-owned ProcessDefinition used the physical lookup repository")
	}
	definition, ok := result.Records[0]["ProcessDefinition"].(map[string]interface{})
	if !ok || definition[constants.FieldName] != "NA DBaaS 250502" {
		t.Fatalf("ProcessDefinition relationship = %#v", result.Records[0]["ProcessDefinition"])
	}
}

func TestProjectRelationshipSelectFieldsSupportsCatalogAndLegacyIDsForSameObject(t *testing.T) {
	definitionRel := "ProcessDefinition"
	instanceSchema := &models.ObjectMetadata{
		APIName: "ProcessInstance", SharingModel: constants.SharingModelPublicReadWrite,
		Fields: []models.FieldMetadata{
			{APIName: constants.FieldID, Type: constants.FieldTypeString, IsSystem: true},
			{APIName: "ProcessDefinitionId", Type: constants.FieldTypeReference,
				ReferenceTo: []string{"ProcessDefinition"}, RelationshipName: &definitionRel},
		},
	}
	definitionSchema := &models.ObjectMetadata{
		APIName: "ProcessDefinition", SharingModel: constants.SharingModelPublicReadWrite,
		Fields: []models.FieldMetadata{
			{APIName: constants.FieldID, Type: constants.FieldTypeString, IsSystem: true},
			{APIName: constants.FieldName, Type: constants.FieldTypeString, IsNameField: true},
		},
	}
	metadataSvc := metadata.NewMetadataService(
		&displayNameMetadataRepository{schemas: []*models.ObjectMetadata{instanceSchema, definitionSchema}}, nil, nil,
	)
	repo := &displayNameQueryRepository{}
	qs := NewQueryService(repo, metadataSvc, permissions.NewPermissionService(&searchPermissionRepository{}, metadataSvc, nil), nil)
	rows := []models.SObject{
		{constants.FieldID: "pi-catalog", "ProcessDefinitionId": "catalog-definition"},
		{constants.FieldID: "pi-legacy", "ProcessDefinitionId": "legacy-definition"},
	}
	ctx := constants.WithSecurityContext(t.Context(), constants.SystemContext, "mixed relationship projection test")
	ctx = referenceidentity.WithAuthority(ctx, relationshipReferenceAuthorityStub{
		object: "ProcessDefinition",
		records: map[string]models.SObject{
			"catalog-definition": {constants.FieldID: "catalog-definition", constants.FieldName: "Catalog Approval"},
		},
		unowned: map[string]struct{}{"legacy-definition": {}},
	})
	if err := qs.projectRelationshipSelectFields(ctx, instanceSchema, rows, []string{"ProcessDefinition.Name"}, &models.UserSession{ID: "u1", ProfileID: "p1"}); err != nil {
		t.Fatalf("projectRelationshipSelectFields: %v", err)
	}
	if len(repo.lookupFetchIDs) != 1 || repo.lookupFetchIDs[0] != "legacy-definition" {
		t.Fatalf("physical relationship IDs = %#v, want legacy ID only", repo.lookupFetchIDs)
	}
	if got := rows[0]["ProcessDefinition"].(map[string]interface{})[constants.FieldName]; got != "Catalog Approval" {
		t.Fatalf("Catalog ProcessDefinition.Name = %#v", got)
	}
	if got := rows[1]["ProcessDefinition"].(map[string]interface{})[constants.FieldName]; got != "Legacy Approval" {
		t.Fatalf("legacy ProcessDefinition.Name = %#v", got)
	}
}

func TestProjectRelationshipSelectFieldsFiltersReadProtectedDisplayNameUnderSystemContext(t *testing.T) {
	accountRel := "Account"
	junctionSchema := &models.ObjectMetadata{
		APIName:      "Junction__c",
		SharingModel: constants.SharingModelPublicReadWrite,
		Fields: []models.FieldMetadata{
			{APIName: constants.FieldID, Type: constants.FieldTypeString, IsSystem: true},
			{
				APIName:          "AccountId",
				Type:             constants.FieldTypeReference,
				ReferenceTo:      []string{"Account"},
				RelationshipName: &accountRel,
			},
		},
	}
	accountSchema := &models.ObjectMetadata{
		APIName:      "Account",
		SharingModel: constants.SharingModelPublicReadWrite,
		Fields: []models.FieldMetadata{
			{APIName: constants.FieldID, Type: constants.FieldTypeString, IsSystem: true},
			{
				APIName:              constants.FieldName,
				Type:                 constants.FieldTypeString,
				IsNameField:          true,
				ReadProtectionPolicy: constants.FieldReadProtectionBlocked,
			},
		},
	}
	metaRepo := &displayNameMetadataRepository{schemas: []*models.ObjectMetadata{junctionSchema, accountSchema}}
	metadataSvc := metadata.NewMetadataService(metaRepo, nil, nil)
	permissionSvc := permissions.NewPermissionService(&searchPermissionRepository{}, metadataSvc, nil)
	repo := &displayNameQueryRepository{}
	qs := NewQueryService(repo, metadataSvc, permissionSvc, nil)
	rows := []models.SObject{{
		constants.FieldID: "jnc-1",
		"AccountId":       "acc-1",
	}}
	ctx := constants.WithSecurityContext(context.Background(), constants.SystemContext, "test read-protected relationship display")

	if err := qs.projectRelationshipSelectFields(ctx, junctionSchema, rows, []string{"Account.Name"}, &models.UserSession{ID: "u1", ProfileID: "p1"}); err != nil {
		t.Fatalf("projectRelationshipSelectFields: %v", err)
	}

	if want := []string{constants.FieldID}; !equalAnalyticsStringSlices(repo.lookupFetchFields, want) {
		t.Fatalf("lookup fetch fields = %#v, want %#v", repo.lookupFetchFields, want)
	}
	account, ok := rows[0]["Account"].(map[string]interface{})
	if !ok {
		t.Fatalf("Account nested relationship missing: %#v", rows[0])
	}
	if _, ok := account[constants.FieldName]; ok {
		t.Fatalf("read-protected Account.Name leaked in nested relationship: %#v", account)
	}
}

func TestProjectRelationshipSelectFieldsFiltersReadProtectedNonNameChildUnderSystemContext(t *testing.T) {
	accountRel := "Account"
	junctionSchema := &models.ObjectMetadata{
		APIName:      "Junction__c",
		SharingModel: constants.SharingModelPublicReadWrite,
		Fields: []models.FieldMetadata{
			{APIName: constants.FieldID, Type: constants.FieldTypeString, IsSystem: true},
			{
				APIName:          "AccountId",
				Type:             constants.FieldTypeReference,
				ReferenceTo:      []string{"Account"},
				RelationshipName: &accountRel,
			},
		},
	}
	accountSchema := &models.ObjectMetadata{
		APIName:      "Account",
		SharingModel: constants.SharingModelPublicReadWrite,
		Fields: []models.FieldMetadata{
			{APIName: constants.FieldID, Type: constants.FieldTypeString, IsSystem: true},
			{
				APIName:              "SecretText__c",
				Type:                 constants.FieldTypeString,
				ReadProtectionPolicy: constants.FieldReadProtectionBlocked,
			},
		},
	}
	metaRepo := &displayNameMetadataRepository{schemas: []*models.ObjectMetadata{junctionSchema, accountSchema}}
	metadataSvc := metadata.NewMetadataService(metaRepo, nil, nil)
	permissionSvc := permissions.NewPermissionService(&searchPermissionRepository{}, metadataSvc, nil)
	repo := &displayNameQueryRepository{}
	qs := NewQueryService(repo, metadataSvc, permissionSvc, nil)
	rows := []models.SObject{{
		constants.FieldID: "jnc-1",
		"AccountId":       "acc-1",
	}}
	ctx := constants.WithSecurityContext(context.Background(), constants.SystemContext, "test read-protected relationship child")

	if err := qs.projectRelationshipSelectFields(ctx, junctionSchema, rows, []string{"Account.SecretText__c"}, &models.UserSession{ID: "u1", ProfileID: "p1"}); err != nil {
		t.Fatalf("projectRelationshipSelectFields: %v", err)
	}

	if want := []string{constants.FieldID}; !equalAnalyticsStringSlices(repo.lookupFetchFields, want) {
		t.Fatalf("lookup fetch fields = %#v, want %#v", repo.lookupFetchFields, want)
	}
	account, ok := rows[0]["Account"].(map[string]interface{})
	if !ok {
		t.Fatalf("Account nested relationship missing: %#v", rows[0])
	}
	if _, ok := account["SecretText__c"]; ok {
		t.Fatalf("read-protected Account.SecretText__c leaked in nested relationship: %#v", account)
	}
}

func TestQueryRejectsPolymorphicDotNotationSelect(t *testing.T) {
	whoRel := "Who"
	taskSchema := &models.ObjectMetadata{
		APIName:      "Task",
		SharingModel: constants.SharingModelPublicReadWrite,
		Fields: []models.FieldMetadata{
			{APIName: constants.FieldID, Type: constants.FieldTypeString, IsSystem: true},
			{APIName: constants.FieldName, Type: constants.FieldTypeString, IsNameField: true},
			{
				APIName:          "WhoId",
				Type:             constants.FieldTypeReference,
				ReferenceTo:      []string{"Contact", "Lead"},
				IsPolymorphic:    true,
				RelationshipName: &whoRel,
			},
		},
	}
	metaRepo := &displayNameMetadataRepository{schemas: []*models.ObjectMetadata{taskSchema}}
	metadataSvc := metadata.NewMetadataService(metaRepo, nil, nil)
	permissionSvc := permissions.NewPermissionService(&searchPermissionRepository{}, metadataSvc, nil)
	repo := &displayNameQueryRepository{}
	qs := NewQueryService(repo, metadataSvc, permissionSvc, nil)

	_, err := qs.QueryWithSpec(context.Background(), queryspec.QuerySpec{
		ObjectAPIName: "Task",
		SelectFields:  []string{"Who.Name"},
	}, &models.UserSession{ID: "u1", ProfileID: "p1", IsSystemAdmin: true})
	if err == nil {
		t.Fatal("Query error = nil, want polymorphic dot-notation rejection")
	}
	if !strings.Contains(err.Error(), "WhoId") || !strings.Contains(err.Error(), "polymorphic") {
		t.Fatalf("Query error = %q, want WhoId polymorphic rejection", err.Error())
	}
	if len(repo.findSelectFields) != 0 {
		t.Fatalf("repo was called with select fields %#v; want validation before query execution", repo.findSelectFields)
	}
}

func TestQueryRejectsUnknownDotNotationChild(t *testing.T) {
	accountRel := "Account"
	junctionSchema := &models.ObjectMetadata{
		APIName:      "Junction__c",
		SharingModel: constants.SharingModelPublicReadWrite,
		Fields: []models.FieldMetadata{
			{APIName: constants.FieldID, Type: constants.FieldTypeString, IsSystem: true},
			{APIName: constants.FieldName, Type: constants.FieldTypeString, IsNameField: true},
			{
				APIName:          "AccountId",
				Type:             constants.FieldTypeReference,
				ReferenceTo:      []string{"Account"},
				RelationshipName: &accountRel,
			},
		},
	}
	accountSchema := &models.ObjectMetadata{
		APIName:      "Account",
		SharingModel: constants.SharingModelPublicReadWrite,
		Fields: []models.FieldMetadata{
			{APIName: constants.FieldID, Type: constants.FieldTypeString, IsSystem: true},
			{APIName: constants.FieldName, Type: constants.FieldTypeString, IsNameField: true},
		},
	}
	metaRepo := &displayNameMetadataRepository{schemas: []*models.ObjectMetadata{junctionSchema, accountSchema}}
	metadataSvc := metadata.NewMetadataService(metaRepo, nil, nil)
	permissionSvc := permissions.NewPermissionService(&searchPermissionRepository{}, metadataSvc, nil)
	repo := &displayNameQueryRepository{}
	qs := NewQueryService(repo, metadataSvc, permissionSvc, nil)

	_, err := qs.QueryWithSpec(context.Background(), queryspec.QuerySpec{
		ObjectAPIName: "Junction__c",
		SelectFields:  []string{"Account.DoesNotExist__c"},
	}, &models.UserSession{ID: "u1", ProfileID: "p1", IsSystemAdmin: true})
	if err == nil {
		t.Fatal("Query error = nil, want unknown dot-notation child rejection")
	}
	if !strings.Contains(err.Error(), "DoesNotExist__c") || !strings.Contains(err.Error(), "no field API name match") {
		t.Fatalf("Query error = %q, want unknown child rejection", err.Error())
	}
	if len(repo.findSelectFields) != 0 {
		t.Fatalf("repo was called with select fields %#v; want validation before query execution", repo.findSelectFields)
	}
}

func TestQueryRejectsVirtualDotNotationChild(t *testing.T) {
	accountRel := "Account"
	junctionSchema := &models.ObjectMetadata{
		APIName:      "Junction__c",
		SharingModel: constants.SharingModelPublicReadWrite,
		Fields: []models.FieldMetadata{
			{APIName: constants.FieldID, Type: constants.FieldTypeString, IsSystem: true},
			{APIName: constants.FieldName, Type: constants.FieldTypeString, IsNameField: true},
			{
				APIName:          "AccountId",
				Type:             constants.FieldTypeReference,
				ReferenceTo:      []string{"Account"},
				RelationshipName: &accountRel,
			},
		},
	}
	accountSchema := &models.ObjectMetadata{
		APIName:      "Account",
		SharingModel: constants.SharingModelPublicReadWrite,
		Fields: []models.FieldMetadata{
			{APIName: constants.FieldID, Type: constants.FieldTypeString, IsSystem: true},
			{APIName: constants.FieldName, Type: constants.FieldTypeString, IsNameField: true},
			{APIName: "First__c", Type: constants.FieldTypeString},
			{APIName: "Last__c", Type: constants.FieldTypeString},
			{
				APIName:      "Display__c",
				Type:         constants.FieldTypeFormula,
				IsVirtual:    true,
				VirtualKind:  constants.VirtualFieldCompound,
				IsCompound:   true,
				ComposedFrom: []string{"First__c", "Last__c"},
			},
		},
	}
	metaRepo := &displayNameMetadataRepository{schemas: []*models.ObjectMetadata{junctionSchema, accountSchema}}
	metadataSvc := metadata.NewMetadataService(metaRepo, nil, nil)
	permissionSvc := permissions.NewPermissionService(&searchPermissionRepository{}, metadataSvc, nil)
	repo := &displayNameQueryRepository{}
	qs := NewQueryService(repo, metadataSvc, permissionSvc, nil)

	_, err := qs.QueryWithSpec(context.Background(), queryspec.QuerySpec{
		ObjectAPIName: "Junction__c",
		SelectFields:  []string{"Account.Display__c"},
	}, &models.UserSession{ID: "u1", ProfileID: "p1", IsSystemAdmin: true})
	if err == nil {
		t.Fatal("Query error = nil, want virtual dot-notation child rejection")
	}
	if !strings.Contains(err.Error(), "Display__c") || !strings.Contains(err.Error(), "virtual or compound child field") {
		t.Fatalf("Query error = %q, want virtual child rejection", err.Error())
	}
	if len(repo.findSelectFields) != 0 {
		t.Fatalf("repo was called with select fields %#v; want validation before query execution", repo.findSelectFields)
	}
}

func TestExecuteSubQueriesHydratesAndProjectsDotNotationChild(t *testing.T) {
	junctionsRel := "Junctions__r"
	accountRel := "Account"
	parentSchema := &models.ObjectMetadata{
		APIName:      "Parent__c",
		SharingModel: constants.SharingModelPublicReadWrite,
		Fields: []models.FieldMetadata{
			{APIName: constants.FieldID, Type: constants.FieldTypeString, IsSystem: true},
			{APIName: constants.FieldName, Type: constants.FieldTypeString, IsNameField: true},
		},
	}
	junctionSchema := &models.ObjectMetadata{
		APIName:      "Junction__c",
		SharingModel: constants.SharingModelPublicReadWrite,
		Fields: []models.FieldMetadata{
			{APIName: constants.FieldID, Type: constants.FieldTypeString, IsSystem: true},
			{APIName: constants.FieldName, Type: constants.FieldTypeString, IsNameField: true},
			{
				APIName:               "Parent__c",
				Type:                  constants.FieldTypeReference,
				ReferenceTo:           []string{"Parent__c"},
				ChildRelationshipName: &junctionsRel,
			},
			{
				APIName:          "AccountId",
				Type:             constants.FieldTypeReference,
				ReferenceTo:      []string{"Account"},
				RelationshipName: &accountRel,
			},
		},
	}
	accountSchema := &models.ObjectMetadata{
		APIName:      "Account",
		SharingModel: constants.SharingModelPublicReadWrite,
		Fields: []models.FieldMetadata{
			{APIName: constants.FieldID, Type: constants.FieldTypeString, IsSystem: true},
			{APIName: constants.FieldName, Type: constants.FieldTypeString, IsNameField: true},
			{APIName: "ExternalId__c", Type: constants.FieldTypeString},
		},
	}
	metaRepo := &displayNameMetadataRepository{schemas: []*models.ObjectMetadata{parentSchema, junctionSchema, accountSchema}}
	metadataSvc := metadata.NewMetadataService(metaRepo, nil, nil)
	permissionSvc := permissions.NewPermissionService(&searchPermissionRepository{}, metadataSvc, nil)
	repo := &subqueryDisplayNameQueryRepository{lookupFetchFieldsByObject: make(map[string][]string)}
	qs := NewQueryService(repo, metadataSvc, permissionSvc, nil)

	parentRecords := []models.SObject{{constants.FieldID: "parent-1"}}
	got, err := qs.executeSubQueries(context.Background(), parentRecords, parentSchema, []models.SubQueryRequest{{
		RelationshipName: "Junctions__r",
		SelectFields:     []string{"Account.ExternalId__c"},
	}}, &models.UserSession{ID: "u1", ProfileID: "p1", IsSystemAdmin: true}, false)
	if err != nil {
		t.Fatalf("executeSubQueries: %v", err)
	}

	if want := []string{constants.FieldID, "AccountId", "Parent__c"}; !equalAnalyticsStringSlices(repo.findSelectFields, want) {
		t.Fatalf("repo select fields = %#v, want %#v", repo.findSelectFields, want)
	}
	if want := []string{constants.FieldID, constants.FieldName, "ExternalId__c"}; !equalAnalyticsStringSlices(repo.lookupFetchFieldsByObject["Account"], want) {
		t.Fatalf("account lookup fetch fields = %#v, want %#v", repo.lookupFetchFieldsByObject["Account"], want)
	}

	// App-blind L0 attaches the neutral child-records slice directly (no SF
	// {totalSize,done,records} envelope; the dialect re-wraps that).
	childRecords, ok := got[0]["Junctions__r"].([]models.SObject)
	if !ok || len(childRecords) != 1 {
		t.Fatalf("child records = %#v, want one neutral SObject slice", got[0]["Junctions__r"])
	}
	child := childRecords[0]
	if got := models.RecordObjectType(child); got != "Junction__c" {
		t.Fatalf("child object type = %q, want Junction__c; record=%#v", got, child)
	}
	account, ok := child["Account"].(map[string]interface{})
	if !ok {
		t.Fatalf("Account nested relationship missing from child row: %#v", child)
	}
	if account["ExternalId__c"] != "EXT-1" {
		t.Fatalf("Account.ExternalId__c = %#v, want EXT-1", account["ExternalId__c"])
	}
	if _, ok := account[constants.FieldName]; ok {
		t.Fatalf("unexpected support-only Account.Name in nested relationship: %#v", account)
	}
	for _, supportField := range []string{"AccountId", "AccountId_Name", "Parent__c", "Parent__c_Name"} {
		if _, ok := child[supportField]; ok {
			t.Fatalf("unexpected support-only %s on child response: %#v", supportField, child)
		}
	}
}

func TestExecuteSubQueriesRejectsPolymorphicDotNotationChild(t *testing.T) {
	junctionsRel := "Junctions__r"
	whoRel := "Who"
	parentSchema := &models.ObjectMetadata{
		APIName:      "Parent__c",
		SharingModel: constants.SharingModelPublicReadWrite,
		Fields: []models.FieldMetadata{
			{APIName: constants.FieldID, Type: constants.FieldTypeString, IsSystem: true},
			{APIName: constants.FieldName, Type: constants.FieldTypeString, IsNameField: true},
		},
	}
	junctionSchema := &models.ObjectMetadata{
		APIName:      "Junction__c",
		SharingModel: constants.SharingModelPublicReadWrite,
		Fields: []models.FieldMetadata{
			{APIName: constants.FieldID, Type: constants.FieldTypeString, IsSystem: true},
			{APIName: constants.FieldName, Type: constants.FieldTypeString, IsNameField: true},
			{
				APIName:               "Parent__c",
				Type:                  constants.FieldTypeReference,
				ReferenceTo:           []string{"Parent__c"},
				ChildRelationshipName: &junctionsRel,
			},
			{
				APIName:          "WhoId",
				Type:             constants.FieldTypeReference,
				ReferenceTo:      []string{"Contact", "Lead"},
				IsPolymorphic:    true,
				RelationshipName: &whoRel,
			},
		},
	}
	metaRepo := &displayNameMetadataRepository{schemas: []*models.ObjectMetadata{parentSchema, junctionSchema}}
	metadataSvc := metadata.NewMetadataService(metaRepo, nil, nil)
	permissionSvc := permissions.NewPermissionService(&searchPermissionRepository{}, metadataSvc, nil)
	repo := &subqueryDisplayNameQueryRepository{lookupFetchFieldsByObject: make(map[string][]string)}
	qs := NewQueryService(repo, metadataSvc, permissionSvc, nil)

	_, err := qs.executeSubQueries(context.Background(), []models.SObject{{constants.FieldID: "parent-1"}}, parentSchema, []models.SubQueryRequest{{
		RelationshipName: "Junctions__r",
		SelectFields:     []string{"Who.Name"},
	}}, &models.UserSession{ID: "u1", ProfileID: "p1", IsSystemAdmin: true}, false)
	if err == nil {
		t.Fatal("executeSubQueries error = nil, want polymorphic dot-notation rejection")
	}
	if !strings.Contains(err.Error(), "WhoId") || !strings.Contains(err.Error(), "polymorphic") {
		t.Fatalf("executeSubQueries error = %q, want WhoId polymorphic rejection", err.Error())
	}
}

func TestExecuteSubQueriesRejectsDotNotationChild(t *testing.T) {
	tests := []struct {
		name               string
		extraAccountFields []models.FieldMetadata
		selectField        string
		wantErrParts       []string
		nilErrMessage      string
		mismatchMessage    string
	}{
		{
			name:            "UnknownDotNotationChild",
			selectField:     "Account.DoesNotExist__c",
			wantErrParts:    []string{"DoesNotExist__c", "no field API name match"},
			nilErrMessage:   "executeSubQueries error = nil, want unknown dot-notation child rejection",
			mismatchMessage: "executeSubQueries error = %q, want unknown child rejection",
		},
		{
			name: "VirtualDotNotationChild",
			extraAccountFields: []models.FieldMetadata{
				{APIName: "First__c", Type: constants.FieldTypeString},
				{APIName: "Last__c", Type: constants.FieldTypeString},
				{
					APIName:      "Display__c",
					Type:         constants.FieldTypeFormula,
					IsVirtual:    true,
					VirtualKind:  constants.VirtualFieldCompound,
					IsCompound:   true,
					ComposedFrom: []string{"First__c", "Last__c"},
				},
			},
			selectField:     "Account.Display__c",
			wantErrParts:    []string{"Display__c", "virtual or compound child field"},
			nilErrMessage:   "executeSubQueries error = nil, want virtual dot-notation child rejection",
			mismatchMessage: "executeSubQueries error = %q, want virtual child rejection",
		},
	}
	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {
			junctionsRel := "Junctions__r"
			accountRel := "Account"
			parentSchema := &models.ObjectMetadata{
				APIName:      "Parent__c",
				SharingModel: constants.SharingModelPublicReadWrite,
				Fields: []models.FieldMetadata{
					{APIName: constants.FieldID, Type: constants.FieldTypeString, IsSystem: true},
					{APIName: constants.FieldName, Type: constants.FieldTypeString, IsNameField: true},
				},
			}
			junctionSchema := &models.ObjectMetadata{
				APIName:      "Junction__c",
				SharingModel: constants.SharingModelPublicReadWrite,
				Fields: []models.FieldMetadata{
					{APIName: constants.FieldID, Type: constants.FieldTypeString, IsSystem: true},
					{APIName: constants.FieldName, Type: constants.FieldTypeString, IsNameField: true},
					{
						APIName:               "Parent__c",
						Type:                  constants.FieldTypeReference,
						ReferenceTo:           []string{"Parent__c"},
						ChildRelationshipName: &junctionsRel,
					},
					{
						APIName:          "AccountId",
						Type:             constants.FieldTypeReference,
						ReferenceTo:      []string{"Account"},
						RelationshipName: &accountRel,
					},
				},
			}
			accountSchema := &models.ObjectMetadata{
				APIName:      "Account",
				SharingModel: constants.SharingModelPublicReadWrite,
				Fields: append([]models.FieldMetadata{
					{APIName: constants.FieldID, Type: constants.FieldTypeString, IsSystem: true},
					{APIName: constants.FieldName, Type: constants.FieldTypeString, IsNameField: true},
				}, tt.extraAccountFields...),
			}
			metaRepo := &displayNameMetadataRepository{schemas: []*models.ObjectMetadata{parentSchema, junctionSchema, accountSchema}}
			metadataSvc := metadata.NewMetadataService(metaRepo, nil, nil)
			permissionSvc := permissions.NewPermissionService(&searchPermissionRepository{}, metadataSvc, nil)
			repo := &subqueryDisplayNameQueryRepository{lookupFetchFieldsByObject: make(map[string][]string)}
			qs := NewQueryService(repo, metadataSvc, permissionSvc, nil)

			_, err := qs.executeSubQueries(context.Background(), []models.SObject{{constants.FieldID: "parent-1"}}, parentSchema, []models.SubQueryRequest{{
				RelationshipName: "Junctions__r",
				SelectFields:     []string{tt.selectField},
			}}, &models.UserSession{ID: "u1", ProfileID: "p1", IsSystemAdmin: true}, false)
			if err == nil {
				t.Fatal(tt.nilErrMessage)
			}
			for _, part := range tt.wantErrParts {
				if !strings.Contains(err.Error(), part) {
					t.Fatalf(tt.mismatchMessage, err.Error())
				}
			}
		})
	}
}

type displayNameMetadataRepository struct {
	ports.MetadataRepository

	schemas []*models.ObjectMetadata
}

func (r *displayNameMetadataRepository) GetAllSchemas(ctx context.Context) ([]*models.ObjectMetadata, error) {
	return r.schemas, nil
}

func (r *displayNameMetadataRepository) GetSchemaByAPIName(ctx context.Context, apiName string) (*models.ObjectMetadata, error) {
	for _, schema := range r.schemas {
		if strings.EqualFold(schema.APIName, apiName) {
			return schema, nil
		}
	}
	return nil, nil
}

func (r *displayNameMetadataRepository) GetAllRelationships(ctx context.Context) ([]*models.Relationship, error) {
	return nil, nil
}

func (r *displayNameMetadataRepository) GetSharingRules(ctx context.Context, objectAPIName string) ([]*models.SharingRule, error) {
	return nil, nil
}

type displayNameQueryRepository struct {
	ports.QueryRepository

	findSelectFields  []string
	lookupFetchFields []string
	lookupFetchIDs    []string
}

type catalogRelationshipQueryRepository struct {
	ports.QueryRepository
	physicalLookupAttempted bool
}

func (r *catalogRelationshipQueryRepository) Find(
	_ context.Context,
	_ *models.ObjectMetadata,
	_ models.QueryRequest,
	_ *domainrls.Result,
	_ []string,
) (*models.QueryResult, error) {
	return &models.QueryResult{
		TotalSize: 1,
		Done:      true,
		Records: []models.SObject{{
			constants.FieldID:     "pi-1",
			"ProcessDefinitionId": "l2.approval.Quote.NA_DBaaS_250502",
		}},
	}, nil
}

func (r *catalogRelationshipQueryRepository) GetRecordsByIDs(
	_ context.Context,
	_ *models.ObjectMetadata,
	_ []string,
	_ []string,
) ([]models.SObject, error) {
	r.physicalLookupAttempted = true
	return nil, nil
}

func (r *displayNameQueryRepository) Find(ctx context.Context, schema *models.ObjectMetadata, req models.QueryRequest, rlsResult *domainrls.Result, visibleFields []string) (*models.QueryResult, error) {
	r.findSelectFields = append([]string(nil), req.SelectFields...)
	return &models.QueryResult{
		TotalSize: 1,
		Done:      true,
		Records: []models.SObject{{
			constants.FieldID: "jnc-1",
			"AccountId":       "acc-1",
		}},
	}, nil
}

func (r *displayNameQueryRepository) GetRecordsByIDs(ctx context.Context, schema *models.ObjectMetadata, ids []string, fields []string) ([]models.SObject, error) {
	r.lookupFetchFields = append([]string(nil), fields...)
	r.lookupFetchIDs = append([]string(nil), ids...)
	result := make([]models.SObject, 0, len(ids))
	for _, id := range ids {
		row := models.SObject{
			constants.FieldID: id, constants.FieldName: "Legacy Approval", constants.FieldOwnerID: "u1",
		}
		if id == "acc-1" {
			row[constants.FieldName] = "Acme"
			row["ExternalId__c"] = "EXT-1"
		}
		result = append(result, projectDisplayNameRecord(row, fields))
	}
	return result, nil
}

type platformLookupNameQueryRepository struct {
	ports.QueryRepository

	lookupObject string
}

func (r *platformLookupNameQueryRepository) Find(ctx context.Context, schema *models.ObjectMetadata, req models.QueryRequest, rlsResult *domainrls.Result, visibleFields []string) (*models.QueryResult, error) {
	return &models.QueryResult{
		TotalSize: 1,
		Done:      true,
		Records: []models.SObject{{
			constants.FieldID:           "acc-1",
			constants.FieldRecordTypeID: "rt-1",
		}},
	}, nil
}

func (r *platformLookupNameQueryRepository) GetRecordsByIDs(ctx context.Context, schema *models.ObjectMetadata, ids []string, fields []string) ([]models.SObject, error) {
	r.lookupObject = schema.APIName
	return []models.SObject{projectDisplayNameRecord(models.SObject{
		constants.FieldID:   "rt-1",
		constants.FieldName: "Business Account",
	}, fields)}, nil
}

type subqueryDisplayNameQueryRepository struct {
	ports.QueryRepository

	findSelectFields          []string
	lookupFetchFieldsByObject map[string][]string
}

func (r *subqueryDisplayNameQueryRepository) Find(ctx context.Context, schema *models.ObjectMetadata, req models.QueryRequest, rlsResult *domainrls.Result, visibleFields []string) (*models.QueryResult, error) {
	r.findSelectFields = append([]string(nil), req.SelectFields...)
	return &models.QueryResult{
		TotalSize: 1,
		Done:      true,
		Records: []models.SObject{{
			constants.FieldID: "jnc-1",
			"Parent__c":       "parent-1",
			"AccountId":       "acc-1",
		}},
	}, nil
}

func (r *subqueryDisplayNameQueryRepository) GetRecordsByIDs(ctx context.Context, schema *models.ObjectMetadata, ids []string, fields []string) ([]models.SObject, error) {
	r.lookupFetchFieldsByObject[schema.APIName] = append([]string(nil), fields...)
	switch schema.APIName {
	case "Account":
		return []models.SObject{projectDisplayNameRecord(models.SObject{
			constants.FieldID:      "acc-1",
			constants.FieldName:    "Acme",
			constants.FieldOwnerID: "u1",
			"ExternalId__c":        "EXT-1",
		}, fields)}, nil
	case "Parent__c":
		return []models.SObject{projectDisplayNameRecord(models.SObject{
			constants.FieldID:   "parent-1",
			constants.FieldName: "Parent",
		}, fields)}, nil
	default:
		return nil, nil
	}
}

func projectDisplayNameRecord(record models.SObject, fields []string) models.SObject {
	projected := make(models.SObject, len(fields))
	for _, field := range fields {
		if value, ok := record[field]; ok {
			projected[field] = value
		}
	}
	return projected
}
