package common

import (
	"context"
	"fmt"
	"reflect"
	"strings"

	"github.com/bitechdev/ResolveSpec/pkg/logger"
	"github.com/bitechdev/ResolveSpec/pkg/reflection"
)

// CRUDRequestProvider interface for models that provide CRUD request strings
type CRUDRequestProvider interface {
	GetRequest() string
}

// RelationshipInfoProvider interface for handlers that can provide relationship info
type RelationshipInfoProvider interface {
	GetRelationshipInfo(modelType reflect.Type, relationName string) *RelationshipInfo
}

// NestedCUDProcessor handles recursive processing of nested object graphs
type NestedCUDProcessor struct {
	db                 Database
	registry           ModelRegistry
	relationshipHelper RelationshipInfoProvider
}

// NewNestedCUDProcessor creates a new nested CUD processor
func NewNestedCUDProcessor(db Database, registry ModelRegistry, relationshipHelper RelationshipInfoProvider) *NestedCUDProcessor {
	return &NestedCUDProcessor{
		db:                 db,
		registry:           registry,
		relationshipHelper: relationshipHelper,
	}
}

// ProcessResult contains the result of processing a CUD operation
type ProcessResult struct {
	ID           interface{}            // The ID of the processed record
	AffectedRows int64                  // Number of rows affected
	Data         map[string]interface{} // The processed data
	RelationData map[string]interface{} // Data from processed relations
}

