package core

import (
	"fmt"
	"time"
)

// RetryWithBackoff retries fn up to maxRetries times with exponential backoff.
// The delay between attempt i and i+1 is baseDelay * 2^i.
// Returns the first successful result or the last error after all retries are exhausted.
func RetryWithBackoff[T any](fn func() (T, error), maxRetries int, baseDelay time.Duration) (T, error) {
	var zero T
	if maxRetries < 0 {
		return zero, fmt.Errorf("maxRetries must be >= 0, got %d", maxRetries)
	}

	var lastErr error
	for attempt := 0; attempt <= maxRetries; attempt++ {
		result, err := fn()
		if err == nil {
			return result, nil
		}
		lastErr = err

		if attempt < maxRetries {
			delay := baseDelay * (1 << uint(attempt))
			time.Sleep(delay)
		}
	}
	return zero, fmt.Errorf("all %d retries exhausted: %w", maxRetries+1, lastErr)
}
