package recovery

import (
	"time"

	"go.temporal.io/sdk/temporal"
	"go.temporal.io/sdk/workflow"
)

// RetryPolicy defines exponential backoff retry behavior
type RetryPolicy struct {
	// InitialInterval is the first wait duration
	InitialInterval time.Duration
	// MaximumInterval is the max wait duration between retries
	MaximumInterval time.Duration
	// BackoffCoefficient is the multiplier for each retry
	BackoffCoefficient float64
	// MaximumAttempts is the max number of retries (0 = unlimited)
	MaximumAttempts int32
}

// DefaultRetryPolicy returns a sensible default retry policy
func DefaultRetryPolicy() *RetryPolicy {
	return &RetryPolicy{
		InitialInterval:    time.Second,
		MaximumInterval:    time.Minute,
		BackoffCoefficient: 2.0,
		MaximumAttempts:    5,
	}
}

// ActivityRetryPolicy returns a retry policy for activities
func ActivityRetryPolicy() *RetryPolicy {
	return &RetryPolicy{
		InitialInterval:    2 * time.Second,
		MaximumInterval:    5 * time.Minute,
		BackoffCoefficient: 2.0,
		MaximumAttempts:    3,
	}
}

// LLMActivityRetryPolicy returns a retry policy for LLM activities (more lenient)
func LLMActivityRetryPolicy() *RetryPolicy {
	return &RetryPolicy{
		InitialInterval:    5 * time.Second,
		MaximumInterval:    10 * time.Minute,
		BackoffCoefficient: 1.5,
		MaximumAttempts:    5,
	}
}

// ToTemporalRetryPolicy converts to Temporal SDK's RetryPolicy
func (p *RetryPolicy) ToTemporalRetryPolicy() *temporal.RetryPolicy {
	if p == nil {
		return nil
	}
	return &temporal.RetryPolicy{
		InitialInterval:    p.InitialInterval,
		MaximumInterval:    p.MaximumInterval,
		BackoffCoefficient: p.BackoffCoefficient,
		MaximumAttempts:    p.MaximumAttempts,
	}
}

// ApplyRetryPolicy applies a retry policy to activity options
func ApplyRetryPolicy(opts workflow.ActivityOptions, policy *RetryPolicy) workflow.ActivityOptions {
	if policy == nil {
		return opts
	}
	opts.RetryPolicy = policy.ToTemporalRetryPolicy()
	return opts
}

// IsRetryableError checks if an error is retryable
func IsRetryableError(err error) bool {
	if err == nil {
		return false
	}

	// Temporal SDK errors that should not be retried
	if temporal.IsTimeoutError(err) {
		return true // Timeouts are usually retryable
	}
	if temporal.IsCanceledError(err) {
		return false // Canceled workflows should not be retried
	}
	if temporal.IsApplicationError(err) {
		// Application errors are retryable by default
		return true
	}

	// Generic errors are retryable
	return true
}

// RetryCount holds retry attempt information
type RetryCount struct {
	Current int
	Maximum int
}

// CanRetry checks if we can retry
func (rc *RetryCount) CanRetry() bool {
	if rc.Maximum == 0 {
		return true // Unlimited retries
	}
	return rc.Current < rc.Maximum
}

// Increment increments the retry count
func (rc *RetryCount) Increment() {
	rc.Current++
}
