package cluster

import (
	"context"
	"testing"
	"time"

	. "github.com/onsi/gomega"
	accountsdk "github.com/tidbcloud/account/idl/pbgen/proto/account"
	"go.uber.org/mock/gomock"
	grpcmetadata "google.golang.org/grpc/metadata"

	openapicommonv1beta1 "github.com/tidbcloud/tidb-management-service/api/spec/tidb_cloud_open_api/common/v1beta1"
	openapidedicatedv1beta1 "github.com/tidbcloud/tidb-management-service/api/spec/tidb_cloud_open_api/dedicated/v1beta1"
	"github.com/tidbcloud/tidb-management-service/tidb-mgmt-service/domain/adapter/account/mock_account"
	"github.com/tidbcloud/tidb-management-service/tidb-mgmt-service/pkg/common"
	"github.com/tidbcloud/tidb-management-service/utilities/grpc/metadata"
)

func TestResumeDedicatedCluster(t *testing.T) {
	g := NewWithT(t)

	mockCtrl := gomock.NewController(t)
	mockAccountClient := mock_account.NewMockClient(mockCtrl)
	mockAccountClient.EXPECT().GetProject(gomock.Any(), gomock.Any()).Return(&accountsdk.Project{
		TenantId: 1,
	}, nil).AnyTimes()
	mockAccountClient.EXPECT().
		GetTenantThirdPartyAccountProviders(gomock.Any(), gomock.Any()).
		DoAndReturn(func(ctx context.Context, id uint64) ([]openapicommonv1beta1.Region_CloudProvider, error) {
			return []openapicommonv1beta1.Region_CloudProvider{}, nil
		}).
		AnyTimes()
	mockAccountClient.EXPECT().
		UpsertClusterRelations(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).
		Return(nil).
		AnyTimes()

	service, err := initServiceWithFakeClients(mockAccountClient)
	g.Expect(err).ShouldNot(HaveOccurred())

	// Create a cluster first
	ctx := grpcmetadata.NewIncomingContext(t.Context(), grpcmetadata.New(map[string]string{
		metadata.UserIDHeaderKey:           "1",
		metadata.OrgIDHeaderKey:            "1",
		metadata.DefaultProjectIDHeaderKey: "1",
		metadata.ProjectListHeaderKey:      "1,2,3",
		metadata.IsCheckPermissionKey:      "true",
	}))

	req := &openapidedicatedv1beta1.CreateClusterRequest{
		Cluster: &openapidedicatedv1beta1.Cluster{
			DisplayName: "resume-test-1",
			RegionId:    "aws-us-west-2",
			TidbNodeSetting: &openapidedicatedv1beta1.Cluster_TidbNodeSetting{
				NodeSpecKey: "8C16G",
				TidbNodeGroups: []*openapidedicatedv1beta1.TidbNodeGroup{
					{
						NodeCount: 1,
					},
				},
			},
			TikvNodeSetting: &openapidedicatedv1beta1.Cluster_StorageNodeSetting{
				NodeSpecKey:   "8C16G",
				NodeCount:     3,
				StorageSizeGi: 50,
				StorageType:   openapidedicatedv1beta1.Cluster_StorageNodeSetting_Standard,
			},
			Labels: map[string]string{
				common.ProjectIDLabelKey: "1",
			},
		},
	}
	c, err := service.CreateCluster(ctx, req)
	g.Expect(err).ShouldNot(HaveOccurred())
	time.Sleep(3 * time.Second) // wait for the workflow dag to finish
	clusterID := c.ClusterId

	t.Run("Resume should success", func(t *testing.T) {
		resp, err := service.ResumeCluster(ctx, &openapidedicatedv1beta1.ResumeClusterRequest{ClusterId: clusterID})
		g.Expect(err).ShouldNot(HaveOccurred())
		g.Expect(resp).ShouldNot(BeNil())

		// Wait for the cluster to be active
		time.Sleep(3 * time.Second)

		// Get the cluster again
		cluster, err := service.GetCluster(
			ctx,
			&openapidedicatedv1beta1.GetClusterRequest{ClusterId: clusterID},
		)
		g.Expect(err).ShouldNot(HaveOccurred())
		g.Expect(cluster).ShouldNot(BeNil())
		g.Expect(cluster.ClusterId).Should(Equal(clusterID))
		g.Expect(cluster.DisplayName).Should(Equal("resume-test-1"))
		g.Expect(cluster.State).Should(Equal(openapicommonv1beta1.ClusterState_ACTIVE))
	})

	t.Run("Resume not found", func(t *testing.T) {
		cluster, err := service.ResumeCluster(ctx, &openapidedicatedv1beta1.ResumeClusterRequest{ClusterId: "1"})
		g.Expect(err).Should(HaveOccurred())
		g.Expect(cluster).Should(BeNil())
		g.Expect(err.Error()).Should(ContainSubstring("cluster not found"))
	})
}
