// Code generated by protoc-gen-go_temporal. DO NOT EDIT.
// versions:
//
//	protoc-gen-go_temporal dev (latest)
//	protoc (unknown)
//
// source: test/opaque/opaque.proto
package opaquexns

import (
	"context"
	"errors"
	"fmt"
	temporalv1 "github.com/cludden/protoc-gen-go-temporal/gen/temporal/v1"
	xnsv1 "github.com/cludden/protoc-gen-go-temporal/gen/temporal/xns/v1"
	opaque "github.com/cludden/protoc-gen-go-temporal/gen/test/opaque"
	xns "github.com/cludden/protoc-gen-go-temporal/pkg/xns"
	uuid "github.com/google/uuid"
	enumsv1 "go.temporal.io/api/enums/v1"
	activity "go.temporal.io/sdk/activity"
	client "go.temporal.io/sdk/client"
	temporal "go.temporal.io/sdk/temporal"
	worker "go.temporal.io/sdk/worker"
	workflow "go.temporal.io/sdk/workflow"
	anypb "google.golang.org/protobuf/types/known/anypb"
	durationpb "google.golang.org/protobuf/types/known/durationpb"
	"time"
)

// OpaqueOptions is used to configure test.opaque.Opaque xns activity registration
type OpaqueOptions struct {
	// errorConverter is used to customize error
	errorConverter func(error) error
	// filter is used to filter xns activity registrations. It receives as
	// input the original activity name, and should return one of the following:
	// 1. the original activity name, for no changes
	// 2. a modified activity name, to override the original activity name
	// 3. an empty string, to skip registration
	filter func(string) string
}

// NewOpaqueOptions initializes a new OpaqueOptions value
func NewOpaqueOptions() *OpaqueOptions {
	return &OpaqueOptions{}
}

// WithErrorConverter overrides the default error converter applied to xns activity errors
func (opts *OpaqueOptions) WithErrorConverter(errorConverter func(error) error) *OpaqueOptions {
	opts.errorConverter = errorConverter
	return opts
}

// Filter is used to filter registered xns activities or customize their name
func (opts *OpaqueOptions) WithFilter(filter func(string) string) *OpaqueOptions {
	opts.filter = filter
	return opts
}

// convertError is applied to all xns activity errors
func (opts *OpaqueOptions) convertError(err error) error {
	if err == nil {
		return nil
	}
	if opts != nil && opts.errorConverter != nil {
		return opts.errorConverter(err)
	}
	return xns.ErrorToApplicationError(err)
}

// filterActivity is used to filter xns activity registrations
func (opts *OpaqueOptions) filterActivity(name string) string {
	if opts == nil || opts.filter == nil {
		return name
	}
	return opts.filter(name)
}

// opaqueOptions is a reference to the OpaqueOptions initialized at registration
var opaqueOptions *OpaqueOptions

// RegisterOpaqueActivities registers test.opaque.Opaque cross-namespace activities
func RegisterOpaqueActivities(r worker.ActivityRegistry, c opaque.OpaqueClient, options ...*OpaqueOptions) {
	if opaqueOptions == nil && len(options) > 0 && options[0] != nil {
		opaqueOptions = options[0]
	}
	a := &opaqueActivities{c}
	if name := opaqueOptions.filterActivity("test.opaque.Opaque.CancelWorkflow"); name != "" {
		r.RegisterActivityWithOptions(a.CancelWorkflow, activity.RegisterOptions{Name: name})
	}
	if name := opaqueOptions.filterActivity(opaque.PutOpaqueExampleWorkflowName); name != "" {
		r.RegisterActivityWithOptions(a.PutOpaqueExample, activity.RegisterOptions{Name: name})
	}
	if name := opaqueOptions.filterActivity("test.opaque.Opaque.GetPutOpaqueExample"); name != "" {
		r.RegisterActivityWithOptions(a.GetPutOpaqueExample, activity.RegisterOptions{Name: name})
	}
	if name := opaqueOptions.filterActivity("test.opaque.Opaque.PutOpaqueExampleWithSignalOpaque"); name != "" {
		r.RegisterActivityWithOptions(a.PutOpaqueExampleWithSignalOpaque, activity.RegisterOptions{Name: name})
	}
	if name := opaqueOptions.filterActivity(opaque.SignalOpaqueSignalName); name != "" {
		r.RegisterActivityWithOptions(a.SignalOpaque, activity.RegisterOptions{Name: name})
	}
}

// PutOpaqueExampleWorkflowOptions are used to configure a(n) test.opaque.Opaque.PutOpaqueExample workflow execution
type PutOpaqueExampleWorkflowOptions struct {
	ActivityOptions      *workflow.ActivityOptions
	Detached             bool
	HeartbeatInterval    time.Duration
	HeartbeatTimeout     time.Duration
	ParentClosePolicy    enumsv1.ParentClosePolicy
	StartWorkflowOptions *client.StartWorkflowOptions
}

// NewPutOpaqueExampleWorkflowOptions initializes a new PutOpaqueExampleWorkflowOptions value
func NewPutOpaqueExampleWorkflowOptions() *PutOpaqueExampleWorkflowOptions {
	return &PutOpaqueExampleWorkflowOptions{}
}

