package vpc

import (
	"context"
	"testing"

	. "github.com/onsi/gomega"
	"go.uber.org/mock/gomock"

	globalcommonv1 "github.com/tidbcloud/tidb-management-service/api/spec/global/common/v1"
	globaldedicatedv1 "github.com/tidbcloud/tidb-management-service/api/spec/global/dedicated/v1"
	"github.com/tidbcloud/tidb-management-service/dedicated-global-service/domain/entity"
	clusterrepo "github.com/tidbcloud/tidb-management-service/dedicated-global-service/domain/repository/cluster"
	clusterrepomock "github.com/tidbcloud/tidb-management-service/dedicated-global-service/domain/repository/cluster/mock_cluster"
	"github.com/tidbcloud/tidb-management-service/utilities/bizerr"
)

func TestEnsureVpcPeeringCreatePrerequisite(t *testing.T) {
	t.Parallel()

	const (
		orgID     = uint64(1001)
		projectID = uint64(2002)
	)

	region := &entity.Region{
		Id:              globalcommonv1.Region_AWS_US_EAST_1,
		CloudProviderId: globalcommonv1.CloudProvider_AWS,
	}

	testCases := []struct {
		name     string
		clusters []*entity.Cluster
		repoErr  bizerr.BizError
		wantErr  bool
		wantCode bizerr.ErrCode
	}{
		{
			name: "allow scaling cluster because it is not excluded",
			clusters: []*entity.Cluster{
				{Cluster: &globaldedicatedv1.Cluster{State: globaldedicatedv1.Cluster_SCALING}},
			},
		},
		{
			name:     "reject when no eligible cluster exists",
			wantErr:  true,
			wantCode: bizerr.ErrCodeVPCPeeringCreatePrerequisite,
		},
		{
			name:     "return repo error",
			repoErr:  bizerr.New(bizerr.ErrCodeUnknown, "query failed"),
			wantErr:  true,
			wantCode: bizerr.ErrCodeUnknown,
		},
	}

	for _, tc := range testCases {
		t.Run(tc.name, func(t *testing.T) {
			t.Parallel()

			g := NewWithT(t)
			ctrl := gomock.NewController(t)
			clusterRepo := clusterrepomock.NewMockRepo(ctrl)
			svc := &serviceImpl{
				clusterRepo: clusterRepo,
			}

			clusterRepo.EXPECT().Query(gomock.Any(), gomock.Any()).DoAndReturn(
				func(ctx context.Context, filter *clusterrepo.Filter) ([]*entity.Cluster, bizerr.BizError) {
					g.Expect(ctx).NotTo(BeNil())
					g.Expect(filter.CloudProviderNames).To(Equal([]entity.CloudProviderName{region.CloudProviderId}))
					g.Expect(filter.RegionNames).To(Equal([]entity.RegionName{region.Id}))
					g.Expect(filter.OrganizationIds).To(Equal([]uint64{orgID}))
					g.Expect(filter.ProjectIds).To(Equal([]uint64{projectID}))
					g.Expect(filter.States).To(BeEmpty())
					g.Expect(filter.ExcludeStates).To(Equal([]entity.State{
						globaldedicatedv1.Cluster_STATE_UNSPECIFIED,
						globaldedicatedv1.Cluster_DELETED,
					}))

					return tc.clusters, tc.repoErr
				},
			)

			err := svc.ensureVpcPeeringCreatePrerequisite(t.Context(), orgID, projectID, region)
			if tc.wantErr {
				g.Expect(err).NotTo(BeNil())
				g.Expect(err.ErrCode()).To(Equal(tc.wantCode))
				return
			}

			g.Expect(err).To(BeNil())
		})
	}
}
