package analytics_test

import (
	"context"
	"testing"

	"github.com/nexuscrm/backend/internal/domain/ports"
	"github.com/nexuscrm/backend/internal/domain/rls"
	"github.com/nexuscrm/backend/internal/features/analytics"
	"github.com/nexuscrm/backend/internal/features/metadata"
	"github.com/nexuscrm/backend/internal/features/permissions"
	"github.com/nexuscrm/shared/pkg/constants"
	"github.com/nexuscrm/shared/pkg/models"

	"github.com/stretchr/testify/assert"
	"github.com/stretchr/testify/mock"
)

// --- Mock Query Repo ---

type MockQueryRepo struct {
	mock.Mock
}

func (m *MockQueryRepo) Search(ctx context.Context, schema *models.ObjectMetadata, term string, searchFields []string, selectFields []string, limit int, offset int, orderBy string, orderDir string, filterExpr string, rlsResult *rls.Result) ([]models.SObject, error) {
	args := m.Called(ctx, schema, term, searchFields, selectFields, limit, offset, orderBy, orderDir, filterExpr, rlsResult)
	if args.Get(0) == nil {
		return nil, args.Error(1)
	}
	return args.Get(0).([]models.SObject), args.Error(1)
}

// Stubs for QueryRepository
func (m *MockQueryRepo) Find(ctx context.Context, tableSchema *models.ObjectMetadata, req models.QueryRequest, rlsResult *rls.Result, visibleFields []string) (*models.QueryResult, error) {
	return nil, nil
}
func (m *MockQueryRepo) RunAnalytics(ctx context.Context, tableSchema *models.ObjectMetadata, q models.AnalyticsQuery, rlsResult *rls.Result) (interface{}, error) {
	return nil, nil
}
func (m *MockQueryRepo) ExecuteRawSQL(ctx context.Context, sql string, params []interface{}) ([]models.SObject, error) {
	return nil, nil
}
func (m *MockQueryRepo) GetLookupNames(ctx context.Context, tableSchema *models.ObjectMetadata, ids []string, idField string, nameField string) ([]models.SObject, error) {
	return nil, nil
}
func (m *MockQueryRepo) GetRecordsByIDs(ctx context.Context, tableSchema *models.ObjectMetadata, ids []string, fields []string) ([]models.SObject, error) {
	args := m.Called(ctx, tableSchema, ids, fields)
	if args.Get(0) == nil {
		return nil, args.Error(1)
	}
	return args.Get(0).([]models.SObject), args.Error(1)
}

// --- Mock Metadata Repo ---

type MockMetaRepo struct {
	mock.Mock
}

func (m *MockMetaRepo) GetAllSchemas(ctx context.Context) ([]*models.ObjectMetadata, error) {
	args := m.Called(ctx)
	if args.Get(0) == nil {
		return nil, args.Error(1)
	}
	return args.Get(0).([]*models.ObjectMetadata), args.Error(1)
}

func (m *MockMetaRepo) GetSchemaByAPIName(ctx context.Context, apiName string) (*models.ObjectMetadata, error) {
	args := m.Called(ctx, apiName)
	if args.Get(0) == nil {
		return nil, args.Error(1)
	}
	return args.Get(0).(*models.ObjectMetadata), args.Error(1)
}

