package region

import (
	"context"
	"testing"

	"github.com/onsi/gomega"
	grpcmetadata "google.golang.org/grpc/metadata"

	globalcommonv1 "github.com/tidbcloud/tidb-management-service/api/spec/global/common/v1"
	globalserverlessv1 "github.com/tidbcloud/tidb-management-service/api/spec/global/serverless/v1"
	"github.com/tidbcloud/tidb-management-service/serverless-global-service/app/register"
	regionsvc "github.com/tidbcloud/tidb-management-service/serverless-global-service/domain/service/region"
	"github.com/tidbcloud/tidb-management-service/utilities/grpc/metadata"
)

func TestListRegions(t *testing.T) {
	setupTest(t)
	g := gomega.NewWithT(t)
	ctx := grpcmetadata.NewIncomingContext(t.Context(), grpcmetadata.New(map[string]string{
		metadata.OrgIDHeaderKey:            "1",
		metadata.DefaultProjectIDHeaderKey: "1",
		metadata.ProjectListHeaderKey:      "1,2",
		metadata.UserIDHeaderKey:           "11",
	}))

	err := register.DiCall(func(svc regionsvc.Service) {
		resp, err := svc.ListRegions(ctx, &globalserverlessv1.RegionServiceListRequest{})
		g.Expect(err).ShouldNot(gomega.HaveOccurred())
		g.Expect(resp.Total >= 1).Should(gomega.BeTrue())
		foundPrivate := false
		for _, r := range resp.Regions {
			if !r.IsPublic { // private in testdata
				foundPrivate = true
			}
		}
		g.Expect(foundPrivate).Should(gomega.BeTrue())
	})
	g.Expect(err).ShouldNot(gomega.HaveOccurred())
}

func TestGetRegion(t *testing.T) {
	setupTest(t)
	g := gomega.NewWithT(t)

	ctx := grpcmetadata.NewIncomingContext(t.Context(), grpcmetadata.New(map[string]string{
		metadata.OrgIDHeaderKey:            "1",
		metadata.DefaultProjectIDHeaderKey: "1",
		metadata.ProjectListHeaderKey:      "1,2",
		metadata.UserIDHeaderKey:           "11",
	}))

	err := register.DiCall(func(svc regionsvc.Service) {
		resp, err := svc.GetRegion(ctx, &globalserverlessv1.RegionServiceGetRequest{
			RegionId:        regionEn.Id,
			CloudProviderId: regionEn.CloudProviderId,
			ServicePlan:     globalcommonv1.ServicePlan_Starter,
		})
		g.Expect(err).ShouldNot(gomega.HaveOccurred())
		g.Expect(resp.Id).Should(gomega.Equal(regionEn.Id))
		g.Expect(resp.CloudProviderId).Should(gomega.Equal(regionEn.CloudProviderId))
		g.Expect(resp.DisplayName).Should(gomega.Equal(regionEn.DisplayName))
		g.Expect(resp.ServicePlan).Should(gomega.Equal(globalcommonv1.ServicePlan_Starter))
	})
	g.Expect(err).ShouldNot(gomega.HaveOccurred())

	err = register.DiCall(func(svc regionsvc.Service) {
		resp, err := svc.GetRegion(ctx, &globalserverlessv1.RegionServiceGetRequest{
			RegionId:        awsUsWest1Region.Id,
			CloudProviderId: awsUsWest1Region.CloudProviderId,
			ServicePlan:     globalcommonv1.ServicePlan_Essential,
		})
		g.Expect(err).ShouldNot(gomega.HaveOccurred())
		g.Expect(resp.Id).Should(gomega.Equal(awsUsWest1Region.Id))
		g.Expect(resp.CloudProviderId).Should(gomega.Equal(awsUsWest1Region.CloudProviderId))
		g.Expect(resp.DisplayName).Should(gomega.Equal(awsUsWest1Region.DisplayName))
		g.Expect(resp.ServicePlan).Should(gomega.Equal(globalcommonv1.ServicePlan_Essential))
	})
	g.Expect(err).ShouldNot(gomega.HaveOccurred())
}