// ProcessNestedCUD recursively processes nested object graphs for Create, Update, Delete operations
// with automatic foreign key resolution
func (p *NestedCUDProcessor) ProcessNestedCUD(
	ctx context.Context,
	operation string, // "insert", "update", or "delete"
	data map[string]interface{},
	model interface{},
	parentIDs map[string]interface{}, // Parent IDs for foreign key resolution
	tableName string,
) (*ProcessResult, error) {
	logger.Info("Processing nested CUD: operation=%s, table=%s", operation, tableName)

	result := &ProcessResult{
		Data:         make(map[string]interface{}),
		RelationData: make(map[string]interface{}),
	}

	// Check if data has a _request field that overrides the operation
	if requestOp := p.extractCRUDRequest(data); requestOp != "" {
		logger.Debug("Found _request override: %s", requestOp)
		operation = requestOp
	}

	// Get model type for reflection
	modelType := reflect.TypeOf(model)
	for modelType != nil && (modelType.Kind() == reflect.Pointer || modelType.Kind() == reflect.Slice || modelType.Kind() == reflect.Array) {
		modelType = modelType.Elem()
	}

	if modelType == nil || modelType.Kind() != reflect.Struct {
		logger.Error("Invalid model type: operation=%s, table=%s, modelType=%v, expected struct", operation, tableName, modelType)
		return nil, fmt.Errorf("model must be a struct type, got %v", modelType)
	}

	// Separate relation fields from regular fields
	relationFields := make(map[string]*RelationshipInfo)
	regularData := make(map[string]interface{})

	for key, value := range data {
		// Skip _request field in actual data processing
		if key == "_request" {
			continue
		}

		// Check if this field is a relation
		relInfo := p.relationshipHelper.GetRelationshipInfo(modelType, key)
		if relInfo != nil {
			relationFields[key] = relInfo
			result.RelationData[key] = value
		} else {
			regularData[key] = value
		}
	}

	// Filter regularData to only include fields that exist in the model,
	// and translate JSON keys to their actual database column names.
	regularData = p.filterValidFields(regularData, model)

	// Inject parent IDs for foreign key resolution
	p.injectForeignKeys(regularData, modelType, parentIDs)

	// Get the primary key name for this model
	pkName := reflection.GetPrimaryKeyName(model)

	// Check if we have any data to process (besides _request)
	hasData := len(regularData) > 0

	// Process based on operation
	switch strings.ToLower(operation) {
	case "insert", "create", "add":
		// Only perform insert if we have data to insert
		if hasData {
			id, err := p.processInsert(ctx, regularData, tableName)
			if err != nil {
				logger.Error("Insert failed for table=%s, data=%+v, error=%v", tableName, regularData, err)
				return nil, fmt.Errorf("insert failed: %w", err)
			}
			result.ID = id
			result.AffectedRows = 1
			result.Data = regularData

			// Re-select the inserted row so result.Data reflects DB-generated defaults.
			if row, err := p.processSelect(ctx, tableName, id); err != nil {
				logger.Warn("Select after insert failed: table=%s, id=%v, error=%v", tableName, id, err)
			} else if len(row) > 0 {
				result.Data = row
			}

			// Process child relations after parent insert (to get parent ID)
			if err := p.processChildRelations(ctx, "insert", id, relationFields, result.RelationData, modelType, parentIDs); err != nil {
				logger.Error("Failed to process child relations after insert: table=%s, parentID=%v, relations=%+v, error=%v", tableName, id, relationFields, err)
				return nil, fmt.Errorf("failed to process child relations: %w", err)
			}
		} else {
			logger.Debug("Skipping insert for %s - no data columns besides _request", tableName)
		}

	case "update", "change", "modify":
		// Only perform update if we have data to update
		if reflection.IsEmptyValue(data[pkName]) {
			logger.Warn("Skipping update for %s - no primary key", tableName)
			return result, nil
		}
		if hasData {
			rows, err := p.processUpdate(ctx, regularData, tableName, data[pkName])
			if err != nil {
				logger.Error("Update failed for table=%s, id=%v, data=%+v, error=%v", tableName, data[pkName], regularData, err)
				return nil, fmt.Errorf("update failed: %w", err)
			}
			result.ID = data[pkName]
			result.AffectedRows = rows
			result.Data = regularData

			// Re-select the updated row so result.Data reflects current DB state.
			if row, err := p.processSelect(ctx, tableName, result.ID); err != nil {
				logger.Warn("Select after update failed: table=%s, id=%v, error=%v", tableName, result.ID, err)
			} else if len(row) > 0 {
				result.Data = row
			}

			// Process child relations for update
			if err := p.processChildRelations(ctx, "update", data[pkName], relationFields, result.RelationData, modelType, parentIDs); err != nil {
				logger.Error("Failed to process child relations after update: table=%s, parentID=%v, relations=%+v, error=%v", tableName, data[pkName], regularData, err)
				return nil, fmt.Errorf("failed to process child relations: %w", err)
			}
		} else {
			logger.Debug("Skipping update for %s - no data columns besides _request", tableName)
			result.ID = data[pkName]
		}

	case "delete", "remove":
		if reflection.IsEmptyValue(data[pkName]) {
			logger.Warn("Skipping delete for %s - no primary key", tableName)
			return result, nil
		}

		// Process child relations first (for referential integrity)
		if err := p.processChildRelations(ctx, "delete", data[pkName], relationFields, result.RelationData, modelType, parentIDs); err != nil {
			logger.Error("Failed to process child relations before delete: table=%s, id=%v, relations=%+v, error=%v", tableName, data[pkName], relationFields, err)
			return nil, fmt.Errorf("failed to process child relations: %w", err)
		}

		rows, err := p.processDelete(ctx, tableName, data[pkName])
		if err != nil {
			logger.Error("Delete failed for table=%s, id=%v, error=%v", tableName, data[pkName], err)
			return nil, fmt.Errorf("delete failed: %w", err)
		}
		result.ID = data[pkName]
		result.AffectedRows = rows
		result.Data = regularData

	default:
		logger.Error("Unsupported operation: %s for table=%s", operation, tableName)
		return nil, fmt.Errorf("unsupported operation: %s", operation)
	}

	logger.Info("Nested CUD completed: operation=%s, id=%v, rows=%d", operation, result.ID, result.AffectedRows)
	return result, nil
}

// extractCRUDRequest extracts the request field from data if present
func (p *NestedCUDProcessor) extractCRUDRequest(data map[string]interface{}) string {
	if request, ok := data["_request"]; ok {
		if requestStr, ok := request.(string); ok {
			return strings.ToLower(strings.TrimSpace(requestStr))
		}
	}
	return ""
}