// Build initializes the activity context and input
func (opts *PutOpaqueExampleWorkflowOptions) Build(ctx workflow.Context, input *opaque.OpaqueExample) (workflow.Context, *xnsv1.WorkflowRequest, error) {
	// initialize start workflow options
	swo := client.StartWorkflowOptions{}
	if opts.StartWorkflowOptions != nil {
		swo = *opts.StartWorkflowOptions
	}

	// initialize workflow id if not set
	if swo.ID == "" {
		if err := workflow.SideEffect(ctx, func(ctx workflow.Context) any {
			id, err := uuid.NewRandom()
			if err != nil {
				workflow.GetLogger(ctx).Error("error generating workflow id", "error", err)
				return nil
			}
			return id
		}).Get(&swo.ID); err != nil {
			return nil, nil, err
		}
	}
	if swo.ID == "" {
		return nil, nil, temporal.NewNonRetryableApplicationError("workflow id is required", "InvalidArgument", nil)
	}

	// marshal workflow request protobuf message
	inputpb, err := anypb.New(input)
	if err != nil {
		return ctx, nil, fmt.Errorf("error marshalling workflow request: %w", err)
	}

	// marshal start workflow options protobuf message
	swopb, err := xns.MarshalStartWorkflowOptions(swo)
	if err != nil {
		return ctx, nil, fmt.Errorf("error marshalling start workflow options: %w", err)
	}

	// marshal parent close policy protobuf message
	var parentClosePolicy temporalv1.ParentClosePolicy
	switch opts.ParentClosePolicy {
	case enumsv1.PARENT_CLOSE_POLICY_ABANDON:
		parentClosePolicy = temporalv1.ParentClosePolicy_PARENT_CLOSE_POLICY_ABANDON
	case enumsv1.PARENT_CLOSE_POLICY_REQUEST_CANCEL:
		parentClosePolicy = temporalv1.ParentClosePolicy_PARENT_CLOSE_POLICY_REQUEST_CANCEL
	case enumsv1.PARENT_CLOSE_POLICY_TERMINATE:
		parentClosePolicy = temporalv1.ParentClosePolicy_PARENT_CLOSE_POLICY_TERMINATE
	}

	// initialize xns activity options
	ao := workflow.ActivityOptions{}
	if opts.ActivityOptions != nil {
		ao = *opts.ActivityOptions
	}

	if ao.HeartbeatTimeout == 0 {
		ao.HeartbeatTimeout = time.Second * 60
	}

	if ao.StartToCloseTimeout == 0 && ao.ScheduleToCloseTimeout == 0 {
		ao.ScheduleToCloseTimeout = time.Hour * 24
	}

	// WaitForCancellation must be set otherwise the underlying workflow is not guaranteed to be canceled
	ao.WaitForCancellation = true

	// configure heartbeat interval
	if opts.HeartbeatInterval == 0 {
		opts.HeartbeatInterval = ao.HeartbeatTimeout / 2
	}

	ctx = workflow.WithActivityOptions(ctx, ao)

	return ctx, &xnsv1.WorkflowRequest{
		Detached:             opts.Detached,
		HeartbeatInterval:    durationpb.New(opts.HeartbeatInterval),
		ParentClosePolicy:    parentClosePolicy,
		Request:              inputpb,
		StartWorkflowOptions: swopb,
	}, nil
}

// WithActivityOptions can be used to customize the activity options
func (opts *PutOpaqueExampleWorkflowOptions) WithActivityOptions(ao workflow.ActivityOptions) *PutOpaqueExampleWorkflowOptions {
	opts.ActivityOptions = &ao
	return opts
}

// WithDetached can be used to start a workflow execution and exit immediately
func (opts *PutOpaqueExampleWorkflowOptions) WithDetached(d bool) *PutOpaqueExampleWorkflowOptions {
	opts.Detached = d
	return opts
}

// WithHeartbeatInterval can be used to customize the activity heartbeat interval
func (opts *PutOpaqueExampleWorkflowOptions) WithHeartbeatInterval(d time.Duration) *PutOpaqueExampleWorkflowOptions {
	opts.HeartbeatInterval = d
	return opts
}

// WithHeartbeatTimeout can be used to customize the activity heartbeat timeout
func (opts *PutOpaqueExampleWorkflowOptions) WithHeartbeatTimeout(d time.Duration) *PutOpaqueExampleWorkflowOptions {
	opts.HeartbeatTimeout = d
	return opts
}

// WithParentClosePolicy can be used to customize the cancellation propagation behavior
func (opts *PutOpaqueExampleWorkflowOptions) WithParentClosePolicy(policy enumsv1.ParentClosePolicy) *PutOpaqueExampleWorkflowOptions {
	opts.ParentClosePolicy = policy
	return opts
}

// WithStartWorkflowOptions can be used to customize the start workflow options
func (opts *PutOpaqueExampleWorkflowOptions) WithStartWorkflow(swo client.StartWorkflowOptions) *PutOpaqueExampleWorkflowOptions {
	opts.StartWorkflowOptions = &swo
	return opts
}

// PutOpaqueExampleRun provides a handle to a test.opaque.Opaque.PutOpaqueExample workflow execution
type PutOpaqueExampleRun interface {
	// Cancel cancels the workflow
	Cancel(workflow.Context) error

	// Future returns the inner workflow.Future
	Future() workflow.Future

	// Get returns the inner workflow.Future
	Get(workflow.Context) (*opaque.OpaqueExample, error)

	// ID returns the workflow id
	ID() string

	// SignalOpaque executes a(n) test.opaque.Opaque.SignalOpaque signal and blocks until completion
	SignalOpaque(workflow.Context, *opaque.OpaqueExample, ...*SignalOpaqueSignalOptions) error

	// SignalOpaqueAsync executes a(n) test.opaque.Opaque.SignalOpaque signal and returns a handle to the underlying activity
	SignalOpaqueAsync(workflow.Context, *opaque.OpaqueExample, ...*SignalOpaqueSignalOptions) (SignalOpaqueSignalHandle, error)
}

// putOpaqueExampleRun provides a(n) PutOpaqueExampleRun implementation
type putOpaqueExampleRun struct {
	cancel            func()
	ctx               workflow.Context
	future            workflow.Future
	id                string
	heartbeatInterval time.Duration
	parentClosePolicy enumsv1.ParentClosePolicy
}

// Cancel the underlying workflow execution
func (r *putOpaqueExampleRun) Cancel(ctx workflow.Context) error {
	if r.cancel != nil {
		r.cancel()
		if _, err := r.Get(ctx); err != nil && !errors.Is(err, workflow.ErrCanceled) {
			return err
		}
		return nil
	}
	return CancelOpaqueWorkflow(ctx, r.id, "")
}

