package common

import (
	"context"
	"testing"

	"github.com/stretchr/testify/assert"
	"github.com/tidbcloud/infra-provider/pkg/deploy"
	"github.com/tidbcloud/infra-provider/regional-server/api/v1alpha1"
	"k8s.io/apimachinery/pkg/runtime"
	"k8s.io/apimachinery/pkg/types"
	ctrl "sigs.k8s.io/controller-runtime"
)

func TestGuardian_Create(t *testing.T) {
	s := runtime.NewScheme()
	v1alpha1.AddToScheme(s)
	gu := NewGuardian(fakeTaskContext(t))
	t.Run("AddFinalizer", func(t *testing.T) {
		assert.Nil(t, gu.PrivateLinkService.GetFinalizers())
		result := gu.Create(context.Background())
		res, err, retriableErr := deploy.MinRequeue([]deploy.Result{result})
		assert.Nil(t, err)
		assert.NotNil(t, retriableErr)
		assert.Equal(t, ctrl.Result{Requeue: true, RequeueAfter: 0}, res)
		assert.Equal(t, []string{v1alpha1.Finalizer}, gu.PrivateLinkService.GetFinalizers())
	})
	t.Run("set internet phase", func(t *testing.T) {
		casts := []struct {
			name          string
			vpcPhase      v1alpha1.VPCPhase
			plsPhase      v1alpha1.PrivateLinkServicePhase
			expectedPhase v1alpha1.PrivateLinkServicePhase
			done          bool
		}{
			{"vpc active and pls pending", v1alpha1.VPCPhaseActive, v1alpha1.PrivateLinkServicePhasePending, v1alpha1.PrivateLinkServicePhaseReadyForCreate, false},
			{"vpc inactive and pls pending", v1alpha1.VPCPhasePending, v1alpha1.PrivateLinkServicePhasePending, v1alpha1.PrivateLinkServicePhasePending, false},
			{"vpc active and pls ready for create", v1alpha1.VPCPhaseActive, v1alpha1.PrivateLinkServicePhaseReadyForCreate, v1alpha1.PrivateLinkServicePhaseCreating, true},
			{"vpc active and pls creating", v1alpha1.VPCPhaseActive, v1alpha1.PrivateLinkServicePhaseCreating, v1alpha1.PrivateLinkServicePhaseCreating, true},
			{"vpc active and pls active", v1alpha1.VPCPhaseActive, v1alpha1.PrivateLinkServicePhaseActive, v1alpha1.PrivateLinkServicePhaseActive, true},
			{"vpc active and pls failed", v1alpha1.VPCPhaseActive, v1alpha1.PrivateLinkServicePhaseFailed, v1alpha1.PrivateLinkServicePhaseCreating, true},
		}
		// set finalizer
		gu.PrivateLinkService.Finalizers = []string{}
		gu.Create(context.Background())
		assert.Equal(t, []string{v1alpha1.Finalizer}, gu.PrivateLinkService.GetFinalizers())
		for _, cast := range casts {
			t.Run(cast.name, func(t *testing.T) {
				err := gu.Local.Get(context.Background(), types.NamespacedName{Namespace: gu.PrivateLinkService.Namespace, Name: gu.PrivateLinkService.Name}, gu.PrivateLinkService)
				assert.Nil(t, err)
				gu.PrivateLinkService.Finalizers = []string{v1alpha1.Finalizer}
				gu.VPC.Status.Phase = cast.vpcPhase
				gu.PrivateLinkService.Status.Phase = cast.plsPhase
				result := gu.Create(context.Background())
				assert.Equal(t, cast.done, result.IsDoneState())
				assert.Equal(t, cast.expectedPhase, gu.PrivateLinkService.Status.Phase)
			})
		}
	})
}

func TestGuardian_waitVPCActive(t *testing.T) {
	gu := NewGuardian(fakeTaskContext(t))
	cases := []struct {
		vpcPhase v1alpha1.VPCPhase
		expected bool
	}{
		{v1alpha1.VPCPhaseActive, true},
		{v1alpha1.VPCPhaseCreating, false},
		{v1alpha1.VPCPhaseFailed, false},
		{v1alpha1.VPCPhasePending, false},
		{v1alpha1.VPCPhaseReadyForCreate, false},
		{v1alpha1.VPCPhaseReadyForDelete, false},
	}

	for _, c := range cases {
		t.Run(string(c.vpcPhase), func(t *testing.T) {
			gu.VPC.Status.Phase = c.vpcPhase
			active := gu.waitVPCActive(context.Background())
			assert.Equal(t, c.expected, active)
		})
	}
}