// Stubs for MetadataRepository
func (m *MockMetaRepo) GetFieldsForObject(ctx context.Context, objectID string) ([]models.FieldMetadata, error) {
	return nil, nil
}
func (m *MockMetaRepo) GetRecordTypes(ctx context.Context, objectAPIName string) ([]*models.RecordType, error) {
	return nil, nil
}
func (m *MockMetaRepo) GetAutoNumbers(ctx context.Context, objectAPIName string) ([]*models.AutoNumber, error) {
	return nil, nil
}
func (m *MockMetaRepo) GetAllAutoNumbers(_ context.Context) ([]*models.AutoNumber, error) {
	return nil, nil
}
func (m *MockMetaRepo) GetAllIdentifierRules(_ context.Context) ([]*models.IdentifierRule, error) {
	return nil, nil
}
func (m *MockMetaRepo) GetAllValidationRules(_ context.Context) ([]*models.ValidationRule, error) {
	return nil, nil
}
func (m *MockMetaRepo) GetAllRelationships(_ context.Context) ([]*models.Relationship, error) {
	return nil, nil
}
func (m *MockMetaRepo) GetRelationships(ctx context.Context, childObjectAPIName string) ([]*models.Relationship, error) {
	return nil, nil
}
func (m *MockMetaRepo) GetFieldDependencies(ctx context.Context, objectAPIName string) ([]*models.FieldDependency, error) {
	return nil, nil
}
func (m *MockMetaRepo) GetChildRelationships(ctx context.Context, parentObjectAPIName string) ([]*models.ObjectMetadata, error) {
	return nil, nil
}
func (m *MockMetaRepo) ConfigureAutoNumberField(ctx context.Context, objectAPIName, fieldAPIName, format string, start int64) error {
	return nil
}
func (m *MockMetaRepo) UpsertUIComponent(ctx context.Context, component *models.UIComponent) error {
	return nil
}
func (m *MockMetaRepo) UpsertSetupPage(ctx context.Context, page *models.SetupPage) error { return nil }
func (m *MockMetaRepo) GetSetupPages(ctx context.Context) ([]*models.SetupPage, error) {
	return nil, nil
}
func (m *MockMetaRepo) UpsertLayout(ctx context.Context, layout *models.PageLayout) error { return nil }
func (m *MockMetaRepo) SaveLayout(ctx context.Context, layout *models.PageLayout) error   { return nil }
func (m *MockMetaRepo) GetLayout(ctx context.Context, id string) (*models.PageLayout, error) {
	return nil, nil
}
func (m *MockQueryRepo) MarkLayoutCustomized(_ context.Context, _ string) {}
func (m *MockMetaRepo) GetLayouts(ctx context.Context, objectAPIName string) ([]*models.PageLayout, error) {
	return nil, nil
}
func (m *MockMetaRepo) DeleteLayout(ctx context.Context, id string) error { return nil }
func (m *MockMetaRepo) SetDefaultLayout(ctx context.Context, objectAPIName string, layoutID string, actorID *string) error {
	return nil
}
func (m *MockMetaRepo) AssignLayoutToProfile(ctx context.Context, profileID, objectAPIName, layoutID string) error {
	return nil
}
func (m *MockMetaRepo) GetLayoutIDForProfile(ctx context.Context, objectAPIName, profileID string) (string, error) {
	return "", nil
}
func (m *MockMetaRepo) GetRelatedListConfigs(ctx context.Context, layoutObjectAPIName string) ([]ports.RelatedListConfig, error) {
	return nil, nil
}
func (m *MockMetaRepo) GetActiveTheme(ctx context.Context) (*models.Theme, error) { return nil, nil }
func (m *MockMetaRepo) GetThemeByName(ctx context.Context, name string) (*models.Theme, error) {
	return nil, nil
}
func (m *MockMetaRepo) CreateTheme(ctx context.Context, theme *models.Theme) error  { return nil }
func (m *MockMetaRepo) UpdateTheme(ctx context.Context, theme *models.Theme) error  { return nil }
func (m *MockMetaRepo) ActivateTheme(ctx context.Context, themeID string) error     { return nil }
func (m *MockMetaRepo) GetAllApps(ctx context.Context) ([]*models.AppConfig, error) { return nil, nil }
func (m *MockMetaRepo) GetApp(ctx context.Context, id string) (*models.AppConfig, error) {
	return nil, nil
}
func (m *MockMetaRepo) GetAppWithTx(ctx context.Context, tx interface{}, id string) (*models.AppConfig, error) {
	return nil, nil
}
func (m *MockMetaRepo) CreateApp(ctx context.Context, app *models.AppConfig) error { return nil }
func (m *MockMetaRepo) CreateAppMenuItem(ctx context.Context, app *models.AppConfig) error {
	return nil
}
func (m *MockMetaRepo) UpdateApp(ctx context.Context, id string, app *models.AppConfig) error {
	return nil
}
func (m *MockMetaRepo) UpdateAppWithTx(ctx context.Context, tx interface{}, id string, app *models.AppConfig) error {
	return nil
}
func (m *MockMetaRepo) DeleteApp(ctx context.Context, id string) error { return nil }
func (m *MockMetaRepo) GetAllDashboards(ctx context.Context) ([]*models.DashboardConfig, error) {
	return nil, nil
}
func (m *MockMetaRepo) GetDashboard(ctx context.Context, id string) (*models.DashboardConfig, error) {
	return nil, nil
}
func (m *MockMetaRepo) CreateDashboard(ctx context.Context, dashboard *models.DashboardConfig) error {
	return nil
}
func (m *MockMetaRepo) UpdateDashboard(ctx context.Context, id string, dashboard *models.DashboardConfig) error {
	return nil
}
func (m *MockMetaRepo) DeleteDashboard(ctx context.Context, id string) error { return nil }
func (m *MockMetaRepo) GetListViews(ctx context.Context, objectAPIName string) ([]*models.ListView, error) {
	return nil, nil
}
func (m *MockMetaRepo) CreateListView(ctx context.Context, lv *models.ListView) error { return nil }
func (m *MockMetaRepo) UpdateListView(ctx context.Context, id string, lv *models.ListView) error {
	return nil
}
func (m *MockMetaRepo) DeleteListView(ctx context.Context, id string) error { return nil }
func (m *MockMetaRepo) CountListViews(ctx context.Context, objectAPIName string) (int, error) {
	return 0, nil
}
func (m *MockMetaRepo) GetActions(ctx context.Context, objectAPIName string) ([]*models.ActionMetadata, error) {
	return nil, nil
}
func (m *MockMetaRepo) GetAction(ctx context.Context, id string) (*models.ActionMetadata, error) {
	return nil, nil
}
func (m *MockMetaRepo) GetAllActions(ctx context.Context) ([]*models.ActionMetadata, error) {
	return nil, nil
}
func (m *MockMetaRepo) CreateAction(ctx context.Context, action *models.ActionMetadata) error {
	return nil
}
func (m *MockMetaRepo) UpdateAction(ctx context.Context, actionID string, updates *models.ActionMetadata) error {
	return nil
}
func (m *MockMetaRepo) DeleteAction(ctx context.Context, actionID string) error { return nil }
func (m *MockMetaRepo) CheckActionExists(ctx context.Context, objectAPIName, name string) (bool, error) {
	return false, nil
}
func (m *MockMetaRepo) GetSharingRules(ctx context.Context, objectAPIName string) ([]*models.SharingRule, error) {
	return nil, nil
}