// filterValidFields filters input data to only include fields that exist in the model,
// and translates JSON key names to their actual database column names.
// For example, a field tagged `json:"_changed_date" bun:"changed_date"` will be
// included in the result as "changed_date", not "_changed_date".
func (p *NestedCUDProcessor) filterValidFields(data map[string]interface{}, model interface{}) map[string]interface{} {
	if len(data) == 0 {
		return data
	}

	modelType := reflect.TypeOf(model)
	for modelType != nil && (modelType.Kind() == reflect.Pointer || modelType.Kind() == reflect.Slice || modelType.Kind() == reflect.Array) {
		modelType = modelType.Elem()
	}

	if modelType == nil || modelType.Kind() != reflect.Struct {
		return data
	}

	// Build a mapping from JSON key -> DB column name for all writable fields.
	// This both validates which fields belong to the model and translates their names
	// to the correct column names for use in SQL insert/update queries.
	jsonToDBCol := reflection.BuildJSONToDBColumnMap(modelType)

	filteredData := make(map[string]interface{})
	for key, value := range data {
		dbColName, exists := jsonToDBCol[key]
		if exists {
			filteredData[dbColName] = value
		} else {
			logger.Debug("Skipping invalid field '%s' - not found in model %v", key, modelType)
		}
	}

	return filteredData
}

// injectForeignKeys injects parent IDs into data for foreign key fields.
// data is expected to be keyed by DB column names (as returned by filterValidFields).
func (p *NestedCUDProcessor) injectForeignKeys(data map[string]interface{}, modelType reflect.Type, parentIDs map[string]interface{}) {
	if len(parentIDs) == 0 {
		return
	}

	pkCol := reflection.GetPrimaryKeyName(reflect.New(modelType).Interface())

	for parentKey, parentID := range parentIDs {
		dbColNames := reflection.GetForeignKeyColumn(modelType, parentKey)

		if len(dbColNames) == 0 {
			// No explicit tag found — fall back to naming convention by scanning scalar fields.
			for i := 0; i < modelType.NumField(); i++ {
				field := modelType.Field(i)
				jsonName := strings.Split(field.Tag.Get("json"), ",")[0]
				if strings.EqualFold(jsonName, "rid"+parentKey) ||
					strings.EqualFold(jsonName, "rid_"+parentKey) ||
					strings.EqualFold(jsonName, "id_"+parentKey) ||
					strings.EqualFold(jsonName, parentKey+"_id") ||
					strings.EqualFold(jsonName, parentKey+"id") ||
					strings.EqualFold(field.Name, parentKey+"ID") {
					dbColNames = []string{reflection.GetColumnName(field)}
					break
				}
			}
		}

		for _, dbColName := range dbColNames {
			if pkCol != "" && strings.EqualFold(dbColName, pkCol) {
				continue
			}
			if _, exists := data[dbColName]; !exists {
				logger.Debug("Injecting foreign key: %s = %v", dbColName, parentID)
				data[dbColName] = parentID
			}
		}
	}
}

// processInsert handles insert operation
func (p *NestedCUDProcessor) processInsert(
	ctx context.Context,
	data map[string]interface{},
	tableName string,
) (interface{}, error) {
	logger.Debug("Inserting into %s with data: %+v", tableName, data)

	query := p.db.NewInsert().Table(tableName)

	for key, value := range data {
		query = query.Value(key, ConvertSliceForBun(value))
	}
	pkName := reflection.GetPrimaryKeyName(tableName)
	query = query.Returning(pkName)

	var id interface{}
	if err := query.Scan(ctx, &id); err != nil {
		logger.Error("Insert execution failed: table=%s, data=%+v, error=%v", tableName, data, err)
		return nil, fmt.Errorf("insert exec failed: %w", err)
	}

	logger.Debug("Insert successful, ID: %v", id)
	return id, nil
}

// processSelect fetches the row identified by id from tableName into a flat map.
// Used to populate result.Data with the actual DB state after insert/update.
func (p *NestedCUDProcessor) processSelect(ctx context.Context, tableName string, id interface{}) (map[string]interface{}, error) {
	pkName := reflection.GetPrimaryKeyName(tableName)
	var row map[string]interface{}
	if err := p.db.NewSelect().
		Table(tableName).
		Where(fmt.Sprintf("%s = ?", QuoteIdent(pkName)), id).
		Scan(ctx, &row); err != nil {
		return nil, fmt.Errorf("select after write failed: %w", err)
	}
	return row, nil
}

