package openapiserverless

import (
	"testing"
	"time"

	"github.com/samber/lo"
	"github.com/spf13/viper"
	"github.com/stretchr/testify/suite"

	serverlessapi "github.com/tidbcloud/tidb-management-service/functional-test/pkg/serverlessapi/api"
	"github.com/tidbcloud/tidb-management-service/functional-test/pkg/serverlessapi/api/model"
	"github.com/tidbcloud/tidb-management-service/utilities/randstr"
)

//	TestClusterCreate verifies end-to-end cluster creation and cleanup
//
// by initializing a client, creating a cluster, checking its status, and deleting the cluster.
func TestClusterCreate(t *testing.T) {
	testSuite := &TestClusterCreateSuite{
		host:              viper.GetString("host"),
		apiKey:            viper.GetString("api_key"),
		prjID:             viper.GetString("prj_id"),
		clusterNamePrefix: viper.GetString("cluster_name_prefix"),

		region:     "regions/aws-us-east-1",
		spendLimit: 1000, // 10 USD
	}

	testSuite.clusterName = testSuite.clusterNamePrefix + randstr.GenWithCharset(4, randstr.AlphabetCharset)
	suite.Run(t, testSuite)
}

type TestClusterCreateSuite struct {
	suite.Suite

	host   string
	apiKey string

	prjID             string
	clusterNamePrefix string

	region      string
	clusterName string
	spendLimit  int32

	serverlessCli *serverlessapi.Cli

	clusterID string
}

func (su *TestClusterCreateSuite) TearDownSuite() {
	if su.clusterID != "" {
		su.serverlessCli.EnsureDeleteCluster(su.prjID, su.clusterName)
	}
}

func (su *TestClusterCreateSuite) Test_01_InitializeClient() {
	var err error
	su.serverlessCli, err = serverlessapi.NewClient(&su.Suite, su.host, su.apiKey)
	su.Require().NoError(err)
	su.Require().NotNil(su.serverlessCli)
}

func (su *TestClusterCreateSuite) Test_02_ListClusters() {
	resp := su.serverlessCli.ListClusters("", "", 10)
	su.Require().NotNil(resp)
}

func (su *TestClusterCreateSuite) Test_03_ListProvidersAndSelectAwsUsEast1() {
	providers := su.serverlessCli.ListProviders()

	r, ok := lo.Find(providers, func(r *model.Commonv1beta1Region) bool {
		return r != nil && r.Name != nil && *r.Name == su.region
	})
	su.Require().True(ok)
	su.Require().NotNil(r.Provider)
}

func (su *TestClusterCreateSuite) Test_04_CreateCluster() {
	su.clusterID = su.serverlessCli.CreateCluster(
		&model.TidbCloudOpenApiserverlessv1beta1Cluster{
			DisplayName: &su.clusterName,
			Region: &model.Commonv1beta1Region{
				Name: &su.region,
			},
			SpendingLimit: &model.ClusterSpendingLimit{
				Monthly: su.spendLimit,
			},
			Labels: map[string]string{
				"tidb.cloud/project": su.prjID,
			},
		},
	)
	su.Require().NotEmpty(su.clusterID)
}

func (su *TestClusterCreateSuite) Test_05_PollClusterStatus() {
	// timeout: 10 minutes (600 seconds)
	for range 60 {
		state := su.serverlessCli.PollClusterStatus(su.clusterID)
		if *state == model.Commonv1beta1ClusterStateACTIVE {
			break
		}
		su.T().Logf("cluster status: %s", *state)
		time.Sleep(10 * time.Second)
	}
}

func (su *TestClusterCreateSuite) Test_06_GetCluster() {
	c := su.serverlessCli.GetCluster(su.clusterID)
	su.Require().NotEmpty(c.ClusterID)
	su.Require().NotEmpty(c.UserPrefix, "userPrefix should not be empty")
	su.Require().Equalf(su.spendLimit, c.SpendingLimit.Monthly, "spendLimit should be equal to %d", su.spendLimit)
}

func (su *TestClusterCreateSuite) Test_07_EnsureDeleteCluster() {
	su.serverlessCli.EnsureDeleteCluster(su.prjID, su.clusterName)
}
