package appbox

import (
	"testing"

	"github.com/stretchr/testify/assert"

	config2 "github.com/tidbcloud/infra-provider/pkg/config"
	"github.com/tidbcloud/infra-provider/pkg/consts"
	"github.com/tidbcloud/infra-provider/pkg/deploy"
	"github.com/tidbcloud/infra-provider/regional-server/api/v1alpha1"
	"github.com/tidbcloud/infra-provider/regional-server/pkg/config"
	"github.com/tidbcloud/infra-provider/regional-server/pkg/controllers/appbox/task"
)

func TestGetAPPBoxTasks(t *testing.T) {
	initCtx := &task.Context{
		APPBox:              &v1alpha1.APPBox{},
		InfraTmplConfig:     &config.InfraTemplateConfig{},
		DedicatedTmplConfig: &config.DedicatedTemplateConfig{},
		DPTmplConfig:        &config.DPTemplateConfig{},
		Config: config.RootConfig{
			ControllerConfig: config.ControllerConfig{
				Provider: consts.ProviderTypeEKS,
			},
		},
	}
	eksTaskCount := 27
	gkeTaskCount := 24
	aksTaskCount := 22
	t.Run("eks and enabled tiflow operator", func(t *testing.T) {
		ctx := initCtx
		tasks := GetAPPBoxTasks(&APPBoxReconciler{}, ctx)
		if len(tasks) != eksTaskCount {
			t.Errorf("expected %d tasks, got %d", eksTaskCount, len(tasks))
		}
		assert.Equal(t, []string{"EKS", "NodePoolGC", "NodeRole"}, taskNames(tasks[1:4]))
	})
	t.Run("eks and disable tiflow operator", func(t *testing.T) {
		ctx := initCtx
		ctx.APPBox.SetAnnotations(map[string]string{v1alpha1.AnnotationKeyDisableTiflowOperator: "true"})
		tasks := GetAPPBoxTasks(&APPBoxReconciler{}, ctx)
		if len(tasks) != eksTaskCount-1 {
			t.Errorf("expected %d tasks, got %d", eksTaskCount-1, len(tasks))
		}
	})
	t.Run("gke and enabled tiflow operator", func(t *testing.T) {
		ctx := initCtx
		ctx.Config.Provider = consts.ProviderTypeGKE
		ctx.APPBox = &v1alpha1.APPBox{}
		tasks := GetAPPBoxTasks(&APPBoxReconciler{}, ctx)
		if len(tasks) != gkeTaskCount {
			t.Errorf("expected %d tasks, got %d", gkeTaskCount, len(tasks))
		}
		assert.Equal(t, []string{"GKE", "NodePoolGC", "ProjectPolicy"}, taskNames(tasks[2:5]))
	})
	t.Run("gke and disable tiflow operator", func(t *testing.T) {
		ctx := initCtx
		ctx.Config.Provider = consts.ProviderTypeGKE
		ctx.APPBox.SetAnnotations(map[string]string{v1alpha1.AnnotationKeyDisableTiflowOperator: "true"})
		tasks := GetAPPBoxTasks(&APPBoxReconciler{}, ctx)
		if len(tasks) != gkeTaskCount-1 {
			t.Errorf("expected %d tasks, got %d", gkeTaskCount-1, len(tasks))
		}
	})
	t.Run("aks and enabled tiflow operator", func(t *testing.T) {
		ctx := initCtx
		ctx.Config.Provider = consts.ProviderTypeAKS
		ctx.APPBox = &v1alpha1.APPBox{}
		tasks := GetAPPBoxTasks(&APPBoxReconciler{}, ctx)
		if len(tasks) != aksTaskCount {
			t.Errorf("expected %d tasks, got %d", aksTaskCount, len(tasks))
		}
		assert.Equal(t, []string{"AKS", "NodePoolGC", "NodeRoleAssignment"}, taskNames(tasks[2:5]))
	})
	t.Run("aks and disable tiflow operator", func(t *testing.T) {
		ctx := initCtx
		ctx.Config.Provider = consts.ProviderTypeAKS
		ctx.APPBox.SetAnnotations(map[string]string{v1alpha1.AnnotationKeyDisableTiflowOperator: "true"})
		tasks := GetAPPBoxTasks(&APPBoxReconciler{}, ctx)
		if len(tasks) != aksTaskCount-1 {
			t.Errorf("expected %d tasks, got %d", aksTaskCount-1, len(tasks))
		}
	})
}

func taskNames(tasks []deploy.Task) []string {
	names := make([]string, 0, len(tasks))
	for _, task := range tasks {
		names = append(names, task.Name())
	}
	return names
}

func Test_getTiDBOperatorTasks(t *testing.T) {
	tests := []struct {
		name string
		c    *task.Context
		want []string
	}{
		{
			name: "empty context",
			c:    &task.Context{},
			want: []string{"TiDBOperator"},
		},
		{
			name: "do not enable TiDBOperatorV2",
			c: &task.Context{
				VPC: &v1alpha1.VPC{},
			},
			want: []string{"TiDBOperator"},
		},
		{
			name: "enable TiDBOperatorV2",
			c: &task.Context{
				VPC: &v1alpha1.VPC{},
				Config: config.RootConfig{
					FeatureGates: map[config2.FeatureGateName]config2.FeatureGate{
						config2.DeployTiDBOperatorV2: {
							All: true,
						},
					},
				},
			},
			want: []string{"TiDBOperator", "TiDBOperatorV2"},
		},
	}
	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {
			tasks := getTiDBOperatorTasks(tt.c)
			var got []string
			for _, tsk := range tasks {
				got = append(got, tsk.Name())
			}
			assert.Equalf(t, tt.want, got, "getTiDBOperatorTasks(%v)", tt.c)
		})
	}
}