func TestListRegions_ServicePlanFilter(t *testing.T) {
	setupTest(t)
	g := gomega.NewWithT(t)

	ctx := grpcmetadata.NewIncomingContext(t.Context(), grpcmetadata.New(map[string]string{
		metadata.OrgIDHeaderKey:            "1",
		metadata.DefaultProjectIDHeaderKey: "1",
		metadata.ProjectListHeaderKey:      "1,2",
		metadata.UserIDHeaderKey:           "11",
	}))

	// regionEn default has starter plan, now regiter essential plan
	_ = register.DiCall(func(svc regionsvc.Service) {
		_, _ = svc.RegisterRegion(ctx, &globalserverlessv1.RegionServiceRegisterRequest{
			Region: &globalcommonv1.Region{
				Id:              regionEn.Id,
				CloudProviderId: regionEn.CloudProviderId,
				DisplayName:     regionEn.DisplayName,
				ServiceAddress:  regionEn.ServiceAddress,
				State:           regionEn.State,
				IsPublic:        regionEn.IsPublic,
				ServicePlan:     globalcommonv1.ServicePlan_Essential,
			},
		})
	})

	// public essential
	err := register.DiCall(func(svc regionsvc.Service) {
		resp, err := svc.ListRegions(ctx, &globalserverlessv1.RegionServiceListRequest{
			CloudProviderIds: []globalcommonv1.CloudProvider_Name{regionEn.CloudProviderId},
			ServicePlan:      globalcommonv1.ServicePlan_Essential,
		})
		g.Expect(err).ShouldNot(gomega.HaveOccurred())
		g.Expect(resp.Total == 1).Should(gomega.BeTrue())
	})
	g.Expect(err).ShouldNot(gomega.HaveOccurred())

	// public essential + private region essential
	err = register.DiCall(func(svc regionsvc.Service) {
		resp, err := svc.ListRegions(ctx, &globalserverlessv1.RegionServiceListRequest{
			CloudProviderIds: []globalcommonv1.CloudProvider_Name{regionEn.CloudProviderId},
			OrganizationId:   uint64(1),
			ServicePlan:      globalcommonv1.ServicePlan_Essential,
		})
		g.Expect(err).ShouldNot(gomega.HaveOccurred())
		g.Expect(resp.Total == 2).Should(gomega.BeTrue())
	})
	g.Expect(err).ShouldNot(gomega.HaveOccurred())

	// public essential + public starter + private region essential
	err = register.DiCall(func(svc regionsvc.Service) {
		resp, err := svc.ListRegions(ctx, &globalserverlessv1.RegionServiceListRequest{
			OrganizationId: uint64(1),
		})
		g.Expect(err).ShouldNot(gomega.HaveOccurred())
		g.Expect(resp.Total == 3).Should(gomega.BeTrue())
	})
	g.Expect(err).ShouldNot(gomega.HaveOccurred())
}

func TestListRegions_OrganizationFilter(t *testing.T) {
	setupTest(t)
	g := gomega.NewWithT(t)

	// Org 1 should see private region awsUsWest1Region
	ctx1 := grpcmetadata.NewIncomingContext(t.Context(), grpcmetadata.New(map[string]string{
		metadata.OrgIDHeaderKey:            "1",
		metadata.DefaultProjectIDHeaderKey: "1",
		metadata.ProjectListHeaderKey:      "1,2",
		metadata.UserIDHeaderKey:           "11",
	}))

	err := register.DiCall(func(svc regionsvc.Service) {
		resp, err := svc.ListRegions(ctx1, &globalserverlessv1.RegionServiceListRequest{
			CloudProviderIds: []globalcommonv1.CloudProvider_Name{regionEn.CloudProviderId},
			OrganizationId:   1,
		})
		g.Expect(err).ShouldNot(gomega.HaveOccurred())
		// expect at least public region and private region for org 1
		g.Expect(resp.Total >= 1).Should(gomega.BeTrue())
		// When private exists, it should be included for org 1
		foundPrivate := false
		for _, r := range resp.Regions {
			if r.Id == awsUsWest1Region.Id && !r.IsPublic { // private in testdata
				foundPrivate = true
			}
		}
		g.Expect(foundPrivate).Should(gomega.BeTrue())
	})
	g.Expect(err).ShouldNot(gomega.HaveOccurred())

	// Org 2 should NOT see private region awsUsWest1Region (opened only to org 1)
	ctx2 := grpcmetadata.NewIncomingContext(t.Context(), grpcmetadata.New(map[string]string{
		metadata.OrgIDHeaderKey:            "2",
		metadata.DefaultProjectIDHeaderKey: "2",
		metadata.ProjectListHeaderKey:      "2",
		metadata.UserIDHeaderKey:           "11",
	}))

	err = register.DiCall(func(svc regionsvc.Service) {
		resp, err := svc.ListRegions(ctx2, &globalserverlessv1.RegionServiceListRequest{
			CloudProviderIds: []globalcommonv1.CloudProvider_Name{awsUsWest1Region.CloudProviderId},
			OrganizationId:   2,
		})
		g.Expect(err).ShouldNot(gomega.HaveOccurred())
		for _, r := range resp.Regions {
			g.Expect(r.Id == awsUsWest1Region.Id).Should(gomega.BeFalse())
		}
	})
	g.Expect(err).ShouldNot(gomega.HaveOccurred())
}

