package automationtesting

import (
	"context"

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

// Rig is the L0 generic test harness for the flow runtime. External
// scenario modules construct a Rig and exercise scenarios through its
// methods, without importing backend/internal/... themselves.
//
// The fields are intentionally unexported. Methods on Rig (added as
// scenario coverage grows) are the only sanctioned way to reach the
// underlying executor; no method takes or returns a value from
// backend/internal/... so external callers never need that import.
type Rig struct {
	executor *automation.FlowExecutor
}

// RigOption configures a Rig at construction time. Each option installs
// one substitution into the underlying flow runtime via the corresponding
// automation.Option. Production lookups remain in place for any seam not
// covered by an applied RigOption.
type RigOption func(*rigConfig)

// rigConfig accumulates option intent before NewRig translates it into
// automation.Option calls. Keeping it unexported lets future fields land
// without breaking the external-facing RigOption signature.
type rigConfig struct {
	flowVersionResolver func(ctx context.Context, apiName string, user *models.UserSession) (*models.FlowVersion, error)
}

// WithFlowVersionResolver substitutes the flow runtime's
// FlowDefinition+FlowVersion query path with the supplied in-memory
// resolver. Scenario tests use this to inject a known set of flow
// versions keyed by API name and exercise subflow / trigger dispatch
// without standing up a database.
//
// fn must be safe for concurrent use; the runtime invokes it whenever a
// flow is referenced by API name.
func WithFlowVersionResolver(
	fn func(ctx context.Context, apiName string, user *models.UserSession) (*models.FlowVersion, error),
) RigOption {
	return func(c *rigConfig) {
		c.flowVersionResolver = fn
	}
}

// NewRig constructs a Rig with the supplied options. With the current
// minimal option set, NewRig always succeeds and never returns nil; the
// signature returns a pointer so future option implementations can fail
// with a non-nil error without breaking callers (an error-returning
// constructor will be added when the first such option lands).
//
// Production runtime dependencies (MetadataService, ActionService,
// PersistenceProvider, etc.) are not wired in this minimal Rig — methods
// that need them will be added alongside the helpers that depend on them.
// Scenarios that only validate the option-routing seam can call NewRig
// with no further dependencies.
func NewRig(opts ...RigOption) *Rig {
	cfg := &rigConfig{}
	for _, opt := range opts {
		opt(cfg)
	}

	var execOpts []automation.Option
	if cfg.flowVersionResolver != nil {
		execOpts = append(execOpts, automation.WithFlowVersionResolver(cfg.flowVersionResolver))
	}

	return &Rig{
		executor: automation.NewFlowExecutor(
			nil, // metadataService — wired by future Rig helpers
			nil, // actions
			nil, // interviews
			nil, // persistence
			nil, // query
			nil, // fieldMappings
			nil, // logger (NewFlowExecutor defaults this)
			execOpts...,
		),
	}
}
