package eks

import (
	"context"
	"testing"

	. "github.com/onsi/gomega"
	corev1 "k8s.io/api/core/v1"
	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
	"k8s.io/apimachinery/pkg/runtime"
	"k8s.io/client-go/kubernetes/scheme"
	"sigs.k8s.io/controller-runtime/pkg/client"
	"sigs.k8s.io/controller-runtime/pkg/client/fake"

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

const (
	testRoleARN0 = "arn:aws:iam::111122223333:role/my-cluster-role"
	testRoleARN1 = "arn:aws:iam::111111111111:role/my-cluster-role"
)

func TestCreate(t *testing.T) {
	cases := map[string]struct {
		input  func(task *RBAC)
		expect func(g *GomegaWithT, cli client.Client, result deploy.Result)
	}{
		"attach authorizedSubject to master group": {
			input: func(task *RBAC) {
				cli, _ := task.Remote.GetClient(context.Background())
				cli.Create(context.Background(), initAWSAuthCM().DeepCopy())
			},
			expect: func(g *GomegaWithT, cli client.Client, result deploy.Result) {
				g.Expect(result).Should(Equal(deploy.Done()))
				expectMapRole0 := awsauth.NewRolesAuthMap(testRoleARN0, UserNamePrefix+"-0", []string{K8sGroupMaster})
				expectMapRole1 := awsauth.NewRolesAuthMap(testRoleARN1, UserNamePrefix+"-1", []string{K8sGroupMaster})
				authRW := awsauth.NewAwsAuthReaderWriter(cli)
				authData, err := authRW.Get(context.Background())
				g.Expect(err).Should(Succeed())
				g.Expect(authData.ContainsMapRole(*expectMapRole0)).Should(BeTrue())
				g.Expect(authData.ContainsMapRole(*expectMapRole1)).Should(BeTrue())
			},
		},
		"with controllerassume role suffix": {
			input: func(task *RBAC) {
				cli, _ := task.Remote.GetClient(context.Background())
				cli.Create(context.Background(), initAWSAuthCM().DeepCopy())
				task.Config.ClusterControllerAssumeRoleName = "prod-us-west-2-cluster-controller-assumed-role"
				task.Config.DPControllerAssumeRoleName = "prod-us-west-2-dp-controller-assumed-role"
				task.Config.TiCDCControllerAssumeRoleName = "prod-us-west-2-ticdc-controller-assumed-role"
			},
			expect: func(g *GomegaWithT, cli client.Client, result deploy.Result) {
				g.Expect(result).Should(Equal(deploy.Done()))
				expectMapRole0 := awsauth.NewRolesAuthMap(testRoleARN0, UserNamePrefix+"-0", []string{K8sGroupMaster})
				expectMapRole1 := awsauth.NewRolesAuthMap(testRoleARN1, UserNamePrefix+"-1", []string{K8sGroupMaster})
				assumeRole := utils.GenAWSRoleArn("111122223333", "prod-us-west-2-cluster-controller-assumed-role")
				expectMapRole2 := awsauth.NewRolesAuthMap(assumeRole, UserNamePrefix+"-2", []string{K8sGroupMaster})
				dpAssumeRole := utils.GenAWSRoleArn("111122223333", "prod-us-west-2-dp-controller-assumed-role")
				expectMapRole3 := awsauth.NewRolesAuthMap(dpAssumeRole, UserNamePrefix+"-3", []string{K8sGroupMaster})
				ticdcAssumeRole := utils.GenAWSRoleArn("111122223333", "prod-us-west-2-ticdc-controller-assumed-role")
				expectMapRole4 := awsauth.NewRolesAuthMap(ticdcAssumeRole, UserNamePrefix+"-4", []string{K8sGroupMaster})
				authRW := awsauth.NewAwsAuthReaderWriter(cli)
				authData, err := authRW.Get(context.Background())
				g.Expect(err).Should(Succeed())
				g.Expect(authData.ContainsMapRole(*expectMapRole0)).Should(BeTrue())
				g.Expect(authData.ContainsMapRole(*expectMapRole1)).Should(BeTrue())
				t.Log(authData.MapRoles[3])
				t.Log(expectMapRole2)
				g.Expect(authData.ContainsMapRole(*expectMapRole2)).Should(BeTrue())
				g.Expect(authData.ContainsMapRole(*expectMapRole3)).Should(BeTrue())
				g.Expect(authData.ContainsMapRole(*expectMapRole4)).Should(BeTrue())
			},
		},
	}

	for name, c := range cases {
		t.Run(name, func(t *testing.T) {
			g := NewGomegaWithT(t)
			ctx := &task.Context{
				APPBox: new(v1alpha1.APPBox),
			}
			task := NewRBAC(ctx)
			task.Config = config.RootConfig{
				ControllerConfig: config.ControllerConfig{
					APPBoxConfig: config.APPBoxConfig{
						AuthorizedSubjects: []string{testRoleARN0, testRoleARN1},
					},
					ClusterControllerAssumeRoleName: "prod-us-west-2-cluster-controller-assumed-role",
					DPControllerAssumeRoleName:      "prod-us-west-2-dp-controller-assumed-role",
				},
			}
			task.VPC = &v1alpha1.VPC{
				Spec: v1alpha1.VPCSpec{
					AccountRef: &v1alpha1.AccountReference{
						AccountID: "111122223333",
					},
				},
			}

			s := runtime.NewScheme()
			g.Expect(scheme.AddToScheme(s)).Should(Succeed())
			cli := fake.NewClientBuilder().WithScheme(s).Build()
			task.Remote = &controllers.MockClientGetter{
				Client: cli,
			}

			c.input(task)
			result := task.Create(context.Background())
			c.expect(g, cli, result)
		})
	}
}

func initAWSAuthCM() *corev1.ConfigMap {
	return &corev1.ConfigMap{
		ObjectMeta: metav1.ObjectMeta{
			Name:      "aws-auth",
			Namespace: "kube-system",
		},
		Data: map[string]string{
			"mapRoles": `- groups:
  - system:bootstrappers
  - system:nodes
  rolearn: arn:aws:iam::111122223333:role/my-node-role
  username: system:node:{{EC2PrivateDNSName}}`,
		},
	}
}