func TestRegisterRegion_IsPublic(t *testing.T) {
	setupTest(t)
	g := gomega.NewWithT(t)

	type testCase struct {
		name      string
		inputsFn  func() (context.Context, *globalserverlessv1.RegionServiceRegisterRequest)
		outputsFn func(*globalcommonv1.Region, error)
	}

	cases := []testCase{
		{
			name: "Create region should be success",
			inputsFn: func() (context.Context, *globalserverlessv1.RegionServiceRegisterRequest) {
				ctx := grpcmetadata.NewIncomingContext(t.Context(), grpcmetadata.New(map[string]string{
					metadata.OrgIDHeaderKey:            "1",
					metadata.DefaultProjectIDHeaderKey: "1",
					metadata.ProjectListHeaderKey:      "1,2",
					metadata.UserIDHeaderKey:           "11",
				}))
				// register regionEn essential plan
				return ctx, &globalserverlessv1.RegionServiceRegisterRequest{
					Region: &globalcommonv1.Region{
						Id:                regionEn.Id,
						DisplayName:       regionEn.DisplayName,
						State:             regionEn.State,
						IsPublic:          regionEn.IsPublic,
						ServiceAddress:    regionEn.ServiceAddress,
						CloudProviderId:   regionEn.CloudProviderId,
						OpenedTenantIds:   []uint64{121},
						DefaultBackupTime: "10:00",
						ServicePlan:       globalcommonv1.ServicePlan_Essential,
					},
				}
			},
			outputsFn: func(re *globalcommonv1.Region, err error) {
				g.Expect(err).ShouldNot(gomega.HaveOccurred())
				g.Expect(re.Id > 0).Should(gomega.BeTrue())
				g.Expect(re.Id).Should(gomega.Equal(regionEn.Id))
				g.Expect(re.DisplayName).Should(gomega.Equal(regionEn.DisplayName))
				g.Expect(re.ServiceAddress).Should(gomega.Equal(regionEn.ServiceAddress))
				g.Expect(re.State).Should(gomega.Equal(regionEn.State))
				g.Expect(re.DefaultBackupTime).Should(gomega.Equal("10:00"))
				g.Expect(re.ServicePlan).Should(gomega.Equal(globalcommonv1.ServicePlan_Essential))
			},
		},
	}

	for _, tc := range cases {
		t.Run(tc.name, func(t *testing.T) {
			ctx, req := tc.inputsFn()
			err := register.DiCall(func(svc regionsvc.Service) {
				resp, err := svc.RegisterRegion(ctx, req)
				tc.outputsFn(resp, err)
			})

			g.Expect(err).ShouldNot(gomega.HaveOccurred())
		})
	}

	// GetRegion without required should return error
	err := register.DiCall(func(svc regionsvc.Service) {
		_, err := svc.GetRegion(t.Context(), &globalserverlessv1.RegionServiceGetRequest{
			RegionId:        regionEn.Id,
			CloudProviderId: regionEn.CloudProviderId,
		})
		g.Expect(err).Should(gomega.HaveOccurred())
	})
	g.Expect(err).ShouldNot(gomega.HaveOccurred())
	// GetRegion with essentail plan
	err = register.DiCall(func(svc regionsvc.Service) {
		re, err := svc.GetRegion(t.Context(), &globalserverlessv1.RegionServiceGetRequest{
			RegionId:        regionEn.Id,
			CloudProviderId: regionEn.CloudProviderId,
			ServicePlan:     globalcommonv1.ServicePlan_Essential,
		})
		g.Expect(err).ShouldNot(gomega.HaveOccurred())
		g.Expect(re.Id > 0).Should(gomega.BeTrue())
		g.Expect(re.Id).Should(gomega.Equal(regionEn.Id))
		g.Expect(re.DisplayName).Should(gomega.Equal(regionEn.DisplayName))
		g.Expect(re.ServiceAddress).Should(gomega.Equal(regionEn.ServiceAddress))
		g.Expect(re.State).Should(gomega.Equal(regionEn.State))
		g.Expect(len(re.OpenedTenantIds)).Should(gomega.Equal(0))
		g.Expect(re.DefaultBackupTime).Should(gomega.Equal("10:00"))
		g.Expect(re.ServicePlan).Should(gomega.Equal(globalcommonv1.ServicePlan_Essential))
	})
	g.Expect(err).ShouldNot(gomega.HaveOccurred())

	// GetRegion with starter plan
	err = register.DiCall(func(svc regionsvc.Service) {
		re, err := svc.GetRegion(t.Context(), &globalserverlessv1.RegionServiceGetRequest{
			RegionId:        regionEn.Id,
			CloudProviderId: regionEn.CloudProviderId,
			ServicePlan:     globalcommonv1.ServicePlan_Starter,
		})
		g.Expect(err).ShouldNot(gomega.HaveOccurred())
		g.Expect(re.Id > 0).Should(gomega.BeTrue())
		g.Expect(re.Id).Should(gomega.Equal(regionEn.Id))
		g.Expect(re.DisplayName).Should(gomega.Equal(regionEn.DisplayName))
		g.Expect(re.ServiceAddress).Should(gomega.Equal(regionEn.ServiceAddress))
		g.Expect(re.State).Should(gomega.Equal(regionEn.State))
		g.Expect(len(re.OpenedTenantIds)).Should(gomega.Equal(0))
		g.Expect(re.ServicePlan).Should(gomega.Equal(globalcommonv1.ServicePlan_Starter))
	})
	g.Expect(err).ShouldNot(gomega.HaveOccurred())
}

