package automation

import (
	"context"
	"fmt"

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

// ResolveActionCallInputParameters resolves an actionCall's input parameters
// using the same Flow variable semantics as in-engine actionCall handlers.
func (e *FlowExecutor) ResolveActionCallInputParameters(ctx context.Context, interview *models.FlowInterview, action *models.FlowActionCall, user *models.UserSession) (map[string]interface{}, error) {
	params := map[string]interface{}{}
	if action == nil {
		return params, nil
	}
	for _, p := range action.InputParameters {
		value, err := e.deepResolveFlowResource(ctx, interview, user, p.Value)
		if err != nil {
			return nil, err
		}
		params[p.Name] = value
	}
	return params, nil
}

// AssignActionCallOutputs writes a handler's output map through the Flow
// actionCall output-parameter bindings.
func (e *FlowExecutor) AssignActionCallOutputs(interview *models.FlowInterview, action *models.FlowActionCall, outputs map[string]interface{}) {
	assignActionCallOutputs(interview, action, outputs)
}

// RouteActionCallFault follows action.FaultConnector when present; otherwise it
// returns the supplied error to the caller.
func (e *FlowExecutor) RouteActionCallFault(ctx context.Context, interview *models.FlowInterview, action *models.FlowActionCall, err error) (string, error) {
	if action != nil && action.FaultConnector != nil {
		return e.routeFault(ctx, interview, action.FaultConnector.TargetReference, err)
	}
	return "", err
}

// PreparedRecordUpdate returns the prepared update stored for the current Flow
// execution, if any.
func (e *FlowExecutor) PreparedRecordUpdate(ctx context.Context, objectAPIName string, recordID string) *models.PreparedRecordUpdate {
	return flowRuntimeContextFromCtx(ctx).PreparedRecordUpdate(objectAPIName, recordID)
}

// CommitPreparedRecordUpdate resumes the shared prepared-update persistence
// path from a product-owned actionCall handler.
func (e *FlowExecutor) CommitPreparedRecordUpdate(ctx context.Context, objectAPIName string, recordID string, prepared *models.PreparedRecordUpdate, extraUpdates models.SObject, user *models.UserSession) error {
	if e == nil || e.persistence == nil {
		return fmt.Errorf("flow executor persistence unavailable")
	}
	return flowRecordMutationValidation(
		e.persistence.CommitPreparedUpdate(ctx, objectAPIName, recordID, prepared, extraUpdates, user),
	)
}

// PublishPostUpsertRecord records an engine-confirmed upsert snapshot for
// later actionCall handlers that read the per-execution post-upsert registry.
func (e *FlowExecutor) PublishPostUpsertRecord(ctx context.Context, objectAPIName string, record models.SObject) {
	e.publishPostUpsertRecord(ctx, objectAPIName, record)
}

// LookupFieldMetadata returns FieldMetadata for objectAPIName.fieldAPIName.
func (e *FlowExecutor) LookupFieldMetadata(ctx context.Context, objectAPIName string, fieldAPIName string) *models.FieldMetadata {
	return e.lookupFieldMeta(ctx, objectAPIName, fieldAPIName)
}

// LookupObjectSchema returns ObjectMetadata for objectAPIName.
func (e *FlowExecutor) LookupObjectSchema(ctx context.Context, objectAPIName string) *models.ObjectMetadata {
	return e.lookupObjectSchema(ctx, objectAPIName)
}

// ObjectSchemaLookupAvailable reports whether this executor has a schema
// provider for product-owned handlers that must fail closed without metadata.
func (e *FlowExecutor) ObjectSchemaLookupAvailable() bool {
	return e != nil && (e.objectSchemaLookup != nil || e.metadata != nil)
}
