package eks

import (
	"context"
	"fmt"
	"time"

	rbacv1 "k8s.io/api/rbac/v1"
	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
	"sigs.k8s.io/controller-runtime/pkg/client"

	"github.com/tidbcloud/eks-provider/controllers/network/task"
	"github.com/tidbcloud/infra-provider/pkg/awsauth"
	"github.com/tidbcloud/infra-provider/pkg/consts"
	"github.com/tidbcloud/infra-provider/pkg/deploy"
	"github.com/tidbcloud/infra-provider/pkg/k8s"
	"github.com/tidbcloud/infra-provider/pkg/util"
)

type RBAC struct {
	*task.BaseTask
}

func NewRBAC(ctx *task.Context) *RBAC {
	return &RBAC{BaseTask: &task.BaseTask{Context: ctx}}
}

func (t *RBAC) Name() string {
	return "RBAC"
}

func (t *RBAC) Create(ctx context.Context) deploy.Result {
	t.BeginAt = util.Pointer(time.Now())
	cli, err := t.Remote.GetClient(ctx)
	if err != nil {
		return deploy.Panic(err)
	}
	if t.Network.Status.IAM.AccountID == "" {
		return deploy.Error(fmt.Errorf("AWS account id is empty"))
	}

	authRW := awsauth.NewAwsAuthReaderWriter(cli)
	authData := new(awsauth.AwsAuthData)
	t.bindReadonlyIAMRole2K8sGroup(ctx, cli, authData)
	return deploy.ErrorOrDone(authRW.Update(ctx, authData))
}

func (t *RBAC) bindReadonlyIAMRole2K8sGroup(ctx context.Context, cli client.Client, authData *awsauth.AwsAuthData) {
	// Bind the ClusterRole `cluster-viewer` to k8s Group `readonly-cluster-controller`
	clusterViewerRoleBinding := &rbacv1.ClusterRoleBinding{
		ObjectMeta: metav1.ObjectMeta{
			Name: consts.ReadonlyClusterController,
		},
		Subjects: []rbacv1.Subject{
			{
				Kind:     rbacv1.GroupKind,
				APIGroup: rbacv1.GroupName,
				Name:     consts.ReadonlyClusterController,
			},
		},
		RoleRef: rbacv1.RoleRef{
			APIGroup: rbacv1.GroupName,
			Kind:     "ClusterRole",
			Name:     consts.ClusterRoleViewerName,
		},
	}
	if err := k8s.Apply(ctx, cli, clusterViewerRoleBinding); err != nil {
		deploy.Error(fmt.Errorf("create cluster-viewer clusterRoleBinding: %w", err))
	}

	// bind the readonly assumeed IAM role (in general, it's `readonly-{env}-{region}-cluster-controller-assumed-role`) to k8s Group `readonly-cluster-controller`
	authData.AppendMapRoles(&awsauth.RolesAuthMap{
		RoleARN:  util.GetRoleARN(t.Network.Status.IAM.AccountID, t.Config.FullManage.ReadonlyAssumeRoleName),
		Username: consts.ReadonlyClusterController,
		Groups:   []string{consts.ReadonlyClusterController},
	})
}