// Salesforce-compatible FlowDefinition methods
func (m *MockMetaRepo) GetAllFlowDefinitions(ctx context.Context) ([]*models.FlowDefinition, error) {
	return nil, nil
}
func (m *MockMetaRepo) GetFlowDefinition(ctx context.Context, id string) (*models.FlowDefinition, error) {
	return nil, nil
}
func (m *MockMetaRepo) GetFlowDefinitionByName(ctx context.Context, developerName string) (*models.FlowDefinition, error) {
	return nil, nil
}
func (m *MockMetaRepo) CreateFlowDefinition(ctx context.Context, def *models.FlowDefinition) error {
	return nil
}
func (m *MockMetaRepo) UpdateFlowDefinition(ctx context.Context, id string, def *models.FlowDefinition) error {
	return nil
}
func (m *MockMetaRepo) PatchFlowDefinition(ctx context.Context, id string, patch *models.FlowDefinitionPatch) error {
	return nil
}
func (m *MockMetaRepo) DeleteFlowDefinition(ctx context.Context, id string) error { return nil }

// Salesforce-compatible FlowVersion methods
func (m *MockMetaRepo) GetFlowVersions(ctx context.Context, definitionId string) ([]*models.FlowVersion, error) {
	return nil, nil
}
func (m *MockMetaRepo) GetFlowVersionsByIDs(_ context.Context, _ []string) (map[string]*models.FlowVersion, error) {
	return nil, nil
}
func (m *MockMetaRepo) GetFlowVersion(ctx context.Context, id string) (*models.FlowVersion, error) {
	return nil, nil
}
func (m *MockMetaRepo) GetActiveFlowVersion(ctx context.Context, definitionId string) (*models.FlowVersion, error) {
	return nil, nil
}
func (m *MockMetaRepo) CreateFlowVersion(ctx context.Context, version *models.FlowVersion) error {
	return nil
}
func (m *MockMetaRepo) CreateSeededFlowVersion(ctx context.Context, version *models.FlowVersion) error {
	return nil
}
func (m *MockMetaRepo) CreateTenantFlowVersion(ctx context.Context, version *models.FlowVersion) error {
	return nil
}
func (m *MockMetaRepo) UpdateFlowVersion(ctx context.Context, id string, version *models.FlowVersion) error {
	return nil
}
func (m *MockMetaRepo) ActivateFlowVersion(ctx context.Context, id string) error   { return nil }
func (m *MockMetaRepo) DeactivateFlowVersion(ctx context.Context, id string) error { return nil }
func (m *MockMetaRepo) DeleteFlowVersion(ctx context.Context, id string) error     { return nil }
func (m *MockMetaRepo) SetLatestVersionId(ctx context.Context, definitionId string, versionId string) error {
	return nil
}
func (m *MockMetaRepo) SetTriggerInfo(ctx context.Context, definitionId string, triggerType string, objectOrEvent string) error {
	return nil
}

// Salesforce-compatible FlowInterview methods
func (m *MockMetaRepo) GetFlowInterviews(ctx context.Context) ([]*models.FlowInterview, error) {
	return nil, nil
}
func (m *MockMetaRepo) GetFlowInterview(ctx context.Context, id string) (*models.FlowInterview, error) {
	return nil, nil
}
func (m *MockMetaRepo) SaveFlowInterview(ctx context.Context, interview *models.FlowInterview) error {
	return nil
}
func (m *MockMetaRepo) DeleteFlowInterview(ctx context.Context, id string) error { return nil }

