package integration

import (
	"context"
	"reflect"
	"time"

	"github.com/aws/aws-sdk-go-v2/aws"
	"github.com/aws/aws-sdk-go-v2/service/ec2"
	ec2types "github.com/aws/aws-sdk-go-v2/service/ec2/types"
	elbapi "github.com/aws/aws-sdk-go-v2/service/elasticloadbalancingv2"
	elbtypes "github.com/aws/aws-sdk-go-v2/service/elasticloadbalancingv2/types"
	"github.com/aws/aws-sdk-go-v2/service/iam"
	iamtypes "github.com/aws/aws-sdk-go-v2/service/iam/types"
	xpv1 "github.com/crossplane/crossplane-runtime/apis/common/v1"
	s3v1beta1 "github.com/crossplane/provider-aws/apis/s3/v1beta1"
	iamv1alpha1 "github.com/crossplane/provider-gcp/apis/iam/v1alpha1"
	"github.com/golang/mock/gomock"
	. "github.com/onsi/ginkgo/v2"
	. "github.com/onsi/gomega"
	"github.com/pingcap/errors"
	appsv1 "k8s.io/api/apps/v1"
	corev1 "k8s.io/api/core/v1"
	apierrors "k8s.io/apimachinery/pkg/api/errors"
	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
	"k8s.io/apimachinery/pkg/runtime"
	"k8s.io/apimachinery/pkg/types"
	"sigs.k8s.io/controller-runtime/pkg/client"
	"sigs.k8s.io/controller-runtime/pkg/controller/controllerutil"

	providergardener "github.com/tidbcloud/infra-api/controllers/provider/gardener"

	"github.com/tidbcloud/infra-api/pkg/consts"
	awsv1alpha1 "github.com/tidbcloud/infra-api/pkg/gardener/aws/apis/v1alpha1"
	gcpv1alpha1 "github.com/tidbcloud/infra-api/pkg/gardener/gcp/apis/v1alpha1"

	cloudv1 "github.com/tidbcloud/infra-api/api/v1"
	gardenerprovider "github.com/tidbcloud/infra-api/controllers/provider/gardener"
	"github.com/tidbcloud/infra-api/pkg/gardener"
	gardencorev1beta1 "github.com/tidbcloud/infra-api/pkg/gardener/core/apis/v1beta1"
	"github.com/tidbcloud/infra-api/pkg/providers/aws/fake"
)

var _ = Describe("Gardener base Network controller", func() {
	const (
		timeout  = time.Second * 120
		interval = time.Second * 1
	)

	var (
		ctx           context.Context
		testNamespace string

		ns        *corev1.Namespace
		network   *cloudv1.Network
		keySecret *corev1.Secret
	)

	BeforeEach(func() {
		ctx = context.Background()
		testNamespace = cloudv1.RandomString(5)
		ns = &corev1.Namespace{
			ObjectMeta: metav1.ObjectMeta{
				Name: testNamespace,
			},
		}
		network = &cloudv1.Network{
			ObjectMeta: metav1.ObjectMeta{
				Name:      "network-" + cloudv1.RandomString(8),
				Namespace: testNamespace,
				Labels:    make(map[string]string),
			},
			Spec: cloudv1.NetworkSpec{
				Provider: "aws",
				Region:   "us-east-2",
				CIDR:     "10.251.0.0/16",
			},
		}
		network.ObjectMeta.Labels[cloudv1.ProjectLabel] = cloudv1.RandomString(8)
		keySecret = mockSecretForDataflowAgent(network)
	})

	JustBeforeEach(func() {
		Expect(k8sClient.Create(ctx, ns)).To(Succeed())
		Expect(k8sClient.Create(ctx, keySecret)).To(Succeed())
		Expect(k8sClient.Create(ctx, network)).To(Succeed())
	})

	Context("When specify reconciler label", func() {
		containsFinalizerName := func() bool {
			if err := k8sClient.Get(ctx, types.NamespacedName{Namespace: network.Namespace, Name: network.Name}, network); err != nil {
				return false
			}
			return controllerutil.ContainsFinalizer(network, providergardener.NetworkFinalizerName)
		}

		Context("When reconcile label is unknown", func() {
			BeforeEach(func() {
				network.Labels[cloudv1.ReconcilerLabelKey] = "unknown"
			})
			It("Should not add finalizer to network", func() {
				Eventually(containsFinalizerName).ShouldNot(BeTrue())
			})
		})

		Context("When reconcile label is nontrivial", func() {
			BeforeEach(func() {
				network.Labels[cloudv1.ReconcilerLabelKey] = CustomReconciler
			})
			It("Should add finalizer to network", func() {
				Eventually(containsFinalizerName).Should(BeTrue())
			})
		})
	})

	It("Can Create shoot in test api server", func() {
		shoot := &gardencorev1beta1.Shoot{
			Spec: gardencorev1beta1.ShootSpec{
				Provider: gardencorev1beta1.Provider{
					Workers: []gardencorev1beta1.Worker{},
				},
			},
		}
		shoot.Namespace = "default"
		shoot.Name = "test-create-" + cloudv1.RandomString(5)

		Expect(k8sClient.Create(ctx, shoot)).Should(Succeed())
		readShoot := &gardencorev1beta1.Shoot{}
		Eventually(func() bool {
			err := k8sClient.Get(ctx, types.NamespacedName{Namespace: shoot.Namespace, Name: shoot.Name}, readShoot)
			if err != nil {
				return false
			}
			return true

		}, timeout, interval).Should(BeTrue())
		Expect(k8sClient.Delete(ctx, readShoot)).Should(Succeed())
	})

	checkComponentDeployment := func() {
		var err error
		nkey := types.NamespacedName{Namespace: network.Namespace, Name: network.Name}

		provider := new(cloudv1.Provider)
		err = k8sClient.Get(ctx, types.NamespacedName{Name: network.Spec.Provider}, provider)
		Expect(err).Should(Succeed())

		var shootName string
		By("Check should create a shoot")
		Eventually(func() error {
			var err error
			shootName, err = shootReady(ctx, nkey, provider)
			return err
		}, timeout, interval).Should(Succeed())

		By("Check can get shoot context")
		err = CreateShootKubeConfig(k8sClient, gardenerEnv.GetShootNamespace(), shootName, k8sConfig)
		Expect(err).Should(Succeed())

		var shootClient client.Client
		Eventually(func() bool {
			var sctx *gardener.ShootContext
			sctx, err = gardenerEnv.GetShootContext(ctx, shootName)
			if err != nil {
				return false
			}
			shootClient = sctx.Manager.GetClient()
			return true
		}, timeout, interval).Should(BeTrue(), "should get shoot client")
		// just make a list call to make sure the client works
		var podList corev1.PodList
		err = shootClient.List(ctx, &podList)
		Expect(err).Should(Succeed())

		By("Check deploy operator")
		Eventually(func() error {
			return checkExistDeployments(
				shootClient,
				"tidb-admin", // namespace
				"tidb-controller-manager", "advanced-statefulset-controller", "tidb-scheduler")
		}, timeout, interval).Should(Succeed())

		By("Check cert manager")
		Eventually(func() error {
			return checkExistDeployments(
				shootClient,
				"cert-manager", // namespace
				"aws-pca-issuer")
		}, timeout, interval).Should(Succeed())

		By("Check deploy local proxy")
		Eventually(func() error {
			return checkExistDeployments(
				shootClient,
				"tidb-admin", // namespace
				"dbaas-proxy")
		}, timeout, interval).Should(Succeed())

		By("Check deploy dataflow agent")
		Eventually(func() error {
			return checkExistDeployments(
				shootClient,
				"tidb-admin", // namespace
				"dataflow-agent")
		}, timeout, interval).Should(Succeed())

		By("Check deploy SLI reporter")
		Eventually(func() error {
			return checkExistDeployments(
				shootClient,
				"tidb-admin", // namespace
				"dbaas-sli-reporter")
		}, time.Minute, interval).Should(Succeed())

		By("Check deploy graceful shutdown web hook")
		Eventually(func() error {
			return checkExistDeployments(
				shootClient,
				"tidb-admin", // namespace
				"graceful-shutdown-tidb-webhook")
		}, timeout, interval).Should(Succeed())

		By("Check phase in creating")
		network = new(cloudv1.Network)
		err = k8sClient.Get(ctx, nkey, network)
		Expect(err).Should(Succeed())
		Expect(network.Status.Phase).Should(Equal(cloudv1.NetworkPhaseCreating))

		By("Check bucket created")
		var bucketName string
		Eventually(func() error {
			var err error
			bucketName, err = bucketReady(ctx, nkey, provider)
			return err
		}, timeout, interval).Should(Succeed())

		By("Check IAM created")
		Eventually(func() error {
			_, err := iamReady(ctx, nkey, provider)
			return err
		}, timeout, interval).Should(Succeed())

		By("Check phase can become normal from creating")
		Eventually(func() error {
			network = new(cloudv1.Network)
			err = k8sClient.Get(ctx, nkey, network)
			if err != nil {
				return err
			}

			if network.Status.Phase == cloudv1.NetworkPhaseNormal {
				return nil
			}

			return errors.Errorf("network phase still in %q", network.Status.Phase)
		}, timeout, interval).Should(Succeed())

		By("Delete the network")
		err = k8sClient.Delete(ctx, network)
		Expect(err).Should(Succeed())

		By("Check should delete shoot")
		Eventually(func() (found bool, err error) {
			shoot := new(gardencorev1beta1.Shoot)
			key := types.NamespacedName{
				Namespace: gardenerEnv.GetShootNamespace(),
				Name:      shootName,
			}
			err = k8sClient.Get(context.Background(), key, shoot)
			if err != nil {
				if apierrors.IsNotFound(err) {
					return false, nil
				}
				return false, err
			}
			return true, nil
		}, timeout, interval).ShouldNot(BeTrue())

		By("Check should delete bucket")
		Eventually(func() (found bool, err error) {
			b := &s3v1beta1.Bucket{}
			key := types.NamespacedName{Name: bucketName}
			err = k8sClient.Get(context.Background(), key, b)
			if err != nil {
				if apierrors.IsNotFound(err) {
					return false, nil
				}
				return false, err
			}
			return true, nil
		}, timeout, interval).ShouldNot(BeTrue())
	}

	Context("Test deployed components", func() {
		// TODO add a aws type test
		Context("For GCP provider", func() {
			BeforeEach(func() {
				network.Spec.Provider = "gcp"
			})
			It("Should deploy deploy components successfully", checkComponentDeployment)
		})
	})
})

func checkExistDeployments(cli client.Client, ns string, names ...string) error {
	depList := new(appsv1.DeploymentList)

	cli = client.NewNamespacedClient(cli, ns)

	err := cli.List(context.Background(), depList)
	if err != nil {
		return err
	}

	has := make(map[string]struct{})
	for _, dep := range depList.Items {
		has[dep.Name] = struct{}{}
	}

	for _, n := range names {
		_, ok := has[n]
		if !ok {
			return errors.Errorf("do not has deployment %q, but has: %v", n, has)
		}
	}

	return nil
}

// networkNormal make sure the phase of network become normal.
// it will update status of CRD own by outside infra-api controller if need.
// when onlyShoot is true, return succeed once we set up a shoot for the according network and update network status
// as Normal directly.
func networkNormal(ctx context.Context, network *cloudv1.Network, onlyShoot bool) (*cloudv1.GardenerNetworkStatus, error) {
	var (
		gstatus *cloudv1.GardenerNetworkStatus
		err     error
	)
	provider := new(cloudv1.Provider)
	err = k8sClient.Get(ctx, types.NamespacedName{Name: network.Spec.Provider}, provider)
	if err != nil {
		return nil, err
	}

	key := types.NamespacedName{Namespace: network.Namespace, Name: network.Name}

	shootName, err := shootReady(ctx, key, provider)
	if err != nil {
		return nil, err
	}

	err = CreateShootKubeConfig(k8sClient, gardenerEnv.GetShootNamespace(), shootName, k8sConfig)
	if err != nil && !apierrors.IsAlreadyExists(err) {
		return nil, err
	}

	_, err = gardenerEnv.GetShootContext(ctx, shootName)
	if err != nil {
		return nil, err
	}

	_, err = iamReady(ctx, key, provider)
	if err != nil {
		return nil, err
	}

	if onlyShoot {
		network = new(cloudv1.Network)
		err = k8sClient.Get(ctx, key, network)
		if err != nil {
			return nil, err
		}
		network.Status.Phase = cloudv1.NetworkPhaseNormal
		err = k8sClient.Status().Update(ctx, network)
		if err != nil {
			return nil, err
		}

		gstatus, err = cloudv1.GardenerNetworkStatusFromNetwork(network)
		if err != nil {
			return nil, err
		}

		return gstatus, nil
	}

	_, err = bucketReady(ctx, key, provider)
	if err != nil {
		return nil, err
	}

	network = new(cloudv1.Network)
	err = k8sClient.Get(ctx, key, network)
	if err != nil {
		return nil, err
	}

	if network.Status.Phase != cloudv1.NetworkPhaseNormal {
		return nil, errors.Errorf("phase still in %q", network.Status.Phase)
	}

	gstatus, err = cloudv1.GardenerNetworkStatusFromNetwork(network)
	if err != nil {
		return nil, err
	}

	return gstatus, nil
}

func bucketReady(ctx context.Context, key types.NamespacedName, provider *cloudv1.Provider) (bucketName string, err error) {
	network := new(cloudv1.Network)
	err = k8sClient.Get(ctx, key, network)
	if err != nil {
		return "", err
	}

	status, err := cloudv1.GardenerNetworkStatusFromNetwork(network)
	if err != nil {
		return "", err
	}

	if status.BucketName == "" {
		return "", errors.New("bucket name not set in status")
	}

	bucketName = status.BucketName

	// check should get bucket CRD
	_, err = gardenerprovider.GetBucketStatus(ctx, k8sClient, provider.Spec.Type, network.Namespace, status.BucketName)
	if err != nil {
		return "", errors.Annotate(err, "failed to get bucket status")
	}

	// this should be done by crossplane controller
	err = gardenerprovider.MarkBucketReady(ctx, k8sClient, provider.Spec.Type, network.Namespace, bucketName)
	if err != nil {
		return "", errors.Annotate(err, "failed to mark bucket as ready")
	}

	return bucketName, nil
}

func iamReady(ctx context.Context, key types.NamespacedName, provider *cloudv1.Provider) (iam *cloudv1.IAMStatus, err error) {
	var network cloudv1.Network
	err = k8sClient.Get(ctx, key, &network)
	if err != nil {
		return nil, err
	}

	if err := markIAMReady(ctx, k8sClient, provider.Spec.Type, &network); err != nil {
		return nil, err
	}
	var created cloudv1.Network
	err = k8sClient.Get(ctx, key, &created)
	return &created.Status.IAM, err
}

func markIAMReady(ctx context.Context, cli client.Client, providerType string, network *cloudv1.Network) error {
	switch providerType {
	case consts.ProviderTypeAWS:
		return nil
	case consts.ProviderTypeGCP:
		var sa iamv1alpha1.ServiceAccount
		saName := providergardener.GetGCPAccessServiceAccountName(network.Spec.Region, network.GetProjectId())
		err := cli.Get(ctx, types.NamespacedName{
			Namespace: network.Namespace,
			Name:      saName}, &sa)
		if err != nil {
			return errors.AddStack(err)
		}

		sa.SetConditions(xpv1.Condition{
			Type:               xpv1.TypeReady,
			Status:             corev1.ConditionTrue,
			Reason:             xpv1.ReasonAvailable,
			LastTransitionTime: metav1.NewTime(time.Now()),
		})
		sa.Status.AtProvider.Email = providergardener.GetGCPAccessServiceAccountEmail(saName, "integration-test")
		sa.Status.AtProvider.Name = saName
		err = cli.Status().Update(ctx, &sa)
		if err != nil {
			return errors.AddStack(err)
		}
		var key iamv1alpha1.ServiceAccountKey
		keyName := providergardener.GetGCPAccessServiceAccountKeyName(saName)
		err = cli.Get(ctx, types.NamespacedName{
			Namespace: network.Namespace,
			Name:      keyName}, &key)
		if err != nil {
			return errors.AddStack(err)
		}

		key.SetConditions(xpv1.Condition{
			Type:               xpv1.TypeReady,
			Status:             corev1.ConditionTrue,
			Reason:             xpv1.ReasonAvailable,
			LastTransitionTime: metav1.NewTime(time.Now()),
		})
		err = cli.Status().Update(ctx, &key)
		if err != nil {
			return errors.AddStack(err)
		}
		return nil
	default:
		return errors.Errorf("unknown provider type %q", providerType)
	}
}

func shootReady(ctx context.Context, key types.NamespacedName, provider *cloudv1.Provider) (shootName string, err error) {
	getNetwork := new(cloudv1.Network)
	err = k8sClient.Get(
		ctx,
		key,
		getNetwork,
	)
	if err != nil {
		return "", err
	}

	status, err := cloudv1.GardenerNetworkStatusFromNetwork(getNetwork)
	if err != nil {
		return "", err
	}
	if status.ShootName == "" {
		return "", errors.Errorf("no shoot name in status")
	}

	shootName = status.ShootName

	shoot := new(gardencorev1beta1.Shoot)
	shootKey := types.NamespacedName{
		Namespace: gardenerEnv.GetShootNamespace(),
		Name:      shootName,
	}
	err = k8sClient.Get(context.Background(), shootKey, shoot)
	if err != nil {
		return "", errors.Annotate(err, "failed to get shoot")
	}

	// mock shoot ready
	if shoot.Spec.Provider.Type == consts.ProviderTypeAWS {
		infraStatus := &awsv1alpha1.InfrastructureStatus{
			TypeMeta: metav1.TypeMeta{
				Kind:       reflect.TypeOf(awsv1alpha1.InfrastructureStatus{}).Name(),
				APIVersion: awsv1alpha1.SchemeGroupVersion.Version,
			},
			VPC: awsv1alpha1.VPCStatus{
				ID: "test-vpc",
			},
		}
		shoot.Status.InfrastructureProviderStatus = &runtime.RawExtension{
			Object: infraStatus,
		}
	}

	if shoot.Spec.Provider.Type == consts.ProviderTypeGCP {
		shoot.Status.InfrastructureProviderStatus = &runtime.RawExtension{
			Object: &gcpv1alpha1.InfrastructureStatus{
				TypeMeta: metav1.TypeMeta{
					Kind:       reflect.TypeOf(gcpv1alpha1.InfrastructureStatus{}).Name(),
					APIVersion: gcpv1alpha1.SchemeGroupVersion.Version,
				},
				Networks: gcpv1alpha1.NetworkStatus{
					VPC: gcpv1alpha1.VPC{Name: "test-vpc"},
				},
			},
		}
	}
	err = k8sClient.Update(context.Background(), shoot)
	if err != nil {
		return "", errors.Annotate(err, "failed to mock shoot status")
	}
	return shootName, nil
}

// It is useful when there are test failures to set this to zero
const one = 1

// setupExpect capture all created and deleted roles/users.
func setupExpect(awsClient *fake.MockClient) (createdEntity map[string]struct{}, deletedEntity map[string]struct{}) {
	createdEntity = make(map[string]struct{})
	deletedEntity = make(map[string]struct{})
	awsClient.MockIAMClient.EXPECT().CreateRole(gomock.Any(), gomock.AssignableToTypeOf(&iam.CreateRoleInput{})).DoAndReturn(
		func(ctx context.Context, params *iam.CreateRoleInput) (interface{}, interface{}) {
			createdEntity[*params.RoleName] = struct{}{}
			return nil, nil
		},
	).MinTimes(one)
	awsClient.MockIAMClient.EXPECT().CreateUser(gomock.Any(), gomock.AssignableToTypeOf(&iam.CreateUserInput{})).DoAndReturn(
		func(ctx context.Context, params *iam.CreateUserInput) (interface{}, interface{}) {
			createdEntity[*params.UserName] = struct{}{}
			return nil, nil
		},
	).MinTimes(one)

	awsClient.MockIAMClient.EXPECT().PutRolePolicy(gomock.Any(), gomock.Any()).Return(nil, nil).MinTimes(one)

	awsClient.MockIAMClient.EXPECT().DeleteRole(gomock.Any(), gomock.AssignableToTypeOf(&iam.DeleteRoleInput{})).DoAndReturn(
		func(ctx context.Context, params *iam.DeleteRoleInput) (interface{}, interface{}) {
			deletedEntity[*params.RoleName] = struct{}{}
			return nil, nil
		},
	).MinTimes(one)
	awsClient.MockIAMClient.EXPECT().DeleteUser(gomock.Any(), gomock.Any()).Return(nil, nil).DoAndReturn(
		func(ctx context.Context, params *iam.DeleteUserInput) (interface{}, interface{}) {
			deletedEntity[*params.UserName] = struct{}{}
			return nil, nil
		},
	).MinTimes(one)
	awsClient.MockKmsClient.EXPECT().DisableKeyRotation(gomock.Any(), gomock.Any(), gomock.Any()).Return(nil, nil).MinTimes(one)
	awsClient.MockKmsClient.EXPECT().CreateGrant(gomock.Any(), gomock.Any(), gomock.Any()).Return(nil, nil).MinTimes(one)

	// before delete role we will List for getting policies and delete or detach it.
	listOutput := &iam.ListRolePoliciesOutput{}
	awsClient.MockIAMClient.EXPECT().ListRolePolicies(gomock.All(), gomock.All()).Return(listOutput, nil).MinTimes(one)
	listAttachedOutput := &iam.ListAttachedRolePoliciesOutput{}
	awsClient.MockIAMClient.EXPECT().ListAttachedRolePolicies(gomock.All(), gomock.Any()).Return(listAttachedOutput, nil).MinTimes(one)

	awsClient.MockIAMClient.EXPECT().CreateAccessKey(gomock.All(), gomock.All()).Return(&iam.CreateAccessKeyOutput{
		AccessKey: &iamtypes.AccessKey{
			AccessKeyId:     aws.String("ak"),
			SecretAccessKey: aws.String("sk"),
		},
	}, nil).MinTimes(one)
	awsClient.MockIAMClient.EXPECT().ListAccessKeys(gomock.All(), gomock.All()).Return(&iam.ListAccessKeysOutput{
		AccessKeyMetadata: []iamtypes.AccessKeyMetadata{
			{
				AccessKeyId: aws.String("ak"),
			},
		},
	}, nil).MinTimes(one)
	awsClient.MockIAMClient.EXPECT().DeleteAccessKey(gomock.All(), gomock.All()).Return(&iam.DeleteAccessKeyOutput{}, nil).AnyTimes()

	awsClient.MockElbClient.EXPECT().DescribeLoadBalancers(gomock.All(), gomock.All(), gomock.All()).Return(&elbapi.DescribeLoadBalancersOutput{
		LoadBalancers: []elbtypes.LoadBalancer{{}},
	}, nil).MinTimes(one)

	// DescribeSubnets and DescribeRouteTables are used for getting subnet and route table ID.
	// Those IDs are necessary when creating VpcEndpoint CRD via crosssplane.

	// Define the mock behavior for the DescribeSubnets API call.
	awsClient.MockEc2Client.EXPECT().DescribeSubnets(gomock.All(), gomock.All(), gomock.All()).Return(
		&ec2.DescribeSubnetsOutput{
			Subnets: []ec2types.Subnet{
				{
					SubnetId: aws.String("subnet_id"),
					Tags: []ec2types.Tag{
						{
							Key:   aws.String("k"),
							Value: aws.String("v"),
						},
					},
				},
			},
		}, nil).AnyTimes()

	// Define the mock behavior for the DescribeSubnets API call.
	awsClient.MockEc2Client.EXPECT().DescribeRouteTables(gomock.All(), gomock.All(), gomock.All()).Return(
		&ec2.DescribeRouteTablesOutput{
			RouteTables: []ec2types.RouteTable{
				{
					RouteTableId: aws.String("rtb_id"),
					Tags: []ec2types.Tag{
						{
							Key:   aws.String("k"),
							Value: aws.String("v"),
						},
					},
				},
			},
		}, nil).AnyTimes()

	awsClient.MockEc2Client.EXPECT().DescribeVpcEndpointServices(gomock.All(), gomock.All(), gomock.Any()).Return(
		&ec2.DescribeVpcEndpointServicesOutput{
			ServiceDetails: []ec2types.ServiceDetail{
				{
					AvailabilityZones: []string{"az-1"},
				},
			},
		}, nil).AnyTimes()

	/* TODO: don't know why this is not working
	awsClient.MockEc2Client.EXPECT().DeleteVpcEndpoints(gomock.All(), gomock.All()).
		Return(&ec2.DeleteVpcEndpointsOutput{}, nil).MinTimes(one)
	*/

	return createdEntity, deletedEntity
}

func mockSecretForDataflowAgent(network *cloudv1.Network) *corev1.Secret {
	saName := gardenerprovider.GetGCPAccessServiceAccountName(network.Spec.Region, network.GetProjectId())
	keyName := gardenerprovider.GetGCPAccessServiceAccountKeyName(saName)
	secretName := types.NamespacedName{Namespace: network.Namespace, Name: keyName}
	return &corev1.Secret{
		ObjectMeta: metav1.ObjectMeta{
			Name:      secretName.Name,
			Namespace: secretName.Namespace,
		},
		Data: map[string][]byte{
			"privateKey": {byte(1)},
		},
	}
}
