package gke

import (
	"context"
	"fmt"

	corev1 "k8s.io/api/core/v1"
	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
	"k8s.io/apimachinery/pkg/types"

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

const credentialKey = "privateKey"

type Secret struct {
	*task.BaseTask
}

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

func NewSecret(ctx *task.Context) *Secret {
	return &Secret{
		&task.BaseTask{Context: ctx},
	}
}

// Create copy gcp-br-credentials secret from tidb-admin or meta-server (infra API server) to tidb namespace
func (t *Secret) Create(ctx context.Context) deploy.Result {
	if t.IsLegacy() {
		return t.copyFromTiDBAdmin(ctx)
	}

	return t.copyFromMetaServer(ctx)
}

func (t *Secret) copyFromTiDBAdmin(ctx context.Context) deploy.Result {
	secretName := consts.BRGCPSecretName
	secret := &corev1.Secret{}
	namespacedName := types.NamespacedName{
		Namespace: consts.LocalOperatorNamespace,
		Name:      secretName,
	}

	cli := t.EnvProvider.GetClient()

	err := cli.Get(ctx, namespacedName, secret)
	if err != nil {
		return deploy.Error(fmt.Errorf("get secret %s failed, %s", secretName, err.Error()))
	}

	secretCopy := &corev1.Secret{
		ObjectMeta: metav1.ObjectMeta{
			Name:      secretName,
			Namespace: t.Namer.GetTiDBNamespace(),
		},
		Data: secret.Data,
		Type: corev1.SecretTypeOpaque,
	}

	err = k8s.CreateIfNotExist(ctx, cli, secretCopy)
	if err != nil {
		return deploy.Error(err)
	}

	return deploy.Done()
}

func (t *Secret) copyFromMetaServer(ctx context.Context) deploy.Result {
	saKeyName := t.GetGCPNodePoolServiceAccountName() // same as SA name
	saKeySecret := corev1.Secret{}
	err := t.Local.Get(ctx, types.NamespacedName{
		// ref `NewServiceAccountKey` in `sa.go`
		Namespace: t.Cluster.Namespace, Name: saKeyName}, &saKeySecret)
	if err != nil {
		return deploy.Error(err)
	}

	if saKeySecret.Data[credentialKey] == nil {
		return deploy.Error(fmt.Errorf("serviceaccount %s key data empty", saKeyName))
	}

	secret := &corev1.Secret{
		ObjectMeta: metav1.ObjectMeta{
			Name:      consts.BRGCPSecretName,
			Namespace: t.Namer.GetTiDBNamespace(),
		},
		Data: map[string][]byte{
			"credentials": saKeySecret.Data[credentialKey],
		},
		Type: corev1.SecretTypeOpaque,
	}

	cli := t.EnvProvider.GetClient()
	if err := k8s.CreateIfNotExist(ctx, cli, secret); err != nil {
		return deploy.Error(fmt.Errorf("create service account key secret in tidb cluster namespace failed, %s", err.Error()))
	}

	return deploy.Done()
}