// processUpdate handles update operation
func (p *NestedCUDProcessor) processUpdate(
	ctx context.Context,
	data map[string]interface{},
	tableName string,
	id interface{},
) (int64, error) {
	if id == nil {
		logger.Error("Update requires an ID: table=%s, data=%+v", tableName, data)
		return 0, fmt.Errorf("update requires an ID")
	}

	logger.Debug("Updating %s with ID %v, data: %+v", tableName, id, data)

	query := p.db.NewUpdate().Table(tableName).SetMap(data).Where(fmt.Sprintf("%s = ?", QuoteIdent(reflection.GetPrimaryKeyName(tableName))), id)

	result, err := query.Exec(ctx)
	if err != nil {
		logger.Error("Update execution failed: table=%s, id=%v, data=%+v, error=%v", tableName, id, data, err)
		return 0, fmt.Errorf("update exec failed: %w", err)
	}

	rows := result.RowsAffected()
	logger.Debug("Update successful, rows affected: %d", rows)
	return rows, nil
}

// processDelete handles delete operation
func (p *NestedCUDProcessor) processDelete(ctx context.Context, tableName string, id interface{}) (int64, error) {
	if id == nil {
		logger.Error("Delete requires an ID: table=%s", tableName)
		return 0, fmt.Errorf("delete requires an ID")
	}

	logger.Debug("Deleting from %s with ID %v", tableName, id)

	query := p.db.NewDelete().Table(tableName).Where(fmt.Sprintf("%s = ?", QuoteIdent(reflection.GetPrimaryKeyName(tableName))), id)

	result, err := query.Exec(ctx)
	if err != nil {
		logger.Error("Delete execution failed: table=%s, id=%v, error=%v", tableName, id, err)
		return 0, fmt.Errorf("delete exec failed: %w", err)
	}

	rows := result.RowsAffected()
	logger.Debug("Delete successful, rows affected: %d", rows)
	return rows, nil
}