// Future returns the underlying activity future
func (r *putOpaqueExampleRun) Future() workflow.Future {
	if r.future == nil {
		rr := GetPutOpaqueExampleAsync(r.ctx, r.id, "").(*putOpaqueExampleRun)
		r.future = rr.future
		r.cancel = rr.cancel
	}
	return r.future
}

// Get blocks on activity completion and returns the underlying workflow result
func (r *putOpaqueExampleRun) Get(ctx workflow.Context) (*opaque.OpaqueExample, error) {
	ctx, cancel := workflow.WithCancel(ctx)
	if r.future == nil {
		rr := GetPutOpaqueExampleAsync(ctx, r.id, "", NewGetPutOpaqueExampleOptions().WithParentClosePolicy(r.parentClosePolicy).WithHeartbeatInterval(r.heartbeatInterval)).(*putOpaqueExampleRun)
		r.future = rr.future
		r.cancel = cancel
	}
	var resp opaque.OpaqueExample
	if err := r.future.Get(ctx, &resp); err != nil {
		return nil, err
	}
	return &resp, nil
}

// ID returns the underlying workflow id
func (r *putOpaqueExampleRun) ID() string {
	return r.id
}

// SignalOpaque executes a(n) test.opaque.Opaque.SignalOpaque signal and blocks until the underlying activity completes
func (r *putOpaqueExampleRun) SignalOpaque(ctx workflow.Context, req *opaque.OpaqueExample, opts ...*SignalOpaqueSignalOptions) error {
	return SignalOpaque(ctx, r.ID(), "", req, opts...)
}

// SignalOpaqueAsync executes a(n) test.opaque.Opaque.SignalOpaque signal and returns a handle to the underlying activity
func (r *putOpaqueExampleRun) SignalOpaqueAsync(ctx workflow.Context, req *opaque.OpaqueExample, opts ...*SignalOpaqueSignalOptions) (SignalOpaqueSignalHandle, error) {
	return SignalOpaqueAsync(ctx, r.ID(), "", req, opts...)
}

// PutOpaqueExample executes a(n) test.opaque.Opaque.PutOpaqueExample workflow and blocks until error or response is received
func PutOpaqueExample(ctx workflow.Context, req *opaque.OpaqueExample, opts ...*PutOpaqueExampleWorkflowOptions) (*opaque.OpaqueExample, error) {
	run, err := PutOpaqueExampleAsync(ctx, req, opts...)
	if err != nil {
		return nil, err
	}
	return run.Get(ctx)
}

// PutOpaqueExampleAsync executes a(n) test.opaque.Opaque.PutOpaqueExample workflow and returns a handle to the underlying activity
func PutOpaqueExampleAsync(ctx workflow.Context, input *opaque.OpaqueExample, opts ...*PutOpaqueExampleWorkflowOptions) (PutOpaqueExampleRun, error) {
	activityName := opaqueOptions.filterActivity(opaque.PutOpaqueExampleWorkflowName)
	if activityName == "" {
		return nil, temporal.NewNonRetryableApplicationError(
			fmt.Sprintf("no activity registered for %s", opaque.PutOpaqueExampleWorkflowName),
			"Unimplemented",
			nil,
		)
	}

	var opt *PutOpaqueExampleWorkflowOptions
	if len(opts) > 0 && opts[0] != nil {
		opt = opts[0]
	} else {
		opt = NewPutOpaqueExampleWorkflowOptions()
	}
	ctx, req, err := opt.Build(ctx, input)
	if err != nil {
		return nil, opaqueOptions.convertError(err)
	}
	ctx, cancel := workflow.WithCancel(ctx)
	return &putOpaqueExampleRun{
		cancel: cancel,
		future: workflow.ExecuteActivity(ctx, activityName, req),
		id:     req.GetStartWorkflowOptions().GetId(),
	}, nil
}

// GetPutOpaqueExample returns a(n) test.opaque.Opaque.PutOpaqueExample workflow execution
func GetPutOpaqueExample(ctx workflow.Context, workflowID string, runID string, options ...*GetPutOpaqueExampleOptions) (out *opaque.OpaqueExample, err error) {
	out, err = GetPutOpaqueExampleAsync(ctx, workflowID, runID, options...).Get(ctx)
	if err != nil {
		return nil, err
	}
	return out, nil
}

// GetPutOpaqueExampleAsync returns a handle to a(n) test.opaque.Opaque.PutOpaqueExample workflow execution
func GetPutOpaqueExampleAsync(ctx workflow.Context, workflowID string, runID string, options ...*GetPutOpaqueExampleOptions) PutOpaqueExampleRun {
	activityName := opaqueOptions.filterActivity("test.opaque.Opaque.GetPutOpaqueExample")
	if activityName == "" {
		f, set := workflow.NewFuture(ctx)
		set.SetError(temporal.NewNonRetryableApplicationError(fmt.Sprintf("no activity registered for %s", activityName), "Unimplemented", nil))
		return &putOpaqueExampleRun{
			future: f,
			id:     workflowID,
		}
	}
	var opt *GetPutOpaqueExampleOptions
	if len(options) > 0 && options[0] != nil {
		opt = options[0]
	} else {
		opt = NewGetPutOpaqueExampleOptions()
	}
	ctx, req, err := opt.Build(ctx, workflowID, runID)
	if err != nil {
		f, set := workflow.NewFuture(ctx)
		set.SetError(opaqueOptions.convertError(temporal.NewNonRetryableApplicationError(fmt.Sprintf("no activity registered for %s", activityName), "Unimplemented", nil)))
		return &putOpaqueExampleRun{
			future: f,
			id:     workflowID,
		}
	}
	ctx, cancel := workflow.WithCancel(ctx)
	return &putOpaqueExampleRun{
		cancel: cancel,
		future: workflow.ExecuteActivity(ctx, activityName, req),
		id:     workflowID,
	}
}