func TestUpdateRegion_IsPrivate(t *testing.T) {
	setupTest(t)
	g := gomega.NewWithT(t)

	type testCase struct {
		name      string
		inputsFn  func() (context.Context, *globalserverlessv1.RegionServiceUpdateRequest)
		outputsFn func(*globalcommonv1.Region, error)
	}

	cases := []testCase{
		{
			name: "Create region should be success",
			// awsUsWest1Region default: private region + essential plan + 1 whitelist tenant
			inputsFn: func() (context.Context, *globalserverlessv1.RegionServiceUpdateRequest) {
				ctx := grpcmetadata.NewIncomingContext(t.Context(), grpcmetadata.New(map[string]string{
					metadata.OrgIDHeaderKey:            "1",
					metadata.DefaultProjectIDHeaderKey: "1",
					metadata.ProjectListHeaderKey:      "1,2",
					metadata.UserIDHeaderKey:           "11",
				}))
				// awsUsWest1Region update: private region + essential plan + 2 whitelist tenant
				return ctx, &globalserverlessv1.RegionServiceUpdateRequest{
					Region: &globalcommonv1.Region{
						Id:                awsUsWest1Region.Id,
						DisplayName:       awsUsWest1Region.DisplayName,
						State:             awsUsWest1Region.State,
						IsPublic:          awsUsWest1Region.IsPublic,
						ServiceAddress:    awsUsWest1Region.ServiceAddress,
						CloudProviderId:   awsUsWest1Region.CloudProviderId,
						OpenedTenantIds:   []uint64{121, 134},
						DefaultBackupTime: "10:00",
						ServicePlan:       globalcommonv1.ServicePlan_Essential,
					},
				}
			},
			outputsFn: func(re *globalcommonv1.Region, err error) {
				g.Expect(err).ShouldNot(gomega.HaveOccurred())
				g.Expect(re.Id > 0).Should(gomega.BeTrue())
				g.Expect(re.Id).Should(gomega.Equal(awsUsWest1Region.Id))
				g.Expect(re.DisplayName).Should(gomega.Equal(awsUsWest1Region.DisplayName))
				g.Expect(re.ServiceAddress).Should(gomega.Equal(awsUsWest1Region.ServiceAddress))
				g.Expect(re.State).Should(gomega.Equal(awsUsWest1Region.State))
				g.Expect(len(re.OpenedTenantIds)).Should(gomega.Equal(2))
				g.Expect(re.OpenedTenantIds[0]).Should(gomega.Equal(uint64(121)))
				g.Expect(re.OpenedTenantIds[1]).Should(gomega.Equal(uint64(134)))
				g.Expect(re.DefaultBackupTime).Should(gomega.Equal("10:00"))
				g.Expect(re.ServicePlan).Should(gomega.Equal(globalcommonv1.ServicePlan_Essential))
			},
		},
	}

	for _, tc := range cases {
		t.Run(tc.name, func(t *testing.T) {
			ctx, req := tc.inputsFn()
			err := register.DiCall(func(svc regionsvc.Service) {
				resp, err := svc.UpdateRegion(ctx, req)
				tc.outputsFn(resp, err)
			})

			g.Expect(err).ShouldNot(gomega.HaveOccurred())
		})
	}

	err := register.DiCall(func(svc regionsvc.Service) {
		re, err := svc.GetRegion(t.Context(), &globalserverlessv1.RegionServiceGetRequest{
			RegionId:        awsUsWest1Region.Id,
			CloudProviderId: awsUsWest1Region.CloudProviderId,
			ServicePlan:     globalcommonv1.ServicePlan_Essential,
		})
		g.Expect(err).ShouldNot(gomega.HaveOccurred())
		g.Expect(re.Id > 0).Should(gomega.BeTrue())
		g.Expect(re.Id).Should(gomega.Equal(awsUsWest1Region.Id))
		g.Expect(re.DisplayName).Should(gomega.Equal(awsUsWest1Region.DisplayName))
		g.Expect(re.ServiceAddress).Should(gomega.Equal(awsUsWest1Region.ServiceAddress))
		g.Expect(re.State).Should(gomega.Equal(awsUsWest1Region.State))
		g.Expect(len(re.OpenedTenantIds)).Should(gomega.Equal(3))
		g.Expect(re.OpenedTenantIds[0]).Should(gomega.Equal(uint64(1)))
		g.Expect(re.OpenedTenantIds[1]).Should(gomega.Equal(uint64(121)))
		g.Expect(re.OpenedTenantIds[2]).Should(gomega.Equal(uint64(134)))
		g.Expect(re.DefaultBackupTime).Should(gomega.Equal("10:00"))
		g.Expect(re.ServicePlan).Should(gomega.Equal(globalcommonv1.ServicePlan_Essential))
	})
	g.Expect(err).ShouldNot(gomega.HaveOccurred())
}