func (m *MockMetaRepo) GetValidationRules(ctx context.Context, objectAPIName string) ([]*models.ValidationRule, error) {
	return nil, nil
}
func (m *MockMetaRepo) GetValidationRule(ctx context.Context, id string) (*models.ValidationRule, error) {
	return nil, nil
}
func (m *MockMetaRepo) CreateValidationRule(ctx context.Context, rule *models.ValidationRule) error {
	return nil
}
func (m *MockMetaRepo) UpdateValidationRule(ctx context.Context, id string, updates *models.ValidationRule) error {
	return nil
}
func (m *MockMetaRepo) DeleteValidationRule(ctx context.Context, id string) error { return nil }
func (m *MockMetaRepo) CheckValidationRuleExists(ctx context.Context, objectAPIName, name string) (bool, error) {
	return false, nil
}

func (m *MockMetaRepo) MarkLayoutCustomized(_ context.Context, _ string) {}
func (m *MockMetaRepo) MarkFlowDefinitionCustomized(_ context.Context, _ string) error {
	return nil
}

// --- Mock Permission Repo ---

type MockPermRepo struct {
	mock.Mock
}

func (m *MockPermRepo) LoadEffectiveObjectPermission(ctx context.Context, user *models.UserSession, objectAPIName string) (*models.ObjectPermissions, error) {
	args := m.Called(ctx, user, objectAPIName)
	if args.Get(0) == nil {
		return nil, args.Error(1)
	}
	return args.Get(0).(*models.ObjectPermissions), args.Error(1)
}
func (m *MockPermRepo) LoadEffectiveFieldPermission(ctx context.Context, user *models.UserSession, objectAPIName, fieldAPIName string) (*models.FieldPermissions, error) {
	args := m.Called(ctx, user, objectAPIName, fieldAPIName)
	if args.Get(0) == nil {
		return nil, args.Error(1)
	}
	return args.Get(0).(*models.FieldPermissions), args.Error(1)
}
func (m *MockPermRepo) LoadObjectPermission(ctx context.Context, profileID, objectAPIName string) (*models.ObjectPermissions, error) {
	return nil, nil
}
func (m *MockPermRepo) LoadFieldPermission(ctx context.Context, profileID, objectAPIName, fieldAPIName string) (*models.FieldPermissions, error) {
	return nil, nil
}
func (m *MockPermRepo) ListObjectPermissions(ctx context.Context, profileID string) ([]models.ObjectPermissions, error) {
	return nil, nil
}
func (m *MockPermRepo) ListFieldPermissions(ctx context.Context, profileID string) ([]models.FieldPermissions, error) {
	return nil, nil
}
func (m *MockPermRepo) UpsertObjectPermission(ctx context.Context, perm models.ObjectPermissions) error {
	return nil
}
func (m *MockPermRepo) BatchUpsertObjectPermissions(ctx context.Context, perms []models.ObjectPermissions) error {
	return nil
}
func (m *MockPermRepo) BatchUpsertFieldPermissions(ctx context.Context, perms []models.FieldPermissions) error {
	return nil
}
func (m *MockPermRepo) DeleteFieldPermissionsForFields(ctx context.Context, objectAPIName string, fieldAPINames []string) error {
	return nil
}
func (m *MockPermRepo) CountObjectPermissionsByProfile(ctx context.Context, profileID string) (int, error) {
	return 0, nil
}
func (m *MockPermRepo) UpsertFieldPermission(ctx context.Context, perm models.FieldPermissions) error {
	return nil
}
func (m *MockPermRepo) ListPermissionSetObjectPermissions(ctx context.Context, permissionSetID string) ([]models.ObjectPermissions, error) {
	return nil, nil
}
func (m *MockPermRepo) ListPermissionSetFieldPermissions(ctx context.Context, permissionSetID string) ([]models.FieldPermissions, error) {
	return nil, nil
}
func (m *MockPermRepo) ListEffectiveObjectPermissionsForUser(ctx context.Context, userID, profileID string) ([]models.ObjectPermissions, error) {
	return nil, nil
}
func (m *MockPermRepo) ListEffectiveFieldPermissionsForUser(ctx context.Context, userID, profileID string) ([]models.FieldPermissions, error) {
	return nil, nil
}
func (m *MockPermRepo) CreatePermissionSet(ctx context.Context, name, label, description string) (string, error) {
	return "", nil
}
func (m *MockPermRepo) UpdatePermissionSet(ctx context.Context, id, name, label, description string) error {
	return nil
}
func (m *MockPermRepo) DeletePermissionSet(ctx context.Context, id string) error { return nil }
func (m *MockPermRepo) GetUserProfileID(ctx context.Context, userID string) (string, error) {
	return "", nil
}
func (m *MockPermRepo) GetAllRoles(ctx context.Context) ([]*models.UserRole, error) { return nil, nil }
func (m *MockPermRepo) CreateRole(ctx context.Context, name, description string, parentRoleID *string) (string, error) {
	return "", nil
}
func (m *MockPermRepo) GetRole(ctx context.Context, id string) (*models.UserRole, error) {
	return nil, nil
}
func (m *MockPermRepo) UpdateRole(ctx context.Context, id, name, description string, parentRoleID *string) error {
	return nil
}
func (m *MockPermRepo) DeleteRole(ctx context.Context, id string) error { return nil }
func (m *MockPermRepo) IsUserInGroup(ctx context.Context, groupID, userID string) (bool, error) {
	return false, nil
}
func (m *MockPermRepo) GetManualShareAccessLevels(ctx context.Context, objectAPIName, recordID, userID string) ([]string, error) {
	return nil, nil
}
func (m *MockPermRepo) GetTeamMemberAccessLevel(ctx context.Context, objectAPIName, recordID, userID string) (*string, error) {
	return nil, nil
}
func (m *MockPermRepo) GetRecordOwnerID(ctx context.Context, tableName, recordID string) (string, error) {
	return "", nil
}
func (m *MockPermRepo) GetRecordByID(ctx context.Context, tableName, recordID string) (models.SObject, error) {
	return nil, nil
}
func (m *MockPermRepo) GetPendingApprovalLockInfo(ctx context.Context, targetObjectID string) (string, string, error) {
	return "", "", nil
}
func (m *MockPermRepo) HasPendingApprovalWorkitemForUser(ctx context.Context, processInstanceID, userID string) (bool, error) {
	return false, nil
}
func (m *MockPermRepo) GetUserGroupIDs(ctx context.Context, userID string) ([]string, error) {
	return nil, nil
}
func (m *MockPermRepo) GetManualShareRecordIDs(ctx context.Context, objectAPIName, userID string) ([]string, error) {
	return nil, nil
}
func (m *MockPermRepo) GetTeamMemberRecordIDs(ctx context.Context, objectAPIName, userID string) ([]string, error) {
	return nil, nil
}
func (m *MockPermRepo) GetAllProfiles(ctx context.Context) ([]*models.Profile, error) {
	return nil, nil
}
func (m *MockPermRepo) ListSystemPermissions(ctx context.Context) ([]models.SystemPermission, error) {
	return nil, nil
}
func (m *MockPermRepo) GetEffectiveSystemPermissions(ctx context.Context, userID, profileID string) (map[string]bool, error) {
	return nil, nil
}
func (m *MockPermRepo) GetEffectiveCustomPermissions(ctx context.Context, userID, profileID string) (map[string]bool, error) {
	return nil, nil
}
func (m *MockPermRepo) ListCustomPermissions(ctx context.Context) ([]models.SystemCustomPermission, error) {
	return nil, nil
}
func (m *MockPermRepo) GetCustomPermission(ctx context.Context, id string) (*models.SystemCustomPermission, error) {
	return nil, nil
}
func (m *MockPermRepo) CreateCustomPermission(ctx context.Context, perm *models.SystemCustomPermission) error {
	return nil
}
func (m *MockPermRepo) UpdateCustomPermission(ctx context.Context, perm *models.SystemCustomPermission) error {
	return nil
}
func (m *MockPermRepo) DeleteCustomPermission(ctx context.Context, id string) error {
	return nil
}
func (m *MockPermRepo) ListPermissionSetGroups(ctx context.Context) ([]models.PermissionSetGroup, error) {
	return nil, nil
}
func (m *MockPermRepo) GetPermissionSetGroupByID(ctx context.Context, id string) (*models.PermissionSetGroup, error) {
	return nil, nil
}
func (m *MockPermRepo) GetPermissionSetGroupComponents(ctx context.Context, groupID string) ([]ports.PermissionSetRef, error) {
	return nil, nil
}
func (m *MockPermRepo) CreatePermissionSetGroup(ctx context.Context, group *models.PermissionSetGroup, permSetIDs []string) error {
	return nil
}
func (m *MockPermRepo) UpdatePermissionSetGroup(ctx context.Context, group *models.PermissionSetGroup, permSetIDs []string) error {
	return nil
}
func (m *MockPermRepo) DeletePermissionSetGroup(ctx context.Context, id string) error {
	return nil
}
func (m *MockPermRepo) CleanupDirectProfilePermissions(ctx context.Context, profileIDs []string) error {
	return nil
}
func (m *MockPermRepo) BulkEnsureProfilePermissionSets(_ context.Context, _ []struct{ ID, Name string }) (map[string]string, error) {
	return nil, nil
}
func (m *MockPermRepo) BulkCountObjectPermissionsByProfiles(_ context.Context, _ []string) (map[string]int, error) {
	return nil, nil
}
func (m *MockPermRepo) BulkCountFieldPermissionsByProfiles(_ context.Context, _ []string) (map[string]int, error) {
	return nil, nil
}
func (m *MockPermRepo) BulkCountObjectPermissionsByProfilesAndTypes(_ context.Context, _ []string, _ []string) (map[string]int, error) {
	return nil, nil
}
func (m *MockPermRepo) BulkCountFieldPermissionsByProfilesAndTypes(_ context.Context, _ []string, _ []string) (map[string]int, error) {
	return nil, nil
}
func (m *MockPermRepo) EnsureProfilePermissionSet(ctx context.Context, profileID, profileName string) (string, error) {
	return "ps_" + profileID, nil
}
func (m *MockPermRepo) CleanupProfilePermissionSet(ctx context.Context, profileID string) error {
	return nil
}
func (m *MockPermRepo) LockPermissionSet(_ context.Context, _ string) (bool, error) {
	return true, nil
}
func (m *MockPermRepo) GetPermissionSetGrants(ctx context.Context, permSetID string) (map[string]bool, error) {
	return nil, nil
}
func (m *MockPermRepo) GetPermissionSetGrantsMany(ctx context.Context, permSetIDs []string) (map[string]map[string]bool, error) {
	return nil, nil
}
func (m *MockPermRepo) SetSystemPermission(ctx context.Context, permSetID, apiName string, enabled bool) error {
	return nil
}