// GetPutOpaqueExampleOptions are used to configure a(n) test.opaque.Opaque.PutOpaqueExample workflow execution getter activity
type GetPutOpaqueExampleOptions struct {
	activityOptions   *workflow.ActivityOptions
	heartbeatInterval time.Duration
	parentClosePolicy enumsv1.ParentClosePolicy
}

// NewGetPutOpaqueExampleOptions initializes a new GetPutOpaqueExampleOptions value
func NewGetPutOpaqueExampleOptions() *GetPutOpaqueExampleOptions {
	return &GetPutOpaqueExampleOptions{}
}

// Build initializes the activity context and input
func (opt *GetPutOpaqueExampleOptions) Build(ctx workflow.Context, workflowID string, runID string) (workflow.Context, *xnsv1.GetWorkflowRequest, error) {
	if opt.heartbeatInterval == 0 {
		opt.heartbeatInterval = 30000000000 // 30 seconds
	}

	// configure activity options
	var ao workflow.ActivityOptions
	if opt.activityOptions != nil {
		ao = *opt.activityOptions
	} else {
		ao = workflow.ActivityOptions{}
	}
	if ao.HeartbeatTimeout == 0 {
		ao.HeartbeatTimeout = 60000000000 // 1 minute
	}
	// WaitForCancellation must be set otherwise the underlying workflow is not guaranteed to be canceled
	ao.WaitForCancellation = true

	if ao.StartToCloseTimeout == 0 && ao.ScheduleToCloseTimeout == 0 {
		ao.ScheduleToCloseTimeout = 86400000000000 // 1 day
	}
	ctx = workflow.WithActivityOptions(ctx, ao)

	return ctx, &xnsv1.GetWorkflowRequest{
		HeartbeatInterval: durationpb.New(opt.heartbeatInterval),
		ParentClosePolicy: opt.parentClosePolicy,
		RunId:             runID,
		WorkflowId:        workflowID,
	}, nil
}

// WithActivityOptions can be used to customize the activity options
func (o *GetPutOpaqueExampleOptions) WithActivityOptions(ao workflow.ActivityOptions) *GetPutOpaqueExampleOptions {
	o.activityOptions = &ao
	return o
}

// WithHeartbeatInterval can be used to customize the activity heartbeat interval
func (o *GetPutOpaqueExampleOptions) WithHeartbeatInterval(d time.Duration) *GetPutOpaqueExampleOptions {
	o.heartbeatInterval = d
	return o
}

// WithParentClosePolicy can be used to customize the cancellation propagation behavior
func (o *GetPutOpaqueExampleOptions) WithParentClosePolicy(policy enumsv1.ParentClosePolicy) *GetPutOpaqueExampleOptions {
	o.parentClosePolicy = policy
	return o
}

// PutOpaqueExampleWithSignalOpaqueOptions are used to configure a(n) test.opaque.Opaque.PutOpaqueExampleWithSignalOpaque activity
type PutOpaqueExampleWithSignalOpaqueOptions struct {
	ActivityOptions      *workflow.ActivityOptions
	Detached             bool
	HeartbeatInterval    time.Duration
	HeartbeatTimeout     time.Duration
	ParentClosePolicy    enumsv1.ParentClosePolicy
	StartWorkflowOptions *client.StartWorkflowOptions
}

// NewPutOpaqueExampleWithSignalOpaqueOptions initializes a new PutOpaqueExampleWithSignalOpaqueOptions value
func NewPutOpaqueExampleWithSignalOpaqueOptions() *PutOpaqueExampleWithSignalOpaqueOptions {
	return &PutOpaqueExampleWithSignalOpaqueOptions{}
}

// Build initializes the activity context and input
func (opts *PutOpaqueExampleWithSignalOpaqueOptions) Build(ctx workflow.Context, input *opaque.OpaqueExample, signal *opaque.OpaqueExample) (workflow.Context, *xnsv1.WorkflowRequest, error) {
	// initialize start workflow options
	swo := client.StartWorkflowOptions{}
	if opts.StartWorkflowOptions != nil {
		swo = *opts.StartWorkflowOptions
	}

	// initialize workflow id if not set
	if swo.ID == "" {
		if err := workflow.SideEffect(ctx, func(ctx workflow.Context) any {
			id, err := uuid.NewRandom()
			if err != nil {
				workflow.GetLogger(ctx).Error("error generating workflow id", "error", err)
				return nil
			}
			return id
		}).Get(&swo.ID); err != nil {
			return nil, nil, err
		}
	}
	if swo.ID == "" {
		return nil, nil, temporal.NewNonRetryableApplicationError("workflow id is required", "InvalidArgument", nil)
	}

	// marshal workflow request protobuf message
	inputpb, err := anypb.New(input)
	if err != nil {
		return ctx, nil, fmt.Errorf("error marshalling workflow request: %w", err)
	}

	// marshal signal request protobuf message
	signalpb, err := anypb.New(signal)
	if err != nil {
		return ctx, nil, fmt.Errorf("error marshalling signal request: %w", err)
	}

	// marshal start workflow options protobuf message
	swopb, err := xns.MarshalStartWorkflowOptions(swo)
	if err != nil {
		return ctx, nil, fmt.Errorf("error marshalling start workflow options: %w", err)
	}

	// marshal parent close policy protobuf message
	var parentClosePolicy temporalv1.ParentClosePolicy
	switch opts.ParentClosePolicy {
	case enumsv1.PARENT_CLOSE_POLICY_ABANDON:
		parentClosePolicy = temporalv1.ParentClosePolicy_PARENT_CLOSE_POLICY_ABANDON
	case enumsv1.PARENT_CLOSE_POLICY_REQUEST_CANCEL:
		parentClosePolicy = temporalv1.ParentClosePolicy_PARENT_CLOSE_POLICY_REQUEST_CANCEL
	case enumsv1.PARENT_CLOSE_POLICY_TERMINATE:
		parentClosePolicy = temporalv1.ParentClosePolicy_PARENT_CLOSE_POLICY_TERMINATE
	}

	// initialize xns activity options
	ao := workflow.ActivityOptions{}
	if opts.ActivityOptions != nil {
		ao = *opts.ActivityOptions
	}

	if ao.HeartbeatTimeout == 0 {
		ao.HeartbeatTimeout = time.Second * 60
	}

	if ao.StartToCloseTimeout == 0 && ao.ScheduleToCloseTimeout == 0 {
		ao.ScheduleToCloseTimeout = time.Hour * 24
	}

	// WaitForCancellation must be set otherwise the underlying workflow is not guaranteed to be canceled
	ao.WaitForCancellation = true

	// configure heartbeat interval
	if opts.HeartbeatInterval == 0 {
		opts.HeartbeatInterval = ao.HeartbeatTimeout / 2
	}

	ctx = workflow.WithActivityOptions(ctx, ao)

	return ctx, &xnsv1.WorkflowRequest{
		Detached:             opts.Detached,
		HeartbeatInterval:    durationpb.New(opts.HeartbeatInterval),
		ParentClosePolicy:    parentClosePolicy,
		Request:              inputpb,
		Signal:               signalpb,
		StartWorkflowOptions: swopb,
	}, nil
}

