//go:build unit || all
// +build unit all

package deploy

import (
	"fmt"
	"testing"
	"time"

	"github.com/onsi/gomega"
	ctrl "sigs.k8s.io/controller-runtime"

	"github.com/tidbcloud/ticdc-service-ng/pkg/k8s"
)

func TestRequeueDuration(t *testing.T) {
	fakeErr := fmt.Errorf("fake error")
	cases := map[string]struct {
		results []Result

		requeue      ctrl.Result
		err          bool
		retriableErr bool
	}{
		"all success": {
			results:      []Result{Done()},
			requeue:      ctrl.Result{},
			err:          false,
			retriableErr: false,
		},
		"different durations": {
			results: []Result{
				Done(),
				Error(fakeErr).WithRequeuAfter(1 * time.Second),
				Error(fakeErr).WithRequeuAfter(2 * time.Second),
				Error(fakeErr).WithRequeuAfter(3 * time.Second),
			},
			requeue:      ctrl.Result{Requeue: true, RequeueAfter: 1 * time.Second},
			err:          false,
			retriableErr: true,
		},
		"end with successful task": {
			results: []Result{
				Error(fakeErr).WithRequeuAfter(1 * time.Second),
				Error(fakeErr).WithRequeuAfter(2 * time.Second),
				Error(fakeErr).WithRequeuAfter(3 * time.Second),
				Done(),
			},
			requeue:      ctrl.Result{Requeue: true, RequeueAfter: 1 * time.Second},
			err:          false,
			retriableErr: true,
		},
		"nil error with requeue": {
			results: []Result{
				Error(nil).WithRequeuAfter(1 * time.Second),
				Done(),
			},
			requeue:      ctrl.Result{Requeue: true, RequeueAfter: 1 * time.Second},
			err:          false,
			retriableErr: true,
		},
		"requeue only error with requeue": {
			results: []Result{
				Error(k8s.RequeueOnlyError).WithRequeuAfter(1 * time.Second),
				Done(),
			},
			requeue:      ctrl.Result{Requeue: true, RequeueAfter: 1 * time.Second},
			err:          false,
			retriableErr: false,
		},
		"requeue only error and more errors": {
			results: []Result{
				Error(k8s.RequeueOnlyError).WithRequeuAfter(1 * time.Second),
				Error(fakeErr).WithRequeuAfter(1 * time.Second),
				Done(),
			},
			requeue:      ctrl.Result{Requeue: true, RequeueAfter: 1 * time.Second},
			err:          false,
			retriableErr: true,
		},
	}
	for name, tc := range cases {
		t.Run(name, func(t *testing.T) {
			g := gomega.NewGomegaWithT(t)
			d, err, retriableErr := MinRequeue(tc.results)
			g.Expect(d).To(gomega.Equal(tc.requeue))
			if tc.err {
				g.Expect(err).NotTo(gomega.BeNil())
			} else {
				g.Expect(err).To(gomega.BeNil())
			}

			if tc.retriableErr {
				g.Expect(retriableErr).NotTo(gomega.BeNil())
			} else {
				g.Expect(retriableErr).To(gomega.BeNil())
			}
		})
	}
}