// --- Mock User Repo ---

type MockUserRepo struct {
	mock.Mock
}

func (m *MockUserRepo) CheckUserExistsByEmail(ctx context.Context, email string) (bool, error) {
	return false, nil
}
func (m *MockUserRepo) CheckUserExistsByID(ctx context.Context, id string) (bool, error) {
	return false, nil
}
func (m *MockUserRepo) CheckEmailConflict(ctx context.Context, email, excludeID string) (bool, error) {
	return false, nil
}
func (m *MockUserRepo) UpdateUser(ctx context.Context, userID string, updates map[string]interface{}) error {
	return nil
}
func (m *MockUserRepo) DeleteUser(ctx context.Context, userID string) error { return nil }
func (m *MockUserRepo) FindAll(ctx context.Context) ([]*models.User, error) { return nil, nil }
func (m *MockUserRepo) GetUserRoleID(ctx context.Context, userID string) (*string, error) {
	return nil, nil
}
func (m *MockUserRepo) FindUserByEmailWithPassword(ctx context.Context, email string) (*ports.UserWithPassword, error) {
	return nil, nil
}
func (m *MockUserRepo) FindUserByIDWithPassword(ctx context.Context, userID string) (*ports.UserWithPassword, error) {
	return nil, nil
}
func (m *MockUserRepo) UpdatePassword(ctx context.Context, userID, passwordHash string) error {
	return nil
}
func (m *MockUserRepo) GetUserByID(ctx context.Context, userID string) (*models.User, error) {
	return nil, nil
}
func (m *MockUserRepo) CreateUser(ctx context.Context, user *models.User) error { return nil }