// WithActivityOptions can be used to customize the activity options
func (opts *PutOpaqueExampleWithSignalOpaqueOptions) WithActivityOptions(ao workflow.ActivityOptions) *PutOpaqueExampleWithSignalOpaqueOptions {
	opts.ActivityOptions = &ao
	return opts
}

// WithDetached can be used to start a workflow execution and exit immediately
func (opts *PutOpaqueExampleWithSignalOpaqueOptions) WithDetached(d bool) *PutOpaqueExampleWithSignalOpaqueOptions {
	opts.Detached = d
	return opts
}

// WithHeartbeatInterval can be used to customize the activity heartbeat interval
func (opts *PutOpaqueExampleWithSignalOpaqueOptions) WithHeartbeatInterval(d time.Duration) *PutOpaqueExampleWithSignalOpaqueOptions {
	opts.HeartbeatInterval = d
	return opts
}

// WithHeartbeatTimeout can be used to customize the activity heartbeat timeout
func (opts *PutOpaqueExampleWithSignalOpaqueOptions) WithHeartbeatTimeout(d time.Duration) *PutOpaqueExampleWithSignalOpaqueOptions {
	opts.HeartbeatTimeout = d
	return opts
}

// WithParentClosePolicy can be used to customize the cancellation propagation behavior
func (opts *PutOpaqueExampleWithSignalOpaqueOptions) WithParentClosePolicy(policy enumsv1.ParentClosePolicy) *PutOpaqueExampleWithSignalOpaqueOptions {
	opts.ParentClosePolicy = policy
	return opts
}

// WithStartWorkflowOptions can be used to customize the start workflow options
func (opts *PutOpaqueExampleWithSignalOpaqueOptions) WithStartWorkflow(swo client.StartWorkflowOptions) *PutOpaqueExampleWithSignalOpaqueOptions {
	opts.StartWorkflowOptions = &swo
	return opts
}

// PutOpaqueExampleWithSignalOpaque executes a(n) test.opaque.Opaque.PutOpaqueExampleWithSignalOpaque activity and blocks until completion
func PutOpaqueExampleWithSignalOpaque(ctx workflow.Context, input *opaque.OpaqueExample, signal *opaque.OpaqueExample, opts ...*PutOpaqueExampleWithSignalOpaqueOptions) (*opaque.OpaqueExample, error) {
	run, err := PutOpaqueExampleWithSignalOpaqueAsync(ctx, input, signal, opts...)
	if err != nil {
		return nil, err
	}
	return run.Get(ctx)
}

// PutOpaqueExampleWithSignalOpaqueAsync executes a(n) test.opaque.Opaque.PutOpaqueExampleWithSignalOpaque activity and returns a handle to the activity
func PutOpaqueExampleWithSignalOpaqueAsync(ctx workflow.Context, input *opaque.OpaqueExample, signal *opaque.OpaqueExample, opts ...*PutOpaqueExampleWithSignalOpaqueOptions) (PutOpaqueExampleRun, error) {
	activityName := opaqueOptions.filterActivity("test.opaque.Opaque.PutOpaqueExampleWithSignalOpaque")
	if activityName == "" {
		return nil, temporal.NewNonRetryableApplicationError(
			fmt.Sprintf("no activity registered for %s", "test.opaque.Opaque.PutOpaqueExampleWithSignalOpaque"),
			"Unimplemented",
			nil,
		)
	}

	var opt *PutOpaqueExampleWithSignalOpaqueOptions
	if len(opts) > 0 && opts[0] != nil {
		opt = opts[0]
	} else {
		opt = NewPutOpaqueExampleWithSignalOpaqueOptions()
	}
	ctx, req, err := opt.Build(ctx, input, signal)
	if err != nil {
		return nil, err
	}
	ctx, cancel := workflow.WithCancel(ctx)
	return &putOpaqueExampleRun{
		cancel: cancel,
		future: workflow.ExecuteActivity(ctx, activityName, req),
		id:     req.GetStartWorkflowOptions().GetId(),
	}, nil
}

// SignalOpaqueSignalOptions are used to configure a(n) test.opaque.Opaque.SignalOpaque signal execution
type SignalOpaqueSignalOptions struct {
	ActivityOptions   *workflow.ActivityOptions
	HeartbeatInterval time.Duration
}

// NewSignalOpaqueSignalOptions initializes a new SignalOpaqueSignalOptions value
func NewSignalOpaqueSignalOptions() *SignalOpaqueSignalOptions {
	return &SignalOpaqueSignalOptions{}
}

// WithActivityOptions can be used to customize the activity options
func (opts *SignalOpaqueSignalOptions) WithActivityOptions(ao workflow.ActivityOptions) *SignalOpaqueSignalOptions {
	opts.ActivityOptions = &ao
	return opts
}

