package supervisor

import (
	
	

	
	
)

// BuilderFunc is a factory function that constructs [process.Runner] instances.
type BuilderFunc[ process.Runner] func(context.Context) (, error)

// Identity returns a [BuilderFunc] that always returns the given runner.
func [ process.Runner]( ) BuilderFunc[] {
	return func( context.Context) (, error) {
		return , nil
	}
}

// Run implements the [process.Runner] interface. It calls the factory function
// to create a runner, then delegates to that runner’s Run method.
func ( BuilderFunc[]) ( context.Context,  process.Callback) error {
	,  := ()
	if  != nil {
		return 
	}
	return .Run(, )
}

// Builder is a reusable [process.Runner] implementation that uses [BuilderFunc]
// on each [Builder.Run] invocation to create a fresh [process.Runner] instance
// for implementations that would otherwise be single-use (do not allow calling
// Run more than once per instance).
type Builder[ process.Runner] struct {
	build BuilderFunc[]

	runnerMu sync.RWMutex
	runner   option.Of[]
}

// NewBuilder returns a new [Builder] instance for the given factory function.
// The function will be called each time [Builder.Run] method is invoked to
// create a fresh runner instance.
func [ process.Runner]( BuilderFunc[]) *Builder[] {
	return &Builder[]{
		build: ,
	}
}

// Runner returns the runner currently executing via [Builder.Run] It returns
// false when no execution is active.
func ( *Builder[]) () (, bool) {
	.runnerMu.RLock()
	defer .runnerMu.RUnlock()
	return .runner.Unwrap()
}

// setRunner updates the currently execution runner instance.
func ( *Builder[]) ( option.Of[]) {
	.runnerMu.Lock()
	defer .runnerMu.Unlock()
	.runner = 
}

// Run implements the [process.Runner] interface. It uses [BuildFunc] to create
// a runner, executes it, and discards the instance when complete.
//
// Use [Builder.Runner] to get the currently executing runner instance.
func ( *Builder[]) ( context.Context,  process.Callback) error {
	,  := .build()
	if  != nil {
		return 
	}

	.setRunner(option.Value())
	defer .setRunner(option.Nil[]())

	return .Run(, )
}