package automation

import (
	"context"

	"github.com/nexuscrm/shared/pkg/models"
)

// PersistenceProvider defines the subset of PersistenceService needed by Automation
type PersistenceProvider interface {
	Insert(ctx context.Context, tableName string, record models.SObject, user *models.UserSession) (models.SObject, error)
	Update(ctx context.Context, tableName string, id string, updates models.SObject, user *models.UserSession) error
	Delete(ctx context.Context, tableName string, id string, user *models.UserSession) error
	GetRaw(ctx context.Context, objectName string, id string) (models.SObject, error)
	GetLock(ctx context.Context, tableName string, id string) (models.SObject, error) // SELECT ... FOR UPDATE
	// RunInTransaction MUST reuse the outer transaction when `ctx` already
	// carries one. Nested atomic flows (a RunAtomically subflow invoked
	// from another RunAtomically flow) depend on this reentrancy: if the
	// implementation opens a fresh savepoint / independent tx on every
	// call, a subflow's rollback would not propagate to the parent,
	// silently breaking atomic semantics (e.g. Std_ConvertLead's
	// RelinkLeadChildren subflow failing would leave the parent's Account
	// / Contact / Opportunity inserts committed). Production code
	// delegates to TransactionManager.IsTransactionActive → direct call
	// path; test doubles must do the same, or a capability probe must
	// be added here if a future use case needs fresh-savepoint semantics.
	RunInTransaction(ctx context.Context, fn func(context.Context) error) error
	// DetachTx returns a derived context with the active DB transaction removed
	// so that subsequent persistence calls start a fresh independent transaction.
	// Used by AfterSave recordUpdate elements to avoid self-deadlock (TiDB 1205)
	// when updating the triggering record while running inside the outbox transaction.
	DetachTx(ctx context.Context) context.Context
}

// QueryProvider defines the subset of QueryService needed by Automation
type QueryProvider interface {
	QueryWithFilter(ctx context.Context, objectName string, filterExpr string, currentUser *models.UserSession, orderBy string, orderDirection string, limit int) (*models.QueryResult, error)
}

// SchemaLookup is the narrow view of MetadataService that Automation needs
// to resolve lookup-field target objects via referenceTo. Allows tests to
// stub out schema without depending on the full MetadataService.
type SchemaLookup interface {
	GetSchema(ctx context.Context, apiName string) *models.ObjectMetadata
}

// FieldMappingApplier resolves _System_ObjectFieldMapping rows for a
// (source, target, actionType) triple and copies fields from source into
// target. The interface hides the underlying table and mapping-row shape
// so the Flow executor does not depend on bootstrap types.
type FieldMappingApplier interface {
	ApplyMappings(ctx context.Context, sourceObject, targetObject, actionType string, source, target map[string]interface{}) error
}