func TestRegisterRegion_PGStarterRequiresSys9Config(t *testing.T) {
	setupTest(t)
	g := gomega.NewWithT(t)

	ctx := grpcmetadata.NewIncomingContext(t.Context(), grpcmetadata.New(map[string]string{
		metadata.OrgIDHeaderKey:            "1",
		metadata.DefaultProjectIDHeaderKey: "1",
		metadata.ProjectListHeaderKey:      "1,2",
		metadata.UserIDHeaderKey:           "11",
	}))

	err := register.DiCall(func(svc regionsvc.Service) {
		_, err := svc.RegisterRegion(ctx, &globalserverlessv1.RegionServiceRegisterRequest{
			Region: &globalcommonv1.Region{
				Id:              globalcommonv1.Region_AWS_US_WEST_2,
				CloudProviderId: globalcommonv1.CloudProvider_AWS,
				DisplayName:     "us-west-2",
				ServicePlan:     globalcommonv1.ServicePlan_Starter,
				EngineType:      globalcommonv1.Region_POSTGRESQL_COMPATIBLE,
				State:           globalcommonv1.Region_ACTIVE,
				IsPublic:        true,
			},
		})
		g.Expect(err).Should(gomega.HaveOccurred())
	})
	g.Expect(err).ShouldNot(gomega.HaveOccurred())

	err = register.DiCall(func(svc regionsvc.Service) {
		resp, err := svc.RegisterRegion(ctx, &globalserverlessv1.RegionServiceRegisterRequest{
			Region: &globalcommonv1.Region{
				Id:              globalcommonv1.Region_AWS_US_WEST_2,
				CloudProviderId: globalcommonv1.CloudProvider_AWS,
				DisplayName:     "us-west-2",
				ServiceAddress:  "https://sys9.example.com",
				ServicePlan:     globalcommonv1.ServicePlan_Starter,
				EngineType:      globalcommonv1.Region_POSTGRESQL_COMPATIBLE,
				State:           globalcommonv1.Region_ACTIVE,
				IsPublic:        true,
				Sys9Config: &globalcommonv1.RegionSys9Config{
					OemProfileRef: "oem-profile-1",
				},
			},
		})
		g.Expect(err).ShouldNot(gomega.HaveOccurred())
		g.Expect(resp.GetEngineType()).Should(gomega.Equal(globalcommonv1.Region_POSTGRESQL_COMPATIBLE))
		g.Expect(resp.GetSys9Config().GetOemProfileRef()).Should(gomega.Equal("oem-profile-1"))
	})
	g.Expect(err).ShouldNot(gomega.HaveOccurred())
}

func TestListAndGetRegion_ByEngineType(t *testing.T) {
	setupTest(t)
	g := gomega.NewWithT(t)

	ctx := grpcmetadata.NewIncomingContext(t.Context(), grpcmetadata.New(map[string]string{
		metadata.OrgIDHeaderKey:            "1",
		metadata.DefaultProjectIDHeaderKey: "1",
		metadata.ProjectListHeaderKey:      "1,2",
		metadata.UserIDHeaderKey:           "11",
	}))

	err := register.DiCall(func(svc regionsvc.Service) {
		_, err := svc.RegisterRegion(ctx, &globalserverlessv1.RegionServiceRegisterRequest{
			Region: &globalcommonv1.Region{
				Id:              globalcommonv1.Region_AWS_US_WEST_2,
				CloudProviderId: globalcommonv1.CloudProvider_AWS,
				DisplayName:     "us-west-2",
				ServiceAddress:  "https://sys9.example.com",
				ServicePlan:     globalcommonv1.ServicePlan_Starter,
				EngineType:      globalcommonv1.Region_POSTGRESQL_COMPATIBLE,
				State:           globalcommonv1.Region_ACTIVE,
				IsPublic:        true,
				Sys9Config: &globalcommonv1.RegionSys9Config{
					OemProfileRef: "oem-profile-1",
				},
			},
		})
		g.Expect(err).ShouldNot(gomega.HaveOccurred())

		listResp, err := svc.ListRegions(ctx, &globalserverlessv1.RegionServiceListRequest{
			CloudProviderIds: []globalcommonv1.CloudProvider_Name{globalcommonv1.CloudProvider_AWS},
			ServicePlan:      globalcommonv1.ServicePlan_Starter,
			EngineType:       "POSTGRESQL_COMPATIBLE",
		})
		g.Expect(err).ShouldNot(gomega.HaveOccurred())
		g.Expect(listResp.GetTotal()).Should(gomega.Equal(uint32(1)))
		g.Expect(listResp.GetRegions()[0].GetEngineType()).Should(gomega.Equal(globalcommonv1.Region_POSTGRESQL_COMPATIBLE))

		getResp, err := svc.GetRegion(ctx, &globalserverlessv1.RegionServiceGetRequest{
			RegionId:        globalcommonv1.Region_AWS_US_WEST_2,
			CloudProviderId: globalcommonv1.CloudProvider_AWS,
			ServicePlan:     globalcommonv1.ServicePlan_Starter,
			EngineType:      "POSTGRESQL_COMPATIBLE",
		})
		g.Expect(err).ShouldNot(gomega.HaveOccurred())
		g.Expect(getResp.GetEngineType()).Should(gomega.Equal(globalcommonv1.Region_POSTGRESQL_COMPATIBLE))
	})
	g.Expect(err).ShouldNot(gomega.HaveOccurred())
}

