package policy

import (
	
	
)

// Executor handles execution and execution results according to a policy. May contain pre-execution and
// post-execution behaviors. Each Executor makes its own determination about whether an execution result is a
// success or failure.
type Executor[ any] interface {
	// PreExecute is called before execution to return an alternative result or error, such as if execution is not allowed or
	// needed.
	PreExecute(exec ExecutionInternal[]) *common.PolicyResult[]

	// Apply performs an execution by calling PreExecute and returning any result, else calling the innerFn PostExecute.
	//
	// If an Executor delays or blocks during execution, it must check that the execution was not canceled in the
	// meantime, else return the ExecutionInternal.Result if it was.
	Apply(innerFn func(failsafe.Execution[]) *common.PolicyResult[]) func(failsafe.Execution[]) *common.PolicyResult[]

	// PostExecute performs synchronous post-execution handling for an execution result.
	PostExecute(exec ExecutionInternal[], result *common.PolicyResult[]) *common.PolicyResult[]

	// IsFailure returns whether the result is a failure according to the corresponding policy.
	IsFailure(result , err error) bool

	// OnSuccess performs post-execution handling for a result that is considered a success according to IsFailure.
	OnSuccess(exec ExecutionInternal[], result *common.PolicyResult[])

	// OnFailure performs post-execution handling for a result that is considered a failure according to IsFailure, possibly
	// creating a new result, else returning the original result.
	OnFailure(exec ExecutionInternal[], result *common.PolicyResult[]) *common.PolicyResult[]
}

// BaseExecutor provides base implementation of Executor.
type BaseExecutor[ any] struct {
	Executor[]
	*BaseFailurePolicy[]
}

var _ Executor[any] = &BaseExecutor[any]{}

func ( *BaseExecutor[]) ( ExecutionInternal[]) *common.PolicyResult[] {
	return nil
}

func ( *BaseExecutor[]) ( func(failsafe.Execution[]) *common.PolicyResult[]) func(failsafe.Execution[]) *common.PolicyResult[] {
	return func( failsafe.Execution[]) *common.PolicyResult[] {
		 := .(ExecutionInternal[])
		 := .Executor.PreExecute()
		if  != nil {
			return 
		}

		 = ()
		return .Executor.PostExecute(, )
	}
}

func ( *BaseExecutor[]) ( ExecutionInternal[],  *common.PolicyResult[]) *common.PolicyResult[] {
	if .Executor.IsFailure(.Result, .Error) {
		 = .Executor.OnFailure(, .WithFailure())
	} else {
		 = .WithDone(true, true)
		.Executor.OnSuccess(, )
	}
	return 
}

func ( *BaseExecutor[]) ( ,  error) bool {
	if .BaseFailurePolicy != nil {
		return .BaseFailurePolicy.IsFailure(, )
	}
	return  != nil
}

func ( *BaseExecutor[]) ( ExecutionInternal[],  *common.PolicyResult[]) {
	if .BaseFailurePolicy != nil && .onSuccess != nil {
		.onSuccess(failsafe.ExecutionEvent[]{
			ExecutionAttempt: .CopyWithResult(),
		})
	}
}

func ( *BaseExecutor[]) ( ExecutionInternal[],  *common.PolicyResult[]) *common.PolicyResult[] {
	if .BaseFailurePolicy != nil && .onFailure != nil {
		.onFailure(failsafe.ExecutionEvent[]{
			ExecutionAttempt: .CopyWithResult(),
		})
	}
	return 
}