package oldopenapi

import (
	"strings"
	"testing"
	"time"

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

	"github.com/tidbcloud/tidb-management-service/functional-test/pkg/openapiv1beta"
	"github.com/tidbcloud/tidb-management-service/functional-test/pkg/openapiv1beta/client/cluster"
	"github.com/tidbcloud/tidb-management-service/utilities/randstr"
)

func TestClusterRBAC(t *testing.T) {
	testSuite := &TestClusterRBACSuite{
		host:              viper.GetString("host"),
		apiKey:            viper.GetString("api_key"),
		prjID:             viper.GetString("prj_id"),
		clusterNamePrefix: viper.GetString("cluster_name_prefix"),

		fakeApiKey: "fkke:fakepassword",
		fakePrjID:  "111",

		provider:   "AWS",
		region:     "us-east-1",
		spendLimit: 1000, // 10 USD
	}

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

type TestClusterRBACSuite struct {
	suite.Suite

	host   string
	apiKey string

	fakeApiKey string

	prjID             string
	clusterNamePrefix string

	fakePrjID string

	region      string
	provider    string
	clusterName string
	spendLimit  int32

	openApiCli      *openapiv1beta.Cli
	fakeOpenApisCli *openapiv1beta.Cli

	clusterID string
}

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

func (su *TestClusterRBACSuite) Test_01_InitializeClient() {
	var err error

	keyPair := strings.Split(su.apiKey, ":")
	su.openApiCli, err = openapiv1beta.NewClient(&su.Suite, su.host, keyPair[0], keyPair[1])
	su.Require().NoError(err)
	su.Require().NotNil(su.openApiCli)

	fakeKeyPair := strings.Split(su.fakeApiKey, ":")
	su.fakeOpenApisCli, err = openapiv1beta.NewClient(&su.Suite, su.host, fakeKeyPair[0], fakeKeyPair[1])
	su.Require().NoError(err)
	su.Require().NotNil(su.fakeOpenApisCli)
}

func (su *TestClusterRBACSuite) Test_02_ListCluster_NoPermission() {
	resp, err := su.openApiCli.ListClustersAllowErr(su.fakePrjID)

	su.Require().Error(err, "The error should not be nil")
	su.Require().Nil(resp, "The response should be nil")
	su.Require().Contains(err.Error(), "permission", "The error msg should be contains 'permission'")
	su.Require().Contains(err.Error(), "403", "The error msg should be contains '403'")
}

func (su *TestClusterRBACSuite) Test_03_CreateCluster_NoPermissionProject() {
	resp, err := su.openApiCli.CreateClusterAllowErr(
		su.fakePrjID,
		cluster.CreateClusterBody{
			CloudProvider: lo.ToPtr(su.provider),
			Config:        &cluster.CreateClusterParamsBodyConfig{},
			ClusterType:   lo.ToPtr("DEVELOPER"),
			Name:          lo.ToPtr(su.clusterName),
			Region:        lo.ToPtr(su.region),
		},
	)

	su.Require().Error(err, "The error should not be nil")
	su.Require().Empty(resp, "The response should be nil")
	su.Require().Contains(err.Error(), "permission", "The error msg should be contains 'permission'")
	su.Require().Contains(err.Error(), "403", "The error msg should be contains '403'")
}

func (su *TestClusterRBACSuite) Test_04_CreateCluster() {
	su.clusterID = su.openApiCli.CreateCluster(
		su.prjID,
		cluster.CreateClusterBody{
			CloudProvider: lo.ToPtr(su.provider),
			Config:        &cluster.CreateClusterParamsBodyConfig{},
			ClusterType:   lo.ToPtr("DEVELOPER"),
			Name:          lo.ToPtr(su.clusterName),
			Region:        lo.ToPtr(su.region),
		},
	)
	su.Require().NotEmpty(su.clusterID)
}

func (su *TestClusterRBACSuite) Test_05_PollClusterStatus() {
	// timeout: 30 minutes (1800 seconds)
	for range 180 {
		state := su.openApiCli.PollClusterStatus(su.prjID, su.clusterID)
		if state.ClusterStatus == "AVAILABLE" {
			break
		}
		su.T().Logf("cluster status: %s", state.ClusterStatus)
		time.Sleep(1 * time.Second)
	}
}

func (su *TestClusterRBACSuite) Test_06_GetCluster_NoPermission() {
	resp, err := su.openApiCli.GetClusterAllowErr(su.fakePrjID, su.clusterID)

	su.Require().Error(err, "The error should not be nil")
	su.Require().Empty(resp, "The response should be nil")
	su.Require().Contains(err.Error(), "49900004", "The error msg should be contains '49900004'")
}

func (su *TestClusterRBACSuite) Test_07_DeleteCluster_NoPermission() {
	time.Sleep(3 * time.Second)
	resp, err := su.openApiCli.DeleteClusterAllowErr(su.fakePrjID, su.clusterID)

	su.Require().Error(err, "The error should not be nil")
	su.Require().Empty(resp, "The response should be nil")
	su.Require().Contains(err.Error(), "49900004", "The error msg should be contains '49900004'")
}

func (su *TestClusterRBACSuite) Test_08_ListClusters_NoPermission_Project() {
	resp, err := su.openApiCli.ListClustersAllowErr(su.fakePrjID)

	su.Require().Error(err, "The error should not be nil")
	su.Require().Empty(resp, "The response should be nil")
	su.Require().Contains(err.Error(), "permission", "The error msg should be contains 'permission'")
	su.Require().Contains(err.Error(), "403", "The error msg should be contains '403'")
}