// WithHeartbeatInterval can be used to customize the activity heartbeat interval
func (opts *SignalOpaqueSignalOptions) WithHeartbeatInterval(d time.Duration) *SignalOpaqueSignalOptions {
	opts.HeartbeatInterval = d
	return opts
}

// SignalOpaqueSignalHandle provides a handle for a test.opaque.Opaque.SignalOpaque signal activity
type SignalOpaqueSignalHandle interface {
	// Cancel cancels the workflow
	Cancel(workflow.Context) error
	// Future returns the inner workflow.Future
	Future() workflow.Future
	// Get returns the inner workflow.Future
	Get(workflow.Context) error
}

// signalOpaqueSignalHandle provides a(n) SignalOpaqueQueryHandle implementation
type signalOpaqueSignalHandle struct {
	cancel func()
	future workflow.Future
}

// Cancel the underlying signal activity
func (r *signalOpaqueSignalHandle) Cancel(ctx workflow.Context) error {
	r.cancel()
	if err := r.Get(ctx); err != nil && !errors.Is(err, workflow.ErrCanceled) {
		return err
	}
	return nil
}

// Future returns the underlying activity future
func (r *signalOpaqueSignalHandle) Future() workflow.Future {
	return r.future
}

// Get blocks on activity completion
func (r *signalOpaqueSignalHandle) Get(ctx workflow.Context) error {
	return r.future.Get(ctx, nil)
}

// SignalOpaque executes a(n) test.opaque.Opaque.SignalOpaque signal
func SignalOpaque(ctx workflow.Context, workflowID string, runID string, req *opaque.OpaqueExample, opts ...*SignalOpaqueSignalOptions) error {
	handle, err := SignalOpaqueAsync(ctx, workflowID, runID, req, opts...)
	if err != nil {
		return err
	}
	return handle.Get(ctx)
}

// SignalOpaqueAsync executes a(n) test.opaque.Opaque.SignalOpaque signal
func SignalOpaqueAsync(ctx workflow.Context, workflowID string, runID string, req *opaque.OpaqueExample, opts ...*SignalOpaqueSignalOptions) (SignalOpaqueSignalHandle, error) {
	activityName := opaqueOptions.filterActivity(opaque.SignalOpaqueSignalName)
	if activityName == "" {
		return nil, temporal.NewNonRetryableApplicationError(
			fmt.Sprintf("no activity registered for %s", opaque.SignalOpaqueSignalName),
			"Unimplemented",
			nil,
		)
	}

	opt := &SignalOpaqueSignalOptions{}
	if len(opts) > 0 && opts[0] != nil {
		opt = opts[0]
	}

	if opt.HeartbeatInterval == 0 {
		opt.HeartbeatInterval = time.Second * 30
	}

	// configure activity options
	var ao workflow.ActivityOptions
	if opt.ActivityOptions != nil {
		ao = *opt.ActivityOptions
	} else {
		ao = workflow.ActivityOptions{}
	}
	if ao.HeartbeatTimeout == 0 {
		ao.HeartbeatTimeout = opt.HeartbeatInterval * 2
	}
	// WaitForCancellation must be set otherwise the underlying workflow is not guaranteed to be canceled
	ao.WaitForCancellation = true

	if ao.StartToCloseTimeout == 0 && ao.ScheduleToCloseTimeout == 0 {
		ao.ScheduleToCloseTimeout = 60000000000 // 1 minute
	}
	ctx = workflow.WithActivityOptions(ctx, ao)

	// marshal workflow request
	wreq, err := anypb.New(req)
	if err != nil {
		return nil, fmt.Errorf("error marshalling workflow request: %w", err)
	}

	ctx, cancel := workflow.WithCancel(ctx)
	return &signalOpaqueSignalHandle{
		cancel: cancel,
		future: workflow.ExecuteActivity(ctx, activityName, &xnsv1.SignalRequest{
			HeartbeatInterval: durationpb.New(opt.HeartbeatInterval),
			WorkflowId:        workflowID,
			RunId:             runID,
			Request:           wreq,
		}),
	}, nil
}

// CancelOpaqueWorkflow cancels an existing workflow
func CancelOpaqueWorkflow(ctx workflow.Context, workflowID string, runID string) error {
	return CancelOpaqueWorkflowAsync(ctx, workflowID, runID).Get(ctx, nil)
}

// CancelOpaqueWorkflowAsync cancels an existing workflow
func CancelOpaqueWorkflowAsync(ctx workflow.Context, workflowID string, runID string) workflow.Future {
	activityName := opaqueOptions.filterActivity("test.opaque.Opaque.CancelWorkflow")
	if activityName == "" {
		f, s := workflow.NewFuture(ctx)
		s.SetError(temporal.NewNonRetryableApplicationError(
			"no activity registered for test.opaque.Opaque.CancelWorkflow",
			"Unimplemented",
			nil,
		))
		return f
	}
	ao := workflow.GetActivityOptions(ctx)
	if ao.StartToCloseTimeout == 0 && ao.ScheduleToCloseTimeout == 0 {
		ao.StartToCloseTimeout = time.Minute
	}
	ctx = workflow.WithActivityOptions(ctx, ao)
	return workflow.ExecuteActivity(ctx, activityName, workflowID, runID)
}

// opaqueActivities provides activities that can be used to interact with a(n) Opaque service's workflow, queries, signals, and updates across namespaces
type opaqueActivities struct {
	client opaque.OpaqueClient
}

// CancelWorkflow cancels an existing workflow execution
func (a *opaqueActivities) CancelWorkflow(ctx context.Context, workflowID string, runID string) error {
	return a.client.CancelWorkflow(ctx, workflowID, runID)
}