// processChildRelations recursively processes child relations
func (p *NestedCUDProcessor) processChildRelations(
	ctx context.Context,
	operation string,
	parentID interface{},
	relationFields map[string]*RelationshipInfo,
	relationData map[string]interface{},
	parentModelType reflect.Type,
	incomingParentIDs map[string]interface{}, // IDs from all ancestors
) error {
	for relationName, relInfo := range relationFields {
		relationValue, exists := relationData[relationName]
		if !exists || relationValue == nil {
			continue
		}

		logger.Debug("Processing relation: %s, type: %s", relationName, relInfo.RelationType)

		// Get the related model
		field, found := parentModelType.FieldByName(relInfo.FieldName)
		if !found {
			logger.Error("Field %s not found in model type %v for relation %s", relInfo.FieldName, parentModelType, relationName)
			continue
		}

		// Get the model type for the relation
		relatedModelType := field.Type
		if relatedModelType.Kind() == reflect.Slice {
			relatedModelType = relatedModelType.Elem()
		}
		if relatedModelType.Kind() == reflect.Pointer {
			relatedModelType = relatedModelType.Elem()
		}

		// Create an instance of the related model
		relatedModel := reflect.New(relatedModelType).Elem().Interface()

		// Get table name for related model
		relatedTableName := p.getTableNameForModel(relatedModel, relInfo.JSONName)

		// Prepare parent IDs for foreign key injection
		// Start by copying all incoming parent IDs (from ancestors)
		parentIDs := make(map[string]interface{})
		for k, v := range incomingParentIDs {
			parentIDs[k] = v
		}
		logger.Debug("Inherited %d parent IDs from ancestors: %+v", len(incomingParentIDs), incomingParentIDs)

		// Add the current parent's primary key to the parentIDs map
		// This ensures nested children have access to all ancestor IDs
		if parentID != nil && parentModelType != nil {
			// Get the parent model's primary key field name
			parentPKFieldName := reflection.GetPrimaryKeyName(parentModelType)
			if parentPKFieldName != "" {
				// Get the JSON name for the primary key field
				parentPKJSONName := reflection.GetJSONNameForField(parentModelType, parentPKFieldName)
				baseName := ""
				if len(parentPKJSONName) > 1 {
					baseName = parentPKJSONName
				} else {
					// Add parent's PK to the map using the base model name
					baseName = strings.TrimSuffix(parentPKFieldName, "ID")
					baseName = strings.TrimSuffix(strings.ToLower(baseName), "_id")
					if baseName == "" {
						baseName = "parent"
					}
				}

				parentIDs[baseName] = parentID
				logger.Debug("Added current parent PK to parentIDs map: %s=%v (from field %s)", baseName, parentID, parentPKFieldName)
			}
		}

		// Also add the foreign key reference if specified
		if relInfo.ForeignKey != "" && parentID != nil {
			// Extract the base name from foreign key (e.g., "DepartmentID" -> "Department")
			baseName := strings.TrimSuffix(relInfo.ForeignKey, "ID")
			baseName = strings.TrimSuffix(strings.ToLower(baseName), "_id")
			// Only add if different from what we already added
			if _, exists := parentIDs[baseName]; !exists {
				parentIDs[baseName] = parentID
				logger.Debug("Added foreign key to parentIDs map: %s=%v (from FK %s)", baseName, parentID, relInfo.ForeignKey)
			}
		}

		logger.Debug("Final parentIDs map for relation %s: %+v", relationName, parentIDs)

		// Determine which field name to use for setting parent ID in child data
		// Priority: Use foreign key field name if specified
		var foreignKeyFieldName string
		if relInfo.ForeignKey != "" {
			// For has-many/has-one: join:parentCol=childCol
			// ForeignKey = parent side, References = child side (where we actually set the value)
			childField := relInfo.ForeignKey
			if (relInfo.RelationType == "hasMany" || relInfo.RelationType == "hasOne") && relInfo.References != "" {
				childField = relInfo.References
			}
			foreignKeyFieldName = reflection.GetJSONNameForField(relatedModelType, childField)
			if foreignKeyFieldName == "" {
				foreignKeyFieldName = strings.ToLower(childField)
			}
			logger.Debug("Using foreign key field for direct assignment: %s (from FK %s -> child %s)", foreignKeyFieldName, relInfo.ForeignKey, childField)
		}

		// Get the primary key name for the child model to avoid overwriting it in recursive relationships
		childPKName := reflection.GetPrimaryKeyName(relatedModel)
		childPKFieldName := reflection.GetJSONNameForField(relatedModelType, childPKName)
		if childPKFieldName == "" {
			childPKFieldName = strings.ToLower(childPKName)
		}

		logger.Debug("Processing relation with foreignKeyField=%s, childPK=%s", foreignKeyFieldName, childPKFieldName)

		// Process based on relation type and data structure
		switch v := relationValue.(type) {
		case map[string]interface{}:
			// Single related object - directly set foreign key if specified
			// IMPORTANT: In recursive relationships, don't overwrite the primary key
			if parentID != nil && foreignKeyFieldName != "" && foreignKeyFieldName != childPKFieldName {
				v[foreignKeyFieldName] = parentID
				logger.Debug("Set foreign key in single relation: %s=%v", foreignKeyFieldName, parentID)
			} else if foreignKeyFieldName == childPKFieldName {
				logger.Debug("Skipping foreign key assignment - same as primary key (recursive relationship): %s", foreignKeyFieldName)
			}
			_, err := p.ProcessNestedCUD(ctx, operation, v, relatedModel, parentIDs, relatedTableName)
			if err != nil {
				logger.Error("Failed to process single relation: name=%s, table=%s, operation=%s, parentID=%v, data=%+v, error=%v",
					relationName, relatedTableName, operation, parentID, v, err)
				return fmt.Errorf("failed to process relation %s: %w", relationName, err)
			}

		case []interface{}:
			// Multiple related objects
			for i, item := range v {
				if itemMap, ok := item.(map[string]interface{}); ok {
					// Directly set foreign key if specified
					// IMPORTANT: In recursive relationships, don't overwrite the primary key
					if parentID != nil && foreignKeyFieldName != "" && foreignKeyFieldName != childPKFieldName {
						itemMap[foreignKeyFieldName] = parentID
						logger.Debug("Set foreign key in relation array[%d]: %s=%v", i, foreignKeyFieldName, parentID)
					} else if foreignKeyFieldName == childPKFieldName {
						logger.Debug("Skipping foreign key assignment in array[%d] - same as primary key (recursive relationship): %s", i, foreignKeyFieldName)
					}
					_, err := p.ProcessNestedCUD(ctx, operation, itemMap, relatedModel, parentIDs, relatedTableName)
					if err != nil {
						logger.Error("Failed to process relation array item: name=%s[%d], table=%s, operation=%s, parentID=%v, data=%+v, error=%v",
							relationName, i, relatedTableName, operation, parentID, itemMap, err)
						return fmt.Errorf("failed to process relation %s[%d]: %w", relationName, i, err)
					}
				} else {
					logger.Warn("Relation array item is not a map: name=%s[%d], type=%T", relationName, i, item)
				}
			}

		case []map[string]interface{}:
			// Multiple related objects (typed slice)
			for i, itemMap := range v {
				// Directly set foreign key if specified
				// IMPORTANT: In recursive relationships, don't overwrite the primary key
				if parentID != nil && foreignKeyFieldName != "" && foreignKeyFieldName != childPKFieldName {
					itemMap[foreignKeyFieldName] = parentID
					logger.Debug("Set foreign key in relation typed array[%d]: %s=%v", i, foreignKeyFieldName, parentID)
				} else if foreignKeyFieldName == childPKFieldName {
					logger.Debug("Skipping foreign key assignment in typed array[%d] - same as primary key (recursive relationship): %s", i, foreignKeyFieldName)
				}
				_, err := p.ProcessNestedCUD(ctx, operation, itemMap, relatedModel, parentIDs, relatedTableName)
				if err != nil {
					logger.Error("Failed to process relation typed array item: name=%s[%d], table=%s, operation=%s, parentID=%v, data=%+v, error=%v",
						relationName, i, relatedTableName, operation, parentID, itemMap, err)
					return fmt.Errorf("failed to process relation %s[%d]: %w", relationName, i, err)
				}
			}

		default:
			logger.Error("Unsupported relation data type: name=%s, type=%T, value=%+v", relationName, relationValue, relationValue)
		}
	}

	return nil
}