func TestQueryService_SearchSingleObject_Strict(t *testing.T) {
	t.Run("Does NOT inject Name property for non-Name objects", func(t *testing.T) {
		mockQueryRepo := new(MockQueryRepo)
		mockPermRepo := new(MockPermRepo)
		mockMetaRepo := new(MockMetaRepo)

		metaSvc := metadata.NewMetadataService(mockMetaRepo, nil, nil)
		permSvc := permissions.NewPermissionService(mockPermRepo, metaSvc, nil)
		querySvc := analytics.NewQueryService(mockQueryRepo, metaSvc, permSvc, nil)

		ctx := context.Background()
		adminUser := &models.UserSession{ID: "admin", IsSystemAdmin: true, ProfileID: constants.ProfileSystemAdmin}

		// Schema: Case
		caseSchema := &models.ObjectMetadata{
			APIName: "Case",
			Fields: []models.FieldMetadata{
				{APIName: "Id", Type: constants.FieldTypeString},
				{APIName: "CaseNumber", Type: constants.FieldTypeString},
				{APIName: "Subject", Type: constants.FieldTypeString},
			},
		}
		caseSchema.Fields[1].IsNameField = true

		// Mock Cache Load check (called on init)
		mockMetaRepo.On("GetAllSchemas", mock.Anything).Return([]*models.ObjectMetadata{caseSchema}, nil).Maybe()
		// Mock GetSchema fallback
		mockMetaRepo.On("GetSchemaByAPIName", mock.Anything, "Case").Return(caseSchema, nil).Maybe()

		// Mock Repo Search Result
		expectedFields := []string{"Id", "Subject"}
		mockResults := []models.SObject{
			{"Id": "500xxx", "Subject": "Broken Laptop"},
		}

		mockQueryRepo.On("Search", mock.Anything, mock.MatchedBy(func(s *models.ObjectMetadata) bool {
			return s.APIName == "Case"
		}), "Laptop", mock.Anything, expectedFields, 500, 0, "", "", "", mock.Anything).Return(mockResults, nil)

		results, err := querySvc.SearchSingleObject(ctx, "Case", "Laptop", []string{"Subject"}, []string{"Id", "Subject"}, 500, 0, "", "", "", adminUser)

		assert.NoError(t, err)
		assert.Len(t, results, 1)

		rec := results[0]
		assert.Equal(t, "Broken Laptop", rec["Subject"])
		_, hasName := rec["Name"]
		assert.False(t, hasName, "Should NOT have synthetic 'Name' property")
	})

	t.Run("Respects Explicit Fields Only", func(t *testing.T) {
		mockQueryRepo := new(MockQueryRepo)
		mockPermRepo := new(MockPermRepo)
		mockMetaRepo := new(MockMetaRepo)

		metaSvc := metadata.NewMetadataService(mockMetaRepo, nil, nil)
		permSvc := permissions.NewPermissionService(mockPermRepo, metaSvc, nil)
		querySvc := analytics.NewQueryService(mockQueryRepo, metaSvc, permSvc, nil)

		ctx := context.Background()
		adminUser := &models.UserSession{ID: "admin", IsSystemAdmin: true, ProfileID: constants.ProfileSystemAdmin}

		// Schema: Account
		accSchema := &models.ObjectMetadata{
			APIName: "Account",
			Fields: []models.FieldMetadata{
				{APIName: "Id", Type: constants.FieldTypeString},
				{APIName: "Name", Type: constants.FieldTypeString, IsNameField: true},
				{APIName: "Industry", Type: constants.FieldTypePicklist},
			},
		}

		mockMetaRepo.On("GetAllSchemas", mock.Anything).Return([]*models.ObjectMetadata{accSchema}, nil).Maybe()
		mockMetaRepo.On("GetSchemaByAPIName", mock.Anything, "Account").Return(accSchema, nil).Maybe()

		requestedFields := []string{"Id", "Industry"}
		mockResults := []models.SObject{
			{"Id": "001xxx", "Industry": "Tech"},
		}

		mockQueryRepo.On("Search", mock.Anything, mock.Anything, "Tech", mock.Anything, requestedFields, 500, 0, "", "", "", mock.Anything).Return(mockResults, nil)

		results, err := querySvc.SearchSingleObject(ctx, "Account", "Tech", []string{"Industry"}, []string{"Id", "Industry"}, 500, 0, "", "", "", adminUser)

		assert.NoError(t, err)
		assert.Len(t, results, 1)
		assert.Equal(t, "Tech", results[0]["Industry"])
		_, hasName := results[0]["Name"]
		assert.False(t, hasName, "Should NOT satisfy unrequested Name field")
	})

	t.Run("Includes AutoNumber fields", func(t *testing.T) {
		mockQueryRepo := new(MockQueryRepo)
		mockPermRepo := new(MockPermRepo)
		mockMetaRepo := new(MockMetaRepo)

		metaSvc := metadata.NewMetadataService(mockMetaRepo, nil, nil)
		permSvc := permissions.NewPermissionService(mockPermRepo, metaSvc, nil)
		querySvc := analytics.NewQueryService(mockQueryRepo, metaSvc, permSvc, nil)

		ctx := context.Background()
		adminUser := &models.UserSession{ID: "admin", IsSystemAdmin: true, ProfileID: constants.ProfileSystemAdmin}

		// Schema: Case with AutoNumber
		caseSchema := &models.ObjectMetadata{
			APIName: "Case",
			Fields: []models.FieldMetadata{
				{APIName: "Id", Type: constants.FieldTypeString},
				{APIName: "CaseNumber", Type: constants.FieldTypeAutonumber, IsNameField: true},
				{APIName: "Subject", Type: constants.FieldTypeString},
			},
		}

		mockMetaRepo.On("GetAllSchemas", mock.Anything).Return([]*models.ObjectMetadata{caseSchema}, nil).Maybe()
		mockMetaRepo.On("GetSchemaByAPIName", mock.Anything, "Case").Return(caseSchema, nil).Maybe()

		// Expect search to include CaseNumber because it is AutoNumber
		// Also add Non-Name AutoNumber to be strict
		caseSchema.Fields = append(caseSchema.Fields, models.FieldMetadata{
			APIName: "TrackingNumber", Type: constants.FieldTypeAutonumber,
		})

		expectedSearchFields := []string{"CaseNumber", "Subject", "TrackingNumber"}

		mockQueryRepo.On("Search", mock.Anything, mock.Anything, "123",
			mock.MatchedBy(func(fields []string) bool {
				// Verify all expected fields are present
				for _, exp := range expectedSearchFields {
					found := false
					for _, f := range fields {
						if f == exp {
							found = true
							break
						}
					}
					if !found {
						return false
					}
				}
				return true
			}),
			mock.Anything, 500, 0, "", "", "", mock.Anything).Return([]models.SObject{}, nil)

		_, err := querySvc.SearchSingleObject(ctx, "Case", "123", expectedSearchFields, nil, 500, 0, "", "", "", adminUser)
		assert.NoError(t, err)
	})

	t.Run("Expands compound return fields for compound name objects", func(t *testing.T) {
		mockQueryRepo := new(MockQueryRepo)
		mockPermRepo := new(MockPermRepo)
		mockMetaRepo := new(MockMetaRepo)

		metaSvc := metadata.NewMetadataService(mockMetaRepo, nil, nil)
		permSvc := permissions.NewPermissionService(mockPermRepo, metaSvc, nil)
		querySvc := analytics.NewQueryService(mockQueryRepo, metaSvc, permSvc, nil)

		ctx := context.Background()
		adminUser := &models.UserSession{ID: "admin", IsSystemAdmin: true, ProfileID: constants.ProfileSystemAdmin}

		leadSchema := &models.ObjectMetadata{
			APIName: "Lead",
			Fields: []models.FieldMetadata{
				{APIName: "Id", Type: constants.FieldTypeString},
				{APIName: "Name", Type: constants.FieldTypeString, IsNameField: true},
				{APIName: "FirstName", Type: constants.FieldTypeString},
				{APIName: "LastName", Type: constants.FieldTypeString},
			},
		}

		mockMetaRepo.On("GetAllSchemas", mock.Anything).Return([]*models.ObjectMetadata{leadSchema}, nil).Maybe()
		mockMetaRepo.On("GetSchemaByAPIName", mock.Anything, "Lead").Return(leadSchema, nil).Maybe()

		mockQueryRepo.On("Search", mock.Anything, mock.Anything, "Rahul", []string{"FirstName", "LastName"}, mock.MatchedBy(func(fields []string) bool {
			expected := []string{"Id", "Name", "FirstName", "LastName"}
			for _, field := range expected {
				found := false
				for _, actual := range fields {
					if actual == field {
						found = true
						break
					}
				}
				if !found {
					return false
				}
			}
			return true
		}), 20, 0, "", "", "", mock.Anything).Return([]models.SObject{
			{"Id": "00Q-test", "FirstName": "Rahul", "LastName": "Gore"},
		}, nil)

		results, err := querySvc.SearchSingleObject(ctx, "Lead", "Rahul", []string{"FirstName", "LastName"}, []string{"Id", "Name"}, 20, 0, "", "", "", adminUser)
		assert.NoError(t, err)
		assert.Len(t, results, 1)
	})
}

