package deploy

import (
	"errors"
	"testing"
	"time"

	"github.com/stretchr/testify/assert"
	ctrl "sigs.k8s.io/controller-runtime"
)

func TestRetriableError(t *testing.T) {
	t.Run("new wraps error with result", func(t *testing.T) {
		err := NewRetriableError(errors.New("base"), ctrl.Result{RequeueAfter: 3 * time.Minute})
		assert.Error(t, err)
		assert.Equal(t, "base", err.Error())
		assert.Equal(t, 3*time.Minute, ShouldRequeue(err).RequeueAfter)
	})

	t.Run("new wraps nil error", func(t *testing.T) {
		err := NewRetriableError(nil, ctrl.Result{Requeue: true})
		assert.NotNil(t, err)
		assert.Equal(t, "", err.Error())
		assert.True(t, ShouldRequeue(err).Requeue)
	})

	t.Run("new updates existing retriable error", func(t *testing.T) {
		original := NewRetriableError(errors.New("base"), ctrl.Result{RequeueAfter: 1 * time.Minute})
		updated := NewRetriableError(original, ctrl.Result{RequeueAfter: 5 * time.Minute})
		assert.Equal(t, original, updated)
		assert.Equal(t, 5*time.Minute, ShouldRequeue(updated).RequeueAfter)
	})

	t.Run("new panics on zero result", func(t *testing.T) {
		assert.Panics(t, func() {
			NewRetriableError(errors.New("x"), ctrl.Result{})
		})
	})

	t.Run("error returns inner error string", func(t *testing.T) {
		assert.Equal(t, "inner", NewRetriableError(errors.New("inner"), ctrl.Result{Requeue: true}).Error())
		assert.Equal(t, "", NewRetriableError(nil, ctrl.Result{Requeue: true}).Error())
	})

	t.Run("should requeue extracts result from retriable error", func(t *testing.T) {
		err := NewRetriableError(errors.New("x"), ctrl.Result{RequeueAfter: 2 * time.Minute})
		assert.Equal(t, 2*time.Minute, ShouldRequeue(err).RequeueAfter)
		assert.Equal(t, ctrl.Result{}, ShouldRequeue(errors.New("plain")))
	})

	t.Run("requeue only matches sentinel", func(t *testing.T) {
		assert.True(t, RequeueOnly(NewRetriableError(ErrorRequeueOnly, ctrl.Result{Requeue: true})))
		assert.False(t, RequeueOnly(NewRetriableError(errors.New("transient"), ctrl.Result{Requeue: true})))
		assert.False(t, RequeueOnly(errors.New("plain")))
	})
}