// getTableNameForModel gets the table name for a model
func (p *NestedCUDProcessor) getTableNameForModel(model interface{}, defaultName string) string {
	if provider, ok := model.(TableNameProvider); ok {
		tableName := provider.TableName()
		if tableName != "" {
			return tableName
		}
	}
	return defaultName
}

// ShouldUseNestedProcessor determines if we should use nested CUD processing
// It recursively checks if the data contains:
// 1. A _request field at any level, OR
// 2. Nested relations that themselves contain further nested relations or _request fields
// This ensures nested processing is only used when there are deeply nested operations
func ShouldUseNestedProcessor(data map[string]interface{}, model interface{}, relationshipHelper RelationshipInfoProvider) bool {
	return shouldUseNestedProcessorDepth(data, model, relationshipHelper, 0)
}

// shouldUseNestedProcessorDepth is the internal recursive implementation with depth tracking
func shouldUseNestedProcessorDepth(data map[string]interface{}, model interface{}, relationshipHelper RelationshipInfoProvider, depth int) bool {
	// Check for _request field
	if _, hasCRUDRequest := data["_request"]; hasCRUDRequest {
		return true
	}

	// Get model type
	modelType := reflect.TypeOf(model)
	for modelType != nil && (modelType.Kind() == reflect.Pointer || modelType.Kind() == reflect.Slice || modelType.Kind() == reflect.Array) {
		modelType = modelType.Elem()
	}

	if modelType == nil || modelType.Kind() != reflect.Struct {
		return false
	}

	// Check if data contains any fields that are relations (nested objects or arrays)
	for key, value := range data {
		// Skip _request and regular scalar fields
		if key == "_request" {
			continue
		}

		// Check if this field is a relation in the model
		relInfo := relationshipHelper.GetRelationshipInfo(modelType, key)
		if relInfo != nil {
			// Check if the value is actually nested data (object or array)
			switch v := value.(type) {
			case map[string]interface{}, []interface{}, []map[string]interface{}:
				// If we're already at a nested level (depth > 0) and found a relation,
				// that means we have multi-level nesting, so return true
				if depth > 0 {
					return true
				}
				// At depth 0, recurse to check if the nested data has further nesting
				switch typedValue := v.(type) {
				case map[string]interface{}:
					if shouldUseNestedProcessorDepth(typedValue, relInfo.RelatedModel, relationshipHelper, depth+1) {
						return true
					}
				case []interface{}:
					for _, item := range typedValue {
						if itemMap, ok := item.(map[string]interface{}); ok {
							if shouldUseNestedProcessorDepth(itemMap, relInfo.RelatedModel, relationshipHelper, depth+1) {
								return true
							}
						}
					}
				case []map[string]interface{}:
					for _, itemMap := range typedValue {
						if shouldUseNestedProcessorDepth(itemMap, relInfo.RelatedModel, relationshipHelper, depth+1) {
							return true
						}
					}
				}
			}
		}
	}

	return false
}