func strPtr(v string) *string {
	return &v
}

// --- Layout Assignment interface stubs (WP2) ---
func (m *MockMetaRepo) FindBestAssignment(_ context.Context, _ string, _ []string, _ string, _ string) (*models.LayoutAssignment, error) {
	return nil, nil
}
func (m *MockMetaRepo) CreateAssignment(_ context.Context, _ *models.LayoutAssignment) error {
	return nil
}
func (m *MockMetaRepo) DeleteAssignment(_ context.Context, _ string) error { return nil }
func (m *MockMetaRepo) GetAssignmentsForObject(_ context.Context, _ string) ([]*models.LayoutAssignment, error) {
	return nil, nil
}
func (m *MockMetaRepo) DeleteAssignmentsByLayoutID(_ context.Context, _ string) error { return nil }
func (m *MockMetaRepo) WriteLayoutHistory(_ context.Context, _ *models.PageLayoutHistoryEntry) error {
	return nil
}
func (m *MockMetaRepo) GetLayoutHistoryMaxVersion(_ context.Context, _ string) (int, error) {
	return 0, nil
}
func (m *MockMetaRepo) GetMigrationVersion(_ context.Context, _ string) (int, error) { return 0, nil }
func (m *MockMetaRepo) SetMigrationVersion(_ context.Context, _ string, _ int, _ string) error {
	return nil
}

func (m *MockMetaRepo) GetLayoutHistoryConfig(_ context.Context, _ string, _ int) (string, error) {
	return "", nil
}

func (m *MockMetaRepo) PruneLayoutHistory(_ context.Context, _ string, _ int) error { return nil }

// Approval layout methods
func (m *MockMetaRepo) GetApprovalLayouts(ctx context.Context, objectAPIName string) ([]*models.ApprovalPageLayout, error) {
	return nil, nil
}
func (m *MockMetaRepo) GetApprovalLayout(ctx context.Context, id string) (*models.ApprovalPageLayout, error) {
	return nil, nil
}
func (m *MockMetaRepo) SaveApprovalLayout(ctx context.Context, layout *models.ApprovalPageLayout) error {
	return nil
}
func (m *MockMetaRepo) DeleteApprovalLayout(ctx context.Context, id string) error {
	return nil
}
func (m *MockMetaRepo) SetDefaultApprovalLayout(ctx context.Context, objectAPIName string, layoutID string) error {
	return nil
}
