package retryhelper

import (
	"fmt"
	"math"
	"time"
)

// RetryOptions 定义重试的配置项
type RetryOptions struct {
	MaxRetries      int              // 最大重试次数
	InitialInterval time.Duration    // 初始重试间隔
	MaxInterval     time.Duration    // 最大重试间隔
	BackoffFactor   float64          // 指数退避的增长因子
	RetryableErrFn  func(error) bool // 用于判断是否为可重试错误的函数（可选）
}

func DefaultRetryOptions() RetryOptions {
	return RetryOptions{
		MaxRetries:      3,
		InitialInterval: 150 * time.Millisecond,
		MaxInterval:     3 * time.Second,
		BackoffFactor:   2.0,
	}
}

// Retry 重试通用函数（用于没有返回值的函数）
func Retry(op func() error, opts RetryOptions) error {
	_, err := RetryWithResult(func() (struct{}, error) {
		return struct{}{}, op()
	}, opts)
	return err
}

// RetryWithResult 重试通用函数（用于带返回值的函数）
func RetryWithResult[T any](op func() (T, error), opts RetryOptions) (result T, err error) {
	interval := opts.InitialInterval
	for attempt := 0; attempt <= opts.MaxRetries; attempt++ {
		result, err = op()
		if err == nil {
			return result, nil
		}

		if opts.RetryableErrFn != nil && !opts.RetryableErrFn(err) {
			return result, err
		}

		if attempt < opts.MaxRetries {
			time.Sleep(interval)
			interval = time.Duration(math.Min(float64(opts.MaxInterval), float64(interval)*opts.BackoffFactor))
		}
	}
	return result, fmt.Errorf("retry failed after %d attempts, last error: %w", opts.MaxRetries+1, err)
}