// GetPutOpaqueExample retrieves a(n) test.opaque.Opaque.PutOpaqueExample workflow via an activity
func (a *opaqueActivities) GetPutOpaqueExample(ctx context.Context, input *xnsv1.GetWorkflowRequest) (out *opaque.OpaqueExample, err error) {
	heartbeatInterval := input.GetHeartbeatInterval().AsDuration()
	if heartbeatInterval == 0 {
		heartbeatInterval = time.Second * 30
	}

	actx, cancel := context.WithCancel(context.Background())
	defer cancel()
	run := a.client.GetPutOpaqueExample(actx, input.GetWorkflowId(), input.GetRunId())
	done := make(chan struct{})
	go func() {
		defer close(done)
		out, err = run.Get(actx)
	}()

	for {
		select {
		// send heartbeats periodically
		case <-time.After(heartbeatInterval):
			activity.RecordHeartbeat(ctx)

		// return retryable error if the worker is stopping
		case <-activity.GetWorkerStopChannel(ctx):
			return nil, opaqueOptions.convertError(temporal.NewApplicationError("worker is stopping", "WorkerStopped"))

		// catch parent activity context cancellation. in most cases, this should indicate a
		// server-sent cancellation, but there's a non-zero possibility that this cancellation
		// is received due to the worker stopping, prior to detecting the closing of the worker
		// stop channel. to give us an opportunity to detect a cancellation stemming from the
		// worker closing, we again check to see if the worker stop channel is closed before
		// propagating the cancellation
		case <-ctx.Done():
			select {
			case <-activity.GetWorkerStopChannel(ctx):
				activity.GetLogger(ctx).Info("worker is stopping")
				return nil, opaqueOptions.convertError(temporal.NewApplicationError("worker is stopping", "WorkerStopped"))
			default:
				parentClosePolicy := input.GetParentClosePolicy()
				if parentClosePolicy == enumsv1.PARENT_CLOSE_POLICY_REQUEST_CANCEL || parentClosePolicy == enumsv1.PARENT_CLOSE_POLICY_TERMINATE {
					disconnectedCtx, cancel := context.WithTimeout(context.Background(), time.Minute)
					defer cancel()
					if parentClosePolicy == enumsv1.PARENT_CLOSE_POLICY_REQUEST_CANCEL {
						err = run.Cancel(disconnectedCtx)
					} else {
						err = run.Terminate(disconnectedCtx, "xns activity cancellation received", "error", ctx.Err())
					}
					if err != nil {
						return nil, opaqueOptions.convertError(err)
					}
				}
				return nil, opaqueOptions.convertError(temporal.NewCanceledError(ctx.Err().Error()))
			}

		// handle workflow completion
		case <-done:
			return out, opaqueOptions.convertError(err)
		}
	}
}

// PutOpaqueExample executes a(n) test.opaque.Opaque.PutOpaqueExample workflow via an activity
func (a *opaqueActivities) PutOpaqueExample(ctx context.Context, input *xnsv1.WorkflowRequest) (resp *opaque.OpaqueExample, err error) {
	// unmarshal workflow request
	var req opaque.OpaqueExample
	if err := input.Request.UnmarshalTo(&req); err != nil {
		return nil, opaqueOptions.convertError(temporal.NewNonRetryableApplicationError(
			fmt.Sprintf("error unmarshalling workflow request of type %s as github.com/cludden/protoc-gen-go-temporal/gen/test/opaque.OpaqueExample", input.Request.GetTypeUrl()),
			"InvalidArgument",
			err,
		))
	}

	// initialize workflow execution
	actx := ctx
	if !input.GetDetached() {
		var cancel context.CancelFunc
		actx, cancel = context.WithCancel(context.Background())
		defer cancel()
	}
	var run opaque.PutOpaqueExampleRun
	run, err = a.client.PutOpaqueExampleAsync(actx, &req, opaque.NewPutOpaqueExampleOptions().WithStartWorkflowOptions(
		xns.UnmarshalStartWorkflowOptions(input.GetStartWorkflowOptions()),
	))
	if err != nil {
		return nil, opaqueOptions.convertError(err)
	}

	// exit early if detached enabled
	if input.GetDetached() {
		return nil, nil
	}

	// otherwise, wait for execution to complete in child goroutine
	doneCh := make(chan struct{})
	go func() {
		resp, err = run.Get(actx)
		close(doneCh)
	}()

	heartbeatInterval := input.GetHeartbeatInterval().AsDuration()
	if heartbeatInterval == 0 {
		heartbeatInterval = time.Second * 30
	}

	// heartbeat activity while waiting for workflow execution to complete
	for {
		select {
		// send heartbeats periodically
		case <-time.After(heartbeatInterval):
			activity.RecordHeartbeat(ctx, run.ID())

		// return retryable error on worker close
		case <-activity.GetWorkerStopChannel(ctx):
			return nil, temporal.NewApplicationError("worker is stopping", "WorkerStopped")

		// catch parent activity context cancellation. in most cases, this should indicate a
		// server-sent cancellation, but there's a non-zero possibility that this cancellation
		// is received due to the worker stopping, prior to detecting the closing of the worker
		// stop channel. to give us an opportunity to detect a cancellation stemming from the
		// worker closing, we again check to see if the worker stop channel is closed before
		// propagating the cancellation
		case <-ctx.Done():
			select {
			case <-activity.GetWorkerStopChannel(ctx):
				return nil, temporal.NewApplicationError("worker is stopping", "WorkerStopped")
			default:
				parentClosePolicy := input.GetParentClosePolicy()
				if parentClosePolicy == temporalv1.ParentClosePolicy_PARENT_CLOSE_POLICY_REQUEST_CANCEL || parentClosePolicy == temporalv1.ParentClosePolicy_PARENT_CLOSE_POLICY_TERMINATE {
					disconnectedCtx, cancel := context.WithTimeout(context.Background(), time.Minute)
					defer cancel()
					if parentClosePolicy == temporalv1.ParentClosePolicy_PARENT_CLOSE_POLICY_REQUEST_CANCEL {
						err = run.Cancel(disconnectedCtx)
					} else {
						err = run.Terminate(disconnectedCtx, "xns activity cancellation received", "error", ctx.Err())
					}
					if err != nil {
						return nil, opaqueOptions.convertError(err)
					}
				}
				return nil, opaqueOptions.convertError(temporal.NewCanceledError(ctx.Err().Error()))
			}

		// handle workflow completion
		case <-doneCh:
			return resp, opaqueOptions.convertError(err)
		}
	}
}

// PutOpaqueExampleWithSignalOpaque sends a(n) test.opaque.Opaque.SignalOpaque signal to a(n) test.opaque.Opaque.PutOpaqueExample workflow via an activity
func (a *opaqueActivities) PutOpaqueExampleWithSignalOpaque(ctx context.Context, input *xnsv1.WorkflowRequest) (resp *opaque.OpaqueExample, err error) {
	// unmarshal workflow request
	var req opaque.OpaqueExample
	if err := input.Request.UnmarshalTo(&req); err != nil {
		return nil, opaqueOptions.convertError(temporal.NewNonRetryableApplicationError(
			fmt.Sprintf("error unmarshalling workflow request of type %s as github.com/cludden/protoc-gen-go-temporal/gen/test/opaque.OpaqueExample", input.Request.GetTypeUrl()),
			"InvalidArgument",
			err,
		))
	}

	// unmarshal signal request
	var signal opaque.OpaqueExample
	if err := input.Signal.UnmarshalTo(&signal); err != nil {
		return nil, opaqueOptions.convertError(temporal.NewNonRetryableApplicationError(
			fmt.Sprintf("error unmarshalling signal request of type %s as github.com/cludden/protoc-gen-go-temporal/gen/test/opaque.OpaqueExample", input.Signal.GetTypeUrl()),
			"InvalidArgument",
			err,
		))
	}

	// initialize workflow execution
	actx := ctx
	if !input.GetDetached() {
		var cancel context.CancelFunc
		actx, cancel = context.WithCancel(context.Background())
		defer cancel()
	}
	var run opaque.PutOpaqueExampleRun
	run, err = a.client.PutOpaqueExampleWithSignalOpaqueAsync(actx, &req, &signal, opaque.NewPutOpaqueExampleOptions().WithStartWorkflowOptions(
		xns.UnmarshalStartWorkflowOptions(input.GetStartWorkflowOptions()),
	))
	if err != nil {
		return nil, opaqueOptions.convertError(err)
	}

	// exit early if detached enabled
	if input.GetDetached() {
		return nil, nil
	}

	// otherwise, wait for execution to complete in child goroutine
	doneCh := make(chan struct{})
	go func() {
		resp, err = run.Get(actx)
		close(doneCh)
	}()

	heartbeatInterval := input.GetHeartbeatInterval().AsDuration()
	if heartbeatInterval == 0 {
		heartbeatInterval = time.Second * 30
	}

	// heartbeat activity while waiting for workflow execution to complete
	for {
		select {
		// send heartbeats periodically
		case <-time.After(heartbeatInterval):
			activity.RecordHeartbeat(ctx, run.ID())

		// return retryable error on worker close
		case <-activity.GetWorkerStopChannel(ctx):
			return nil, temporal.NewApplicationError("worker is stopping", "WorkerStopped")

		// catch parent activity context cancellation. in most cases, this should indicate a
		// server-sent cancellation, but there's a non-zero possibility that this cancellation
		// is received due to the worker stopping, prior to detecting the closing of the worker
		// stop channel. to give us an opportunity to detect a cancellation stemming from the
		// worker closing, we again check to see if the worker stop channel is closed before
		// propagating the cancellation
		case <-ctx.Done():
			select {
			case <-activity.GetWorkerStopChannel(ctx):
				return nil, temporal.NewApplicationError("worker is stopping", "WorkerStopped")
			default:
				parentClosePolicy := input.GetParentClosePolicy()
				if parentClosePolicy == temporalv1.ParentClosePolicy_PARENT_CLOSE_POLICY_REQUEST_CANCEL || parentClosePolicy == temporalv1.ParentClosePolicy_PARENT_CLOSE_POLICY_TERMINATE {
					disconnectedCtx, cancel := context.WithTimeout(context.Background(), time.Minute)
					defer cancel()
					if parentClosePolicy == temporalv1.ParentClosePolicy_PARENT_CLOSE_POLICY_REQUEST_CANCEL {
						err = run.Cancel(disconnectedCtx)
					} else {
						err = run.Terminate(disconnectedCtx, "xns activity cancellation received", "error", ctx.Err())
					}
					if err != nil {
						return nil, opaqueOptions.convertError(err)
					}
				}
				return nil, opaqueOptions.convertError(temporal.NewCanceledError(ctx.Err().Error()))
			}

		// handle workflow completion
		case <-doneCh:
			return resp, opaqueOptions.convertError(err)
		}
	}
}

// SignalOpaque executes a(n) test.opaque.Opaque.SignalOpaque signal via an activity
func (a *opaqueActivities) SignalOpaque(ctx context.Context, input *xnsv1.SignalRequest) (err error) {
	// unmarshal signal request
	var req opaque.OpaqueExample
	if err := input.Request.UnmarshalTo(&req); err != nil {
		return opaqueOptions.convertError(temporal.NewNonRetryableApplicationError(
			fmt.Sprintf("error unmarshalling signal request of type %s as github.com/cludden/protoc-gen-go-temporal/gen/test/opaque.OpaqueExample", input.Request.GetTypeUrl()),
			"InvalidArgument",
			err,
		))
	}
	// execute signal in child goroutine
	doneCh := make(chan struct{})
	go func() {
		err = a.client.SignalOpaque(ctx, input.GetWorkflowId(), input.GetRunId(), &req)
		close(doneCh)
	}()

	heartbeatInterval := input.GetHeartbeatInterval().AsDuration()
	if heartbeatInterval == 0 {
		heartbeatInterval = time.Second * 10
	}

	// heartbeat activity while waiting for signal to complete
	for {
		select {
		case <-time.After(heartbeatInterval):
			activity.RecordHeartbeat(ctx)
		case <-ctx.Done():
			opaqueOptions.convertError(ctx.Err())
		case <-doneCh:
			return opaqueOptions.convertError(err)
		}
	}
}
