package pond

import (
	
	
	
	
)

var ErrPanic = errors.New("task panicked")

var ErrContextCanceled = errors.New("context canceled")

type wrappedTask[ any,  func(error) | func(, error)] struct {
	task          any
	callback      
	ctx           context.Context
	panicRecovery bool
}

func ( wrappedTask[, ]) () error {
	var  
	var  error

	if .ctx != nil {
		if  := .ctx.Err();  != nil {
			 = errors.Join(ErrContextCanceled, )
		}
	}

	if  == nil {
		,  = invokeTask[](.task, .panicRecovery)
	}

	switch c := any(.callback).(type) {
	case func(error):
		()
	case func(, error):
		(, )
	default:
		panic(fmt.Sprintf("unsupported callback type: %#v", .callback))
	}

	return 
}

func wrapTask[ any,  func(error) | func(, error)]( any,  ,  context.Context,  bool) func() error {
	 := &wrappedTask[, ]{
		task:          ,
		callback:      ,
		ctx:           ,
		panicRecovery: ,
	}

	return .Run
}

func invokeTask[ any]( any,  bool) ( ,  error) {
	if  {
		defer func() {
			if  := recover();  != nil {
				if ,  := .(error);  {
					 = fmt.Errorf("%w: %w, %s", ErrPanic, , debug.Stack())
				} else {
					 = fmt.Errorf("%w: %v, %s", ErrPanic, , debug.Stack())
				}
				return
			}
		}()
	}

	switch t := any().(type) {
	case func():
		()
	case func() error:
		 = ()
	case func() :
		 = ()
	case func() (, error):
		,  = ()
	default:
		panic(fmt.Sprintf("unsupported task type: %#v", ))
	}
	return
}