package appbox

import (
	"context"
	"testing"

	"cloud.google.com/go/container/apiv1/containerpb"
	eksv1beta1 "github.com/crossplane-contrib/provider-aws/apis/eks/v1beta1"
	gkev1beta2 "github.com/crossplane-contrib/provider-gcp/apis/container/v1beta2"
	xpmeta "github.com/crossplane/crossplane-runtime/pkg/meta"
	"github.com/stretchr/testify/assert"
	regionalpb "github.com/tidbcloud/infra-provider/api/tidbcloud/regional-server/v1"
	"github.com/tidbcloud/infra-provider/pkg/consts"
	"github.com/tidbcloud/infra-provider/regional-server/api/v1alpha1"
	"github.com/tidbcloud/infra-provider/regional-server/pkg/common/message"
	"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/test/resourcemanager/mockappbox"
	"github.com/tidbcloud/infra-provider/regional-server/test/resourcemanager/mockapproute"
	"github.com/tidbcloud/infra-provider/regional-server/test/resourcemanager/mockvpc"
	"github.com/tidbcloud/infra-provider/regional-server/test/service/mockgcpcontainer"
	aksv1beta1 "github.com/upbound/provider-azure/apis/containerservice/v1beta1"
	"go.uber.org/mock/gomock"
	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/runtime/schema"
	"k8s.io/utils/ptr"
	"sigs.k8s.io/controller-runtime/pkg/client"
	"sigs.k8s.io/controller-runtime/pkg/client/fake"
)

func TestAPPBoxService_CreateAPPBox(t *testing.T) {
	ctl := gomock.NewController(t)
	vpcr := mockvpc.NewMockVPCReader(ctl)
	appboxrw := mockappbox.NewMockAPPBoxReaderWriter(ctl)
	appboxsvc := &APPBoxService{
		cli:      nil,
		vpcr:     vpcr,
		appboxrw: appboxrw,
		config: config.RootConfig{
			ControllerConfig: config.ControllerConfig{
				Provider: consts.ProviderTypeEKS,
				Env:      "test",
				RegionConfig: config.RegionConfig{
					Name: "us-west-1",
				},
			},
		},
		tmplconfig: config.TemplatesConfig{},
	}
	t.Run("vpc not found", func(t *testing.T) {
		req := &message.CreateAPPBoxReq{
			VPCID: "vpc-123",
		}
		vpcr.EXPECT().List(gomock.Any(), gomock.Any(), gomock.Any()).Return(nil)
		_, err := appboxsvc.CreateAPPBox(context.TODO(), req)
		assert.ErrorContains(t, err, "vpc not found")
	})
	t.Run("multiple vpc found", func(t *testing.T) {
		req := &message.CreateAPPBoxReq{
			VPCID: "vpc-123",
		}
		vpcr.EXPECT().List(gomock.Any(), &v1alpha1.VPCList{}, gomock.Any()).DoAndReturn(
			func(ctx context.Context, vpcList *v1alpha1.VPCList, opts ...client.ListOption) error {
				vpcList.Items = []v1alpha1.VPC{
					{
						ObjectMeta: metav1.ObjectMeta{
							Name: "vpc-123",
						},
					},
					{
						ObjectMeta: metav1.ObjectMeta{
							Name: "vpc-456",
						},
					},
				}
				return nil
			},
		)
		_, err := appboxsvc.CreateAPPBox(context.TODO(), req)
		assert.ErrorContains(t, err, "multiple vpc found")
	})
	t.Run("create appbox success", func(t *testing.T) {
		vpcr.EXPECT().List(gomock.Any(), &v1alpha1.VPCList{}, gomock.Any()).DoAndReturn(
			func(ctx context.Context, vpcList *v1alpha1.VPCList, opts ...client.ListOption) error {
				vpcList.Items = []v1alpha1.VPC{
					{
						ObjectMeta: metav1.ObjectMeta{
							Name: "vpc-123",
						},
					},
				}
				return nil
			},
		)
		appboxrw.EXPECT().Create(gomock.Any(), gomock.Any()).Return(nil)
		req := &message.CreateAPPBoxReq{
			VPCID:     "vpc-123",
			Name:      "appbox-123",
			Namespace: "default",
			TenantID:  "tenant-123",
			ProjectID: "project-123",
		}
		_, err := appboxsvc.CreateAPPBox(context.TODO(), req)
		assert.NoError(t, err)
	})
}

func TestAPPBoxService_DeleteAPPBox(t *testing.T) {
	ctl := gomock.NewController(t)
	vpcr := mockvpc.NewMockVPCReader(ctl)
	appboxrw := mockappbox.NewMockAPPBoxReaderWriter(ctl)
	appboxsvc := &APPBoxService{
		cli:      nil,
		vpcr:     vpcr,
		appboxrw: appboxrw,
		config: config.RootConfig{
			ControllerConfig: config.ControllerConfig{
				Provider: consts.ProviderTypeEKS,
				Env:      "test",
				RegionConfig: config.RegionConfig{
					Name: "us-west-1",
				},
			},
		},
		tmplconfig: config.TemplatesConfig{},
	}
	t.Run("appbox not found", func(t *testing.T) {
		appboxrw.EXPECT().Delete(context.TODO(), &v1alpha1.APPBox{
			ObjectMeta: metav1.ObjectMeta{
				Name:      "appbox-123",
				Namespace: "dedicated-test-us-west-1",
			},
		}).Return(apierrors.NewNotFound(schema.GroupResource{}, "")).Times(1)
		err := appboxsvc.DeleteAPPBox(context.TODO(), &regionalpb.DeleteAPPBoxRequest{
			Name: "appbox-123",
		})
		assert.ErrorContains(t, err, "appbox not found")
	})
	t.Run("delete appbox success", func(t *testing.T) {
		appboxrw.EXPECT().Delete(context.TODO(), &v1alpha1.APPBox{
			ObjectMeta: metav1.ObjectMeta{
				Name:      "appbox-123",
				Namespace: "dedicated-test-us-west-1",
			},
		}).Return(nil).Times(1)
		err := appboxsvc.DeleteAPPBox(context.TODO(), &regionalpb.DeleteAPPBoxRequest{
			Name: "appbox-123",
		})
		assert.NoError(t, err)
	})
}

func TestAPPBoxService_GetAPPBox(t *testing.T) {
	s := runtime.NewScheme()
	eksv1beta1.SchemeBuilder.AddToScheme(s)
	mockcli := fake.NewClientBuilder().WithScheme(s).Build()
	ctl := gomock.NewController(t)
	vpcr := mockvpc.NewMockVPCReader(ctl)
	appboxrw := mockappbox.NewMockAPPBoxReaderWriter(ctl)
	appboxsvc := &APPBoxService{
		cli:      mockcli,
		vpcr:     vpcr,
		appboxrw: appboxrw,
		config: config.RootConfig{
			ControllerConfig: config.ControllerConfig{
				Provider: consts.ProviderTypeEKS,
				Env:      "test",
				RegionConfig: config.RegionConfig{
					Name: "us-west-1",
				},
			},
		},
		tmplconfig: config.TemplatesConfig{},
	}
	t.Run("appbox not found", func(t *testing.T) {
		appboxrw.EXPECT().Get(context.TODO(), client.ObjectKey{
			Namespace: "dedicated-test-us-west-1",
			Name:      "appbox-123",
		}, gomock.Any()).Return(apierrors.NewNotFound(schema.GroupResource{}, "")).Times(1)
		_, err := appboxsvc.GetAPPBox(context.TODO(), &regionalpb.GetAPPBoxRequest{
			Name: "appbox-123",
		})
		assert.ErrorContains(t, err, "appbox not found")
	})
	t.Run("get appbox success", func(t *testing.T) {
		appboxrw.EXPECT().Get(context.TODO(), client.ObjectKey{
			Namespace: "dedicated-test-us-west-1",
			Name:      "appbox-123",
		}, gomock.Any()).DoAndReturn(
			func(ctx context.Context, key client.ObjectKey, appbox *v1alpha1.APPBox) error {
				appbox.ObjectMeta.Name = key.Name
				appbox.ObjectMeta.Namespace = key.Namespace
				appbox.Spec.Provider = consts.ProviderTypeEKS
				appbox.Spec.VPCRef = &v1alpha1.Reference{
					Name:      "vpc-123",
					Namespace: "dedicated-test-us-west-1",
				}
				appbox.Status.KubernetesClusterName = "kubernetes-123"
				return nil
			},
		).Times(1)
		vpcr.EXPECT().Get(context.TODO(), client.ObjectKey{
			Namespace: "dedicated-test-us-west-1",
			Name:      "vpc-123",
		}, gomock.Any()).DoAndReturn(
			func(ctx context.Context, key client.ObjectKey, vpc *v1alpha1.VPC) error {
				vpc.ObjectMeta.Name = key.Name
				vpc.ObjectMeta.Namespace = key.Namespace
				vpc.Spec.AccountRef = &v1alpha1.AccountReference{
					AccountID: "account-123",
				}
				return nil
			},
		).Times(1)

		mockcli.Create(context.TODO(), &eksv1beta1.Cluster{
			ObjectMeta: metav1.ObjectMeta{
				Name: "kubernetes-123",
			},
			Status: eksv1beta1.ClusterStatus{
				AtProvider: eksv1beta1.ClusterObservation{
					Endpoint:                 "https://kubernetes-123.us-west-1.eks.amazonaws.com",
					CertificateAuthorityData: "Y2EtZGF0YQ==",
					ResourcesVpcConfig: eksv1beta1.VpcConfigResponse{
						ClusterSecurityGroupID: "sg-123",
					},
				},
			},
		})
		appbox, err := appboxsvc.GetAPPBox(context.TODO(), &regionalpb.GetAPPBoxRequest{
			Name: "appbox-123",
		})
		assert.NoError(t, err)
		assert.Equal(t, "appbox-123", appbox.GetName())
	})
}

func TestMeetAPPBoxStatus(t *testing.T) {
	testData := []struct {
		name     string
		phase    v1alpha1.APPBoxPhase
		statuses []regionalpb.APPBox_Status
		expect   bool
	}{
		{
			name:  "meet status",
			phase: v1alpha1.APPBoxPhaseActive,
			statuses: []regionalpb.APPBox_Status{
				regionalpb.APPBox_ACTIVE,
			},
			expect: true,
		},
		{
			name:  "appbox creating",
			phase: v1alpha1.APPBoxPhaseCreating,
			statuses: []regionalpb.APPBox_Status{
				regionalpb.APPBox_ACTIVE,
			},
			expect: false,
		},
		{
			name:  "appbox deleting",
			phase: v1alpha1.APPBoxPhaseDeleting,
			statuses: []regionalpb.APPBox_Status{
				regionalpb.APPBox_ACTIVE,
			},
			expect: false,
		},
		{
			name:  "appbox failed",
			phase: v1alpha1.APPBoxPhaseFailed,
			statuses: []regionalpb.APPBox_Status{
				regionalpb.APPBox_ACTIVE,
			},
			expect: false,
		},
		{
			name:  "appbox creating",
			phase: v1alpha1.APPBoxPhasePending,
			statuses: []regionalpb.APPBox_Status{
				regionalpb.APPBox_ACTIVE,
			},
			expect: false,
		},
		{
			name:  "appbox exmpty",
			phase: "",
			statuses: []regionalpb.APPBox_Status{
				regionalpb.APPBox_ACTIVE,
			},
			expect: false,
		},
		{
			name:  "appbox readyfordelete",
			phase: v1alpha1.APPBoxPhaseReadyForDelete,
			statuses: []regionalpb.APPBox_Status{
				regionalpb.APPBox_ACTIVE,
			},
			expect: false,
		},
	}

	for _, data := range testData {
		t.Run(data.name, func(t *testing.T) {
			assert.Equal(t, data.expect, meetAPPBoxStatus(data.phase, data.statuses))
		})
	}
}

func TestListAPPBoxes(t *testing.T) {
	t.Run("set cluster id, appbox not found", func(t *testing.T) {
		ctrl := gomock.NewController(t)
		appboxrw := mockappbox.NewMockAPPBoxReaderWriter(ctrl)
		approuter := mockapproute.NewMockAPPRouteReader(ctrl)
		appboxsvc := &APPBoxService{
			cli:       nil,
			appboxrw:  appboxrw,
			approuter: approuter,
			config: config.RootConfig{
				ControllerConfig: config.ControllerConfig{
					Provider: consts.ProviderTypeEKS,
					Env:      "test",
					RegionConfig: config.RegionConfig{
						Name: "us-west-1",
					},
				},
			},
			tmplconfig: config.TemplatesConfig{},
		}
		req := &regionalpb.ListAPPBoxesRequest{
			TenantId:  "tenant-123",
			ProjectId: "project-123",
			ClusterId: "cluster-123",
		}
		approuteList := &v1alpha1.APPRouteList{}
		approuter.EXPECT().List(context.Background(), approuteList, client.MatchingLabels{
			utils.GenTenantLabelKey(req.TenantId):   "true",
			utils.GenClusterLabelKey(req.ClusterId): "true",
			utils.GenProjectLabelKey(req.ProjectId): "true",
		}).Return(nil)
		resp, err := appboxsvc.ListAPPBoxes(context.Background(), req)
		assert.Nil(t, err)
		assert.Equal(t, 0, len(resp.Appboxes))
	})
	t.Run("not set cluster id, appbox not found", func(t *testing.T) {
		ctrl := gomock.NewController(t)
		appboxrw := mockappbox.NewMockAPPBoxReaderWriter(ctrl)
		approuter := mockapproute.NewMockAPPRouteReader(ctrl)
		appboxsvc := &APPBoxService{
			cli:       nil,
			appboxrw:  appboxrw,
			approuter: approuter,
			config: config.RootConfig{
				ControllerConfig: config.ControllerConfig{
					Provider: consts.ProviderTypeEKS,
					Env:      "test",
					RegionConfig: config.RegionConfig{
						Name: "us-west-1",
					},
				},
			},
			tmplconfig: config.TemplatesConfig{},
		}
		req := &regionalpb.ListAPPBoxesRequest{
			TenantId:  "tenant-123",
			ProjectId: "project-123",
		}
		appboxList := &v1alpha1.APPBoxList{}
		appboxrw.EXPECT().List(context.Background(), appboxList, client.MatchingLabels{
			utils.GenTenantLabelKey(req.TenantId):   "true",
			utils.GenProjectLabelKey(req.ProjectId): "true",
		}).Return(nil)
		resp, err := appboxsvc.ListAPPBoxes(context.Background(), req)
		assert.Nil(t, err)
		assert.Equal(t, 0, len(resp.Appboxes))
	})
	t.Run("get appbox by cluster id", func(t *testing.T) {
		ctrl := gomock.NewController(t)
		vpcr := mockvpc.NewMockVPCReader(ctrl)
		appboxrw := mockappbox.NewMockAPPBoxReaderWriter(ctrl)
		approuter := mockapproute.NewMockAPPRouteReader(ctrl)
		appboxsvc := &APPBoxService{
			cli:       nil,
			vpcr:      vpcr,
			appboxrw:  appboxrw,
			approuter: approuter,
			config: config.RootConfig{
				ControllerConfig: config.ControllerConfig{
					Provider: consts.ProviderTypeEKS,
					Env:      "test",
					RegionConfig: config.RegionConfig{
						Name: "us-west-1",
					},
				},
			},
			tmplconfig: config.TemplatesConfig{},
		}
		req := &regionalpb.ListAPPBoxesRequest{
			TenantId:  "tenant-123",
			ProjectId: "project-123",
			ClusterId: "cluster-123",
		}
		approuteList := &v1alpha1.APPRouteList{}
		approuter.EXPECT().List(context.Background(), approuteList, client.MatchingLabels{
			utils.GenTenantLabelKey(req.TenantId):   "true",
			utils.GenClusterLabelKey(req.ClusterId): "true",
			utils.GenProjectLabelKey(req.ProjectId): "true",
		}).DoAndReturn(func(ctx context.Context, list *v1alpha1.APPRouteList, opts ...client.ListOption) error {
			list.Items = []v1alpha1.APPRoute{
				{
					ObjectMeta: metav1.ObjectMeta{
						Name:      req.ClusterId,
						Namespace: "default",
						Annotations: map[string]string{
							utils.GenTenantLabelKey(req.TenantId):   "true",
							utils.GenClusterLabelKey(req.ClusterId): "true",
							utils.GenProjectLabelKey(req.ProjectId): "true",
						},
					},
					Spec: v1alpha1.APPRouteSpec{
						APPBoxRef: &v1alpha1.Reference{
							Name:      "appbox-123",
							Namespace: "default",
						},
					},
				},
			}
			return nil
		}).Times(4)
		t.Run("get eks kubernetes", func(t *testing.T) {
			appboxrw.EXPECT().Get(context.Background(), client.ObjectKey{
				Namespace: "default",
				Name:      "appbox-123",
			}, &v1alpha1.APPBox{}).DoAndReturn(
				func(ctx context.Context, key client.ObjectKey, appbox *v1alpha1.APPBox) error {
					appbox.ObjectMeta.Name = key.Name
					appbox.ObjectMeta.Namespace = key.Namespace
					appbox.Status.Phase = v1alpha1.APPBoxPhaseActive
					appbox.Labels = map[string]string{
						utils.GenTenantLabelKey(req.TenantId):   "true",
						utils.GenClusterLabelKey(req.ClusterId): "true",
						utils.GenProjectLabelKey(req.ProjectId): "true",
						v1alpha1.TagProjectKey:                  req.ProjectId,
					}
					appbox.Status.DataflowAgentUrl = "http://dataflow-agent"
					appbox.Status.ProxyBaseUrl = "http://proxy-base"
					appbox.Spec.VPCRef = &v1alpha1.Reference{
						Name:      "vpc-123",
						Namespace: "default",
					}
					appbox.Status.KubernetesClusterName = "kubernetes-123"
					appbox.Spec.Provider = consts.ProviderTypeEKS
					appbox.Spec.KubernetesConfig.Version = "1.30"
					appbox.Status.IAM.NodeRoleARN = "arn:aws:iam::123:role/node"
					return nil
				},
			).Times(1)
			appboxsvc.config.Provider = consts.ProviderTypeEKS
			vpcr.EXPECT().Get(context.Background(), client.ObjectKey{
				Namespace: "default",
				Name:      "vpc-123",
			}, &v1alpha1.VPC{}).DoAndReturn(
				func(ctx context.Context, key client.ObjectKey, vpc *v1alpha1.VPC) error {
					vpc.ObjectMeta.Name = key.Name
					vpc.ObjectMeta.Namespace = key.Namespace
					vpc.Status.Phase = v1alpha1.VPCPhaseActive
					vpc.Labels = map[string]string{
						utils.GenTenantLabelKey(req.TenantId):   "true",
						utils.GenProjectLabelKey(req.ProjectId): "true",
					}
					vpc.Status.VPC.VPCID = "vpc-id-123"
					vpc.Spec.AccountRef = &v1alpha1.AccountReference{
						AccountID: "account-123",
					}
					vpc.Status.NodeSubnets = []v1alpha1.Subnet{
						{
							SubnetID:           "subnet-123",
							AvailabilityZone:   "us-west-a",
							AvailabilityZoneID: "us-west-1a",
						},
						{
							SubnetID:           "subnet-456",
							AvailabilityZone:   "us-west-b",
							AvailabilityZoneID: "us-west-1b",
						},
						{
							SubnetID:           "subnet-789",
							AvailabilityZone:   "us-west-c",
							AvailabilityZoneID: "us-west-1c",
						},
					}
					vpc.Status.PrivateSubnets = []v1alpha1.Subnet{
						{
							SubnetID:           "subnet-123-private",
							AvailabilityZone:   "us-west-a",
							AvailabilityZoneID: "us-west-1a",
						},
						{
							SubnetID:           "subnet-456-private",
							AvailabilityZone:   "us-west-b",
							AvailabilityZoneID: "us-west-1b",
						},
						{
							SubnetID:           "subnet-789-private",
							AvailabilityZone:   "us-west-c",
							AvailabilityZoneID: "us-west-1c",
						},
					}
					vpc.Status.PublicSubnets = []v1alpha1.Subnet{
						{
							SubnetID:           "subnet-123-public",
							AvailabilityZone:   "us-west-a",
							AvailabilityZoneID: "us-west-1a",
						},
						{
							SubnetID:           "subnet-456-public",
							AvailabilityZone:   "us-west-b",
							AvailabilityZoneID: "us-west-1b",
						},
						{
							SubnetID:           "subnet-789-public",
							AvailabilityZone:   "us-west-c",
							AvailabilityZoneID: "us-west-1c",
						},
					}
					vpc.Status.SecondaryNodeSubnets = []v1alpha1.Subnet{
						{
							SubnetID:           "subnet-123-secondary",
							AvailabilityZone:   "us-west-a",
							AvailabilityZoneID: "us-west-1a",
						},
					}
					return nil
				},
			).Times(1)
			s := runtime.NewScheme()
			eksv1beta1.SchemeBuilder.AddToScheme(s)
			mockcli := fake.NewClientBuilder().WithScheme(s).Build()
			appboxsvc.cli = mockcli
			mockcli.Create(context.Background(), &eksv1beta1.Cluster{
				ObjectMeta: metav1.ObjectMeta{
					Name: "kubernetes-123",
				},
				Status: eksv1beta1.ClusterStatus{
					AtProvider: eksv1beta1.ClusterObservation{
						Endpoint:                 "https://kubernetes-123.us-west-1.eks.amazonaws.com",
						CertificateAuthorityData: "Y2EtZGF0YQ==",
						ResourcesVpcConfig: eksv1beta1.VpcConfigResponse{
							ClusterSecurityGroupID: "sg-123",
						},
					},
				},
			})
			resp, err := appboxsvc.ListAPPBoxes(context.Background(), req)
			assert.Nil(t, err)
			assert.Equal(t, 1, len(resp.Appboxes))
			assert.Equal(t, &regionalpb.APPBox{
				TenantIds:        []string{"tenant-123"},
				ProjectIds:       []string{"project-123"},
				Status:           regionalpb.APPBox_ACTIVE,
				DataflowAgentUrl: "http://dataflow-agent",
				ProxyBaseUrl:     "http://proxy-base",
				Name:             "appbox-123",
				Kubernetes: &regionalpb.APPBox_Kubernetes{
					Name:       "kubernetes-123",
					Version:    "1.30",
					Endpoint:   "https://kubernetes-123.us-west-1.eks.amazonaws.com",
					Ca:         "ca-data",
					AccountId:  "account-123",
					ExternalId: "project-123",
					Vpc:        "vpc-id-123",
					Info: &regionalpb.APPBox_Kubernetes_Aws_{
						Aws: &regionalpb.APPBox_Kubernetes_Aws{
							SecurityGroup: "sg-123",
							NodeSubnets: []*regionalpb.APPBox_Kubernetes_AwsSubnet{
								{
									Id:     "subnet-123",
									AzId:   "us-west-1a",
									AzName: "us-west-a",
								},
								{
									Id:     "subnet-456",
									AzId:   "us-west-1b",
									AzName: "us-west-b",
								},
								{
									Id:     "subnet-789",
									AzId:   "us-west-1c",
									AzName: "us-west-c",
								},
							},
							PublicLoadbalancerSubnets: []*regionalpb.APPBox_Kubernetes_AwsSubnet{
								{
									Id:     "subnet-123-public",
									AzId:   "us-west-1a",
									AzName: "us-west-a",
								},
								{
									Id:     "subnet-456-public",
									AzId:   "us-west-1b",
									AzName: "us-west-b",
								},
								{
									Id:     "subnet-789-public",
									AzId:   "us-west-1c",
									AzName: "us-west-c",
								},
							},
							PrivateLoadbalancerSubnets: []*regionalpb.APPBox_Kubernetes_AwsSubnet{
								{
									Id:     "subnet-123-private",
									AzId:   "us-west-1a",
									AzName: "us-west-a",
								},
								{
									Id:     "subnet-456-private",
									AzId:   "us-west-1b",
									AzName: "us-west-b",
								},
								{
									Id:     "subnet-789-private",
									AzId:   "us-west-1c",
									AzName: "us-west-c",
								},
							},
							SecondaryNodeSubnets: []*regionalpb.APPBox_Kubernetes_AwsSubnet{
								{
									Id:     "subnet-123-secondary",
									AzId:   "us-west-1a",
									AzName: "us-west-a",
								},
							},
							AdminNodeRole: "arn:aws:iam::123:role/node",
						},
					},
				},
			}, resp.Appboxes[0])
		})
		t.Run("get gke kubernetes", func(t *testing.T) {
			appboxrw.EXPECT().Get(context.Background(), client.ObjectKey{
				Namespace: "default",
				Name:      "appbox-123",
			}, &v1alpha1.APPBox{}).DoAndReturn(
				func(ctx context.Context, key client.ObjectKey, appbox *v1alpha1.APPBox) error {
					appbox.ObjectMeta.Name = key.Name
					appbox.ObjectMeta.Namespace = key.Namespace
					appbox.Status.Phase = v1alpha1.APPBoxPhaseActive
					appbox.Labels = map[string]string{
						utils.GenTenantLabelKey(req.TenantId):   "true",
						utils.GenClusterLabelKey(req.ClusterId): "true",
						utils.GenProjectLabelKey(req.ProjectId): "true",
					}
					appbox.Status.DataflowAgentUrl = "http://dataflow-agent"
					appbox.Status.ProxyBaseUrl = "http://proxy-base"
					appbox.Spec.VPCRef = &v1alpha1.Reference{
						Name:      "vpc-123",
						Namespace: "default",
					}
					appbox.Status.KubernetesClusterName = "kubernetes-123"
					appbox.Spec.Provider = consts.ProviderTypeGKE
					appbox.Spec.KubernetesConfig.Version = "1.30"
					appbox.Status.IAM.ServiceAccountEmail = "service@account"
					return nil
				},
			).Times(1)
			appboxsvc.config.Provider = consts.ProviderTypeGKE
			vpcr.EXPECT().Get(context.Background(), client.ObjectKey{
				Namespace: "default",
				Name:      "vpc-123",
			}, &v1alpha1.VPC{}).DoAndReturn(
				func(ctx context.Context, key client.ObjectKey, vpc *v1alpha1.VPC) error {
					vpc.ObjectMeta.Name = key.Name
					vpc.ObjectMeta.Namespace = key.Namespace
					vpc.Status.Phase = v1alpha1.VPCPhaseActive
					vpc.Status.NodeSubnets = []v1alpha1.Subnet{{SubnetID: "subnet-123"}}
					vpc.Labels = map[string]string{
						utils.GenTenantLabelKey(req.TenantId):   "true",
						utils.GenProjectLabelKey(req.ProjectId): "true",
					}
					vpc.Status.VPC.VPCID = "vpc-id-123"
					vpc.Spec.AccountRef = &v1alpha1.AccountReference{
						AccountID: "account-123",
					}
					return nil
				},
			).Times(1)
			s := runtime.NewScheme()
			gkev1beta2.SchemeBuilder.AddToScheme(s)
			mockcli := fake.NewClientBuilder().WithScheme(s).Build()
			appboxsvc.cli = mockcli
			mockcli.Create(context.Background(), &gkev1beta2.Cluster{
				ObjectMeta: metav1.ObjectMeta{
					Name: "kubernetes-123",
					Annotations: map[string]string{
						xpmeta.AnnotationKeyExternalName: "kubernetes-123",
					},
				},
				Spec: gkev1beta2.ClusterSpec{
					ForProvider: gkev1beta2.ClusterParameters{
						Locations: []string{"us-west1a", "us-west1b", "us-west1c"},
					},
				},
				Status: gkev1beta2.ClusterStatus{
					AtProvider: gkev1beta2.ClusterObservation{
						Endpoint: "123.4.5.6",
						Location: "us-west1",
					},
				},
			})
			gcpContainerCli := mockgcpcontainer.NewMockClusterGetter(ctrl)
			gcpContainerCli.EXPECT().GetCluster(context.Background(), &containerpb.GetClusterRequest{
				Name: "projects/account-123/locations/us-west1/clusters/kubernetes-123",
			}).Return(&containerpb.Cluster{
				MasterAuth: &containerpb.MasterAuth{
					ClusterCaCertificate: "Y2EtZGF0YQ==",
				},
			}, nil)
			appboxsvc.WithGKEClient(gcpContainerCli)
			resp, err := appboxsvc.ListAPPBoxes(context.Background(), req)
			assert.Nil(t, err)
			assert.Equal(t, 1, len(resp.Appboxes))
			assert.Equal(t, &regionalpb.APPBox{
				TenantIds:        []string{"tenant-123"},
				ProjectIds:       []string{"project-123"},
				Status:           regionalpb.APPBox_ACTIVE,
				DataflowAgentUrl: "http://dataflow-agent",
				ProxyBaseUrl:     "http://proxy-base",
				Name:             "appbox-123",
				Kubernetes: &regionalpb.APPBox_Kubernetes{
					Name:      "kubernetes-123",
					Version:   "1.30",
					Endpoint:  "https://123.4.5.6",
					Ca:        "ca-data",
					AccountId: "account-123",
					Vpc:       "vpc-id-123",
					Info: &regionalpb.APPBox_Kubernetes_Gcp_{
						Gcp: &regionalpb.APPBox_Kubernetes_Gcp{
							NodeZones:   []string{"us-west1a", "us-west1b", "us-west1c"},
							AdminNodeSa: "service@account",
							NodeSubnets: []*regionalpb.APPBox_Kubernetes_GcpSubnet{{Id: "subnet-123"}},
						},
					},
				},
			}, resp.Appboxes[0])
		})
		t.Run("get aks kubernetes", func(t *testing.T) {
			appboxrw.EXPECT().Get(context.Background(), client.ObjectKey{
				Namespace: "default",
				Name:      "appbox-123",
			}, &v1alpha1.APPBox{}).DoAndReturn(
				func(ctx context.Context, key client.ObjectKey, appbox *v1alpha1.APPBox) error {
					appbox.ObjectMeta.Name = key.Name
					appbox.ObjectMeta.Namespace = key.Namespace
					appbox.Status.Phase = v1alpha1.APPBoxPhaseActive
					appbox.Labels = map[string]string{
						utils.GenTenantLabelKey(req.TenantId):   "true",
						utils.GenClusterLabelKey(req.ClusterId): "true",
						utils.GenProjectLabelKey(req.ProjectId): "true",
					}
					appbox.Status.DataflowAgentUrl = "http://dataflow-agent"
					appbox.Status.ProxyBaseUrl = "http://proxy-base"
					appbox.Spec.VPCRef = &v1alpha1.Reference{
						Name:      "vpc-123",
						Namespace: "default",
					}
					appbox.Status.KubernetesClusterName = "kubernetes-123"
					appbox.Spec.Provider = consts.ProviderTypeAKS
					appbox.Spec.KubernetesConfig.Version = "1.30"
					appbox.Status.KubeConfigSecretRef = &corev1.SecretReference{
						Name:      "kubeconfig-123",
						Namespace: "default",
					}
					return nil
				},
			).Times(1)
			appboxsvc.config.Provider = consts.ProviderTypeAKS
			appboxsvc.config.RegionConfig.Zones = []string{"us-west-1a", "us-west-1b", "us-west-1c"}
			vpcr.EXPECT().Get(context.Background(), client.ObjectKey{
				Namespace: "default",
				Name:      "vpc-123",
			}, &v1alpha1.VPC{}).DoAndReturn(
				func(ctx context.Context, key client.ObjectKey, vpc *v1alpha1.VPC) error {
					vpc.ObjectMeta.Name = key.Name
					vpc.ObjectMeta.Namespace = key.Namespace
					vpc.Status.Phase = v1alpha1.VPCPhaseActive
					vpc.Labels = map[string]string{
						utils.GenTenantLabelKey(req.TenantId):   "true",
						utils.GenProjectLabelKey(req.ProjectId): "true",
					}
					vpc.Status.VPC.VPCID = "vpc-id-123"
					vpc.Spec.AccountRef = &v1alpha1.AccountReference{AccountID: "account-123"}
					vpc.Status.NodeSubnets = []v1alpha1.Subnet{{SubnetID: "subnet-123-node"}}
					vpc.Status.PodSubnets = []v1alpha1.Subnet{{SubnetID: "subnet-456-pod"}}
					return nil
				},
			).Times(1)
			s := runtime.NewScheme()
			corev1.AddToScheme(s)
			aksv1beta1.SchemeBuilder.AddToScheme(s)
			mockcli := fake.NewClientBuilder().WithScheme(s).Build()
			appboxsvc.cli = mockcli
			mockcli.Create(context.Background(), &aksv1beta1.KubernetesCluster{
				ObjectMeta: metav1.ObjectMeta{
					Name: "kubernetes-123",
				},
				Spec: aksv1beta1.KubernetesClusterSpec{
					ForProvider: aksv1beta1.KubernetesClusterParameters{
						ResourceGroupName: ptr.To("rg-123"),
					},
				},
				Status: aksv1beta1.KubernetesClusterStatus{
					AtProvider: aksv1beta1.KubernetesClusterObservation{
						Fqdn: ptr.To("kubernetes-123.us-west-1.aks.azure.com"),
					},
				},
			})
			mockcli.Create(context.Background(), &corev1.Secret{
				ObjectMeta: metav1.ObjectMeta{
					Name:      "kubeconfig-123",
					Namespace: "default",
				},
				Data: map[string][]byte{
					"kubeconfig": []byte("ca-data"),
				},
			})
			resp, err := appboxsvc.ListAPPBoxes(context.Background(), req)
			assert.Nil(t, err)
			assert.Equal(t, 1, len(resp.Appboxes))
			assert.Equal(t, &regionalpb.APPBox{
				TenantIds:        []string{"tenant-123"},
				ProjectIds:       []string{"project-123"},
				Status:           regionalpb.APPBox_ACTIVE,
				DataflowAgentUrl: "http://dataflow-agent",
				ProxyBaseUrl:     "http://proxy-base",
				Name:             "appbox-123",
				Kubernetes: &regionalpb.APPBox_Kubernetes{
					Name:       "kubernetes-123",
					Version:    "1.30",
					Endpoint:   "https://kubernetes-123.us-west-1.aks.azure.com",
					AccountId:  "account-123",
					Vpc:        "vpc-id-123",
					Kubeconfig: "Y2EtZGF0YQ==",
					Info: &regionalpb.APPBox_Kubernetes_Azure_{
						Azure: &regionalpb.APPBox_Kubernetes_Azure{
							NodeZones:     []string{"us-west-1a", "us-west-1b", "us-west-1c"},
							ResourceGroup: "rg-123",
							NodeSubnets:   []*regionalpb.APPBox_Kubernetes_AzureSubnet{{Id: "subnet-123-node"}},
							PodSubnets:    []*regionalpb.APPBox_Kubernetes_AzureSubnet{{Id: "subnet-456-pod"}},
						},
					},
				},
			}, resp.Appboxes[0])
		})
		t.Run("faled to get gke kubernetes", func(t *testing.T) {
			appboxrw.EXPECT().Get(context.Background(), client.ObjectKey{
				Namespace: "default",
				Name:      "appbox-123",
			}, &v1alpha1.APPBox{}).DoAndReturn(
				func(ctx context.Context, key client.ObjectKey, appbox *v1alpha1.APPBox) error {
					appbox.ObjectMeta.Name = key.Name
					appbox.ObjectMeta.Namespace = key.Namespace
					appbox.Status.Phase = v1alpha1.APPBoxPhaseActive
					appbox.Labels = map[string]string{
						utils.GenTenantLabelKey(req.TenantId):   "true",
						utils.GenClusterLabelKey(req.ClusterId): "true",
						utils.GenProjectLabelKey(req.ProjectId): "true",
					}
					appbox.Status.DataflowAgentUrl = "http://dataflow-agent"
					appbox.Status.ProxyBaseUrl = "http://proxy-base"
					appbox.Spec.VPCRef = &v1alpha1.Reference{
						Name:      "vpc-123",
						Namespace: "default",
					}
					appbox.Status.KubernetesClusterName = "kubernetes-123"
					appbox.Spec.Provider = consts.ProviderTypeGKE
					appbox.Spec.KubernetesConfig.Version = "1.30"
					appbox.Status.IAM.ServiceAccountEmail = "service@account"
					return nil
				},
			).Times(1)
			appboxsvc.config.Provider = consts.ProviderTypeGKE
			vpcr.EXPECT().Get(context.Background(), client.ObjectKey{
				Namespace: "default",
				Name:      "vpc-123",
			}, &v1alpha1.VPC{}).DoAndReturn(
				func(ctx context.Context, key client.ObjectKey, vpc *v1alpha1.VPC) error {
					vpc.ObjectMeta.Name = key.Name
					vpc.ObjectMeta.Namespace = key.Namespace
					vpc.Status.Phase = v1alpha1.VPCPhaseActive
					vpc.Status.NodeSubnets = []v1alpha1.Subnet{{SubnetID: "subnet-123"}}
					vpc.Labels = map[string]string{
						utils.GenTenantLabelKey(req.TenantId):   "true",
						utils.GenProjectLabelKey(req.ProjectId): "true",
					}
					vpc.Status.VPC.VPCID = "vpc-id-123"
					vpc.Spec.AccountRef = &v1alpha1.AccountReference{
						AccountID: "account-123",
					}
					return nil
				},
			).Times(1)
			s := runtime.NewScheme()
			gkev1beta2.SchemeBuilder.AddToScheme(s)
			mockcli := fake.NewClientBuilder().WithScheme(s).Build()
			appboxsvc.cli = mockcli
			_, err := appboxsvc.ListAPPBoxes(context.Background(), req)
			assert.Error(t, err)
			assert.ErrorContains(t, err, "failed to convert appbox to regionalp")
		})
	})
}