func TestRegionLifeCycle(t *testing.T) {
	setupTest(t)
	g := gomega.NewWithT(t)

	ctx := grpcmetadata.NewIncomingContext(t.Context(), grpcmetadata.New(map[string]string{
		metadata.OrgIDHeaderKey:            "1",
		metadata.DefaultProjectIDHeaderKey: "1",
		metadata.ProjectListHeaderKey:      "1,2",
		metadata.UserIDHeaderKey:           "11",
	}))
	newRegionEssential := &globalcommonv1.Region{
		Id:              globalcommonv1.Region_AWS_AF_SOUTH_1,
		CloudProviderId: globalcommonv1.CloudProvider_AWS,
		State:           globalcommonv1.Region_ACTIVE,
		IsPublic:        false,
		OpenedTenantIds: []uint64{10000},
		ServicePlan:     globalcommonv1.ServicePlan_Essential,
	}
	newRegionStarter := &globalcommonv1.Region{
		Id:              globalcommonv1.Region_AWS_AF_SOUTH_1,
		CloudProviderId: globalcommonv1.CloudProvider_AWS,
		State:           globalcommonv1.Region_ACTIVE,
		IsPublic:        true,
		ServicePlan:     globalcommonv1.ServicePlan_Starter,
	}

	// step 1: register new private newRegionEssential
	err := register.DiCall(func(svc regionsvc.Service) {
		resp, err := svc.RegisterRegion(ctx, &globalserverlessv1.RegionServiceRegisterRequest{
			Region: newRegionEssential,
		})
		g.Expect(err).ShouldNot(gomega.HaveOccurred())
		g.Expect(resp.Id).Should(gomega.Equal(newRegionEssential.Id))
		g.Expect(resp.CloudProviderId).Should(gomega.Equal(newRegionEssential.CloudProviderId))
		g.Expect(len(resp.OpenedTenantIds)).Should(gomega.Equal(1))
		g.Expect(resp.ServicePlan).Should(gomega.Equal(globalcommonv1.ServicePlan_Essential))
	})
	g.Expect(err).ShouldNot(gomega.HaveOccurred())

	// step 2: update newRegionEssential with whitelist orgs
	err = register.DiCall(func(svc regionsvc.Service) {
		newRegionEssential.OpenedTenantIds = []uint64{10001, 10002, 10003}
		resp, err := svc.UpdateRegion(ctx, &globalserverlessv1.RegionServiceUpdateRequest{
			Region: newRegionEssential,
		})
		g.Expect(err).ShouldNot(gomega.HaveOccurred())
		g.Expect(resp.Id).Should(gomega.Equal(newRegionEssential.Id))
		g.Expect(resp.CloudProviderId).Should(gomega.Equal(newRegionEssential.CloudProviderId))
		g.Expect(len(resp.OpenedTenantIds)).Should(gomega.Equal(3))
	})
	g.Expect(err).ShouldNot(gomega.HaveOccurred())

	err = register.DiCall(func(svc regionsvc.Service) {
		resp, err := svc.ListRegions(ctx, &globalserverlessv1.RegionServiceListRequest{
			OrganizationId: 10003,
		})
		// default public region + new private newRegionEssential
		g.Expect(err).ShouldNot(gomega.HaveOccurred())
		g.Expect(len(resp.Regions)).Should(gomega.Equal(2))
		g.Expect(resp.Regions[1].Id).Should(gomega.Equal(newRegionEssential.Id))
		g.Expect(resp.Regions[1].CloudProviderId).Should(gomega.Equal(newRegionEssential.CloudProviderId))
		g.Expect(len(resp.Regions[1].OpenedTenantIds)).Should(gomega.Equal(4))
		g.Expect(resp.Regions[1].ServicePlan).Should(gomega.Equal(globalcommonv1.ServicePlan_Essential))
	})
	g.Expect(err).ShouldNot(gomega.HaveOccurred())

	// step 3: update newRegionEssential from private to public
	err = register.DiCall(func(svc regionsvc.Service) {
		newRegionEssential.IsPublic = true
		_, err = svc.UpdateRegion(ctx, &globalserverlessv1.RegionServiceUpdateRequest{
			Region: newRegionEssential,
		})
		g.Expect(err).ShouldNot(gomega.HaveOccurred())
	})
	g.Expect(err).ShouldNot(gomega.HaveOccurred())

	err = register.DiCall(func(svc regionsvc.Service) {
		// two public region: default region with starter plan, newRegionEssential
		resp, err := svc.ListRegions(ctx, &globalserverlessv1.RegionServiceListRequest{
			OrganizationId: 10005, // not exist whitelist tenant id
		})
		g.Expect(err).ShouldNot(gomega.HaveOccurred())
		g.Expect(len(resp.Regions)).Should(gomega.Equal(2))
		g.Expect(resp.Regions[1].Id).Should(gomega.Equal(newRegionEssential.Id))
		g.Expect(resp.Regions[1].CloudProviderId).Should(gomega.Equal(newRegionEssential.CloudProviderId))
		g.Expect(len(resp.Regions[1].OpenedTenantIds)).Should(gomega.Equal(0))
		g.Expect(resp.Regions[0].ServicePlan).Should(gomega.Equal(globalcommonv1.ServicePlan_Starter))
		g.Expect(resp.Regions[1].ServicePlan).Should(gomega.Equal(globalcommonv1.ServicePlan_Essential))
	})
	g.Expect(err).ShouldNot(gomega.HaveOccurred())

	err = register.DiCall(func(svc regionsvc.Service) {
		// only return newRegionEssential
		resp, err := svc.ListRegions(ctx, &globalserverlessv1.RegionServiceListRequest{
			ServicePlan: globalcommonv1.ServicePlan_Essential,
		})
		g.Expect(err).ShouldNot(gomega.HaveOccurred())
		g.Expect(len(resp.Regions)).Should(gomega.Equal(1))
		g.Expect(resp.Regions[0].Id).Should(gomega.Equal(newRegionEssential.Id))
		g.Expect(resp.Regions[0].CloudProviderId).Should(gomega.Equal(newRegionEssential.CloudProviderId))
		g.Expect(len(resp.Regions[0].OpenedTenantIds)).Should(gomega.Equal(0))
		g.Expect(resp.Regions[0].ServicePlan).Should(gomega.Equal(globalcommonv1.ServicePlan_Essential))
	})
	g.Expect(err).ShouldNot(gomega.HaveOccurred())

	// step 4: register public newRegionStarter
	err = register.DiCall(func(svc regionsvc.Service) {
		resp, err := svc.RegisterRegion(ctx, &globalserverlessv1.RegionServiceRegisterRequest{
			Region: newRegionStarter,
		})
		g.Expect(err).ShouldNot(gomega.HaveOccurred())
		g.Expect(resp.Id).Should(gomega.Equal(newRegionEssential.Id))
		g.Expect(resp.CloudProviderId).Should(gomega.Equal(newRegionEssential.CloudProviderId))
		g.Expect(resp.ServicePlan).Should(gomega.Equal(globalcommonv1.ServicePlan_Starter))
	})
	g.Expect(err).ShouldNot(gomega.HaveOccurred())

	err = register.DiCall(func(svc regionsvc.Service) {
		// only return newRegionEssential
		resp, err := svc.ListRegions(ctx, &globalserverlessv1.RegionServiceListRequest{
			ServicePlan: globalcommonv1.ServicePlan_Essential,
		})
		g.Expect(err).ShouldNot(gomega.HaveOccurred())
		g.Expect(len(resp.Regions)).Should(gomega.Equal(1))
		g.Expect(resp.Regions[0].Id).Should(gomega.Equal(newRegionEssential.Id))
		g.Expect(resp.Regions[0].CloudProviderId).Should(gomega.Equal(newRegionEssential.CloudProviderId))
		g.Expect(len(resp.Regions[0].OpenedTenantIds)).Should(gomega.Equal(0))
		g.Expect(resp.Regions[0].ServicePlan).Should(gomega.Equal(globalcommonv1.ServicePlan_Essential))
	})
	g.Expect(err).ShouldNot(gomega.HaveOccurred())

	err = register.DiCall(func(svc regionsvc.Service) {
		// two public region: default region with starter plan, newRegionStarter with starter plan
		resp, err := svc.ListRegions(ctx, &globalserverlessv1.RegionServiceListRequest{
			ServicePlan: globalcommonv1.ServicePlan_Starter,
		})
		g.Expect(err).ShouldNot(gomega.HaveOccurred())
		g.Expect(len(resp.Regions)).Should(gomega.Equal(2))
		g.Expect(resp.Regions[1].Id).Should(gomega.Equal(newRegionEssential.Id))
		g.Expect(resp.Regions[1].CloudProviderId).Should(gomega.Equal(newRegionEssential.CloudProviderId))
		g.Expect(len(resp.Regions[1].OpenedTenantIds)).Should(gomega.Equal(0))
		g.Expect(resp.Regions[0].ServicePlan).Should(gomega.Equal(globalcommonv1.ServicePlan_Starter))
		g.Expect(resp.Regions[1].ServicePlan).Should(gomega.Equal(globalcommonv1.ServicePlan_Starter))
	})
	g.Expect(err).ShouldNot(gomega.HaveOccurred())

	err = register.DiCall(func(svc regionsvc.Service) {
		// three public region: default region with starter plan, newRegionStarter with starter plan, newRegionEssential with essential plan
		resp, err := svc.ListRegions(ctx, &globalserverlessv1.RegionServiceListRequest{
			OrganizationId: 10005,
		})
		g.Expect(err).ShouldNot(gomega.HaveOccurred())
		g.Expect(len(resp.Regions)).Should(gomega.Equal(3))
		g.Expect(resp.Regions[1].Id).Should(gomega.Equal(newRegionEssential.Id))
		g.Expect(resp.Regions[1].CloudProviderId).Should(gomega.Equal(newRegionEssential.CloudProviderId))
		g.Expect(len(resp.Regions[1].OpenedTenantIds)).Should(gomega.Equal(0))
		g.Expect(resp.Regions[2].Id).Should(gomega.Equal(newRegionEssential.Id))
		g.Expect(resp.Regions[2].CloudProviderId).Should(gomega.Equal(newRegionEssential.CloudProviderId))
		g.Expect(len(resp.Regions[2].OpenedTenantIds)).Should(gomega.Equal(0))
		g.Expect(resp.Regions[0].ServicePlan).Should(gomega.Equal(globalcommonv1.ServicePlan_Starter))
		g.Expect(resp.Regions[1].ServicePlan).Should(gomega.Equal(globalcommonv1.ServicePlan_Essential))
		g.Expect(resp.Regions[2].ServicePlan).Should(gomega.Equal(globalcommonv1.ServicePlan_Starter))
	})
	g.Expect(err).ShouldNot(gomega.HaveOccurred())

	// step 5: delete newRegionEssential
	// current three public region: default region with starter plan, newRegionStarter with starter plan, newRegionEssential with essential plan
	_ = register.DiCall(func(svc regionsvc.Service) {
		err = svc.DeleteRegion(ctx, &globalserverlessv1.RegionServiceDeleteRequest{
			RegionId: newRegionEssential.Id,
		})
		// invalid params: cloud provider, region, service plan
		g.Expect(err).Should(gomega.HaveOccurred())
	})
	// delete newRegionEssential
	_ = register.DiCall(func(svc regionsvc.Service) {
		err = svc.DeleteRegion(ctx, &globalserverlessv1.RegionServiceDeleteRequest{
			CloudProviderId: newRegionEssential.CloudProviderId,
			RegionId:        newRegionEssential.Id,
			ServicePlan:     globalcommonv1.ServicePlan_Essential,
		})
		// region is not inactive
		g.Expect(err).Should(gomega.HaveOccurred())
	})
	// update newRegionEssential to inactive before delete
	_ = register.DiCall(func(svc regionsvc.Service) {
		newRegionEssential.State = globalcommonv1.Region_INACTIVE
		_, err = svc.UpdateRegion(ctx, &globalserverlessv1.RegionServiceUpdateRequest{
			Region: newRegionEssential,
		})
		g.Expect(err).ShouldNot(gomega.HaveOccurred())
	})
	// delete newRegionEssential essential plan, retry
	_ = register.DiCall(func(svc regionsvc.Service) {
		err = svc.DeleteRegion(ctx, &globalserverlessv1.RegionServiceDeleteRequest{
			CloudProviderId: newRegionEssential.CloudProviderId,
			RegionId:        newRegionEssential.Id,
			ServicePlan:     newRegionEssential.ServicePlan,
		})
		g.Expect(err).ShouldNot(gomega.HaveOccurred())
	})
	err = register.DiCall(func(svc regionsvc.Service) {
		// two public region: default region with starter plan, public newRegionStarter with starter plan
		resp, err := svc.ListRegions(ctx, &globalserverlessv1.RegionServiceListRequest{
			OrganizationId: 10005,
		})
		g.Expect(err).ShouldNot(gomega.HaveOccurred())
		g.Expect(len(resp.Regions)).Should(gomega.Equal(2))
		g.Expect(resp.Regions[1].Id).Should(gomega.Equal(newRegionEssential.Id))
		g.Expect(resp.Regions[1].CloudProviderId).Should(gomega.Equal(newRegionEssential.CloudProviderId))
		g.Expect(len(resp.Regions[1].OpenedTenantIds)).Should(gomega.Equal(0))
		g.Expect(resp.Regions[0].ServicePlan).Should(gomega.Equal(globalcommonv1.ServicePlan_Starter))
		g.Expect(resp.Regions[1].ServicePlan).Should(gomega.Equal(globalcommonv1.ServicePlan_Starter))
		g.Expect(resp.Regions[1].IsPublic).Should(gomega.Equal(true))
	})
	g.Expect(err).ShouldNot(gomega.HaveOccurred())
	// delete newRegionStarter
	_ = register.DiCall(func(svc regionsvc.Service) {
		err = svc.DeleteRegion(ctx, &globalserverlessv1.RegionServiceDeleteRequest{
			CloudProviderId: newRegionStarter.CloudProviderId,
			RegionId:        newRegionStarter.Id,
			ServicePlan:     newRegionStarter.ServicePlan,
		})
		// region is not inactive
		g.Expect(err).Should(gomega.HaveOccurred())
	})
	// update newRegionStarter to inactive before delete
	_ = register.DiCall(func(svc regionsvc.Service) {
		newRegionStarter.State = globalcommonv1.Region_INACTIVE
		_, err = svc.UpdateRegion(ctx, &globalserverlessv1.RegionServiceUpdateRequest{
			Region: newRegionStarter,
		})
		g.Expect(err).ShouldNot(gomega.HaveOccurred())
	})
	// delete newRegionStarter, retry
	_ = register.DiCall(func(svc regionsvc.Service) {
		err = svc.DeleteRegion(ctx, &globalserverlessv1.RegionServiceDeleteRequest{
			CloudProviderId: newRegionStarter.CloudProviderId,
			RegionId:        newRegionStarter.Id,
			ServicePlan:     newRegionStarter.ServicePlan,
		})
		g.Expect(err).ShouldNot(gomega.HaveOccurred())
	})
	err = register.DiCall(func(svc regionsvc.Service) {
		// one public region: default region with starter plan, newRegionEssential/newRegionStarter was deleted
		resp, err := svc.ListRegions(ctx, &globalserverlessv1.RegionServiceListRequest{
			OrganizationId: 10005,
		})
		g.Expect(err).ShouldNot(gomega.HaveOccurred())
		g.Expect(len(resp.Regions)).Should(gomega.Equal(1))
		g.Expect(resp.Regions[0].CloudProviderId).Should(gomega.Equal(newRegionEssential.CloudProviderId))
		g.Expect(resp.Regions[0].ServicePlan).Should(gomega.Equal(globalcommonv1.ServicePlan_Starter))
	})
	g.Expect(err).ShouldNot(gomega.HaveOccurred())
}
