package controllers

import (
	"context"
	"fmt"
	"testing"

	. "github.com/onsi/gomega"
	"github.com/tidbcloud/infra-provider/pkg/k8s"
	"github.com/tidbcloud/infra-provider/pkg/namer"
	"github.com/tidbcloud/infra-provider/regional-server/api/v1alpha1"
	"gotest.tools/assert"
	appsv1 "k8s.io/api/apps/v1"
	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
	"k8s.io/apimachinery/pkg/types"
	"sigs.k8s.io/controller-runtime/pkg/client"
	"sigs.k8s.io/controller-runtime/pkg/client/fake"
)

func TestEnsureChartDeploymentReady(t *testing.T) {
	cases := map[string]struct {
		initGetter func(cli client.Client) k8s.ClientGetter
		expect     func(g *WithT, err error)
	}{
		"empty Getter": {
			initGetter: func(cli client.Client) k8s.ClientGetter {
				return &k8s.EmptyGetter{}
			},
			expect: func(g *WithT, err error) {
				g.Expect(err).Should(Equal(fmt.Errorf("empty getter")))
			},
		},
		"deloyment not found": {
			initGetter: func(cli client.Client) k8s.ClientGetter {
				app := &appsv1.Deployment{
					ObjectMeta: metav1.ObjectMeta{
						Name:      "notfound",
						Namespace: "notfound",
					},
				}
				cli.Create(context.Background(), app)
				return &MockClientGetter{
					Client: fake.NewClientBuilder().Build(),
				}
			},

			expect: func(g *WithT, err error) {
				g.Expect(client.IgnoreNotFound(err)).Should(BeNil())
			},
		},
		"deployment not ready": {
			initGetter: func(cli client.Client) k8s.ClientGetter {
				app := &appsv1.Deployment{
					ObjectMeta: metav1.ObjectMeta{
						Name:      "kube-state-metrics",
						Namespace: "monitoring",
					},
				}
				cli.Create(context.Background(), app)
				return &MockClientGetter{
					Client: cli,
				}
			},
			expect: func(g *WithT, err error) {
				g.Expect(err).Should(Equal(fmt.Errorf("chart deployment monitoring/kube-state-metrics not ready")))
			},
		},
		"deployment condition ready": {
			initGetter: func(cli client.Client) k8s.ClientGetter {
				app := &appsv1.Deployment{
					ObjectMeta: metav1.ObjectMeta{
						Name:      "kube-state-metrics",
						Namespace: "monitoring",
					},
					Status: appsv1.DeploymentStatus{
						Conditions: []appsv1.DeploymentCondition{
							{
								Type:   appsv1.DeploymentAvailable,
								Status: "True",
							},
						},
					},
				}
				cli.Create(context.Background(), app)
				return &MockClientGetter{
					Client: cli,
				}
			},
			expect: func(g *WithT, err error) {
				g.Expect(err).Should(Succeed())
			},
		},
	}

	for name, c := range cases {
		t.Run(name, func(t *testing.T) {
			g := NewWithT(t)
			cli := fake.NewClientBuilder().Build()
			getter := c.initGetter(cli)

			c.expect(g, EnsureChartDeploymentReady(context.Background(), getter, types.NamespacedName{
				Namespace: "monitoring",
				Name:      "kube-state-metrics",
			}))
		})
	}
}

func Test_GetResourceGroupName(t *testing.T) {
	vpc := &v1alpha1.VPC{
		ObjectMeta: metav1.ObjectMeta{
			Name: "test",
		},
	}
	assert.Equal(t, namer.UniqueIdentifier(vpc.ObjectMeta, namer.WithLimit(VNetNameLimit)), GetResourceGroupName(vpc))
}
