package instancemetering

import (
	"context"
	"fmt"
	"os"
	"testing"
	"time"

	"github.com/tidbcloud/metering/pkg/common/config"
	"github.com/tidbcloud/metering/pkg/common/constants"
	"github.com/tidbcloud/metering/pkg/errors"

	"github.com/stretchr/testify/assert"
	"github.com/tidbcloud/metering/pkg/common/models"
	"github.com/tidbcloud/metering/pkg/facade"
	"github.com/tidbcloud/metering/test/mockfacade"
	"github.com/tidbcloud/metering/test/mockrepoter"
	"go.uber.org/mock/gomock"
)

func TestBeforeSwitchProcess(t *testing.T) {
	nowTS := billingSwitchTime - 6000
	cachedQueryClusterMetaResult = QueryClusterMetaResult{
		QueryTime: nowTS - 60,
	}

	ctrl := gomock.NewController(t)
	ds := mockfacade.NewMockTiDBClusterMetaQuerier(ctrl)
	facade.MockTiDBClusterMetaQuerier(ds)

	ds.EXPECT().List(gomock.Any(), gomock.Any()).Return([]*models.ClusterMeta{
		{
			TenantID:     "111",
			ProjectID:    "222",
			ClusterID:    "333",
			Cluster:      "aaa",
			DevTier:      false,
			Poc:          true,
			CrossAccount: false,
			Provider:     "aws",
			Region:       "us-west-2",
			State:        2,
			Components: []*models.ComponentMeta{
				{
					ComponentType: "pd",
					Count:         3,
					State:         1,
				},
				{
					ComponentType: "tikv",
					Count:         5,
					State:         1,
				},

				{
					ComponentType: "tidb",
					Count:         2,
					State:         1,
				},
			},
			Timestamp: nowTS,
		},
		{
			TenantID:     "111",
			ProjectID:    "444",
			ClusterID:    "555",
			Cluster:      "bbb",
			DevTier:      false,
			Poc:          true,
			CrossAccount: false,
			Provider:     "aws",
			Region:       "us-west-2",
			State:        2,
			Components: []*models.ComponentMeta{
				{
					ComponentType: "pd",
					Count:         3,
					State:         1,
				},
				{
					ComponentType: "tikv",
					Count:         5,
					State:         1,
				},

				{
					ComponentType: "tidb",
					Count:         1,
					State:         1,
				},
			},
			Timestamp: nowTS,
		},
		{
			TenantID:     "6666",
			ProjectID:    "7777",
			ClusterID:    "8888",
			Cluster:      "cccc",
			DevTier:      false,
			Poc:          true,
			CrossAccount: false,
			Provider:     "azure",
			Region:       "eastus",
			State:        2,
			Components: []*models.ComponentMeta{
				{
					ComponentType: "pd",
					Count:         4,
					State:         1,
				},
				{
					ComponentType: "tikv",
					Count:         7,
					State:         1,
				},

				{
					ComponentType: "tidb",
					Count:         5,
					State:         1,
				},
			},
			Timestamp: nowTS,
		},
		{
			TenantID:     "9999",
			ProjectID:    "9999",
			ClusterID:    "101010",
			Cluster:      "cccc",
			DevTier:      false,
			Poc:          true,
			CrossAccount: false,
			Provider:     "aws",
			Region:       "us-west-2",
			State:        2,
			Components: []*models.ComponentMeta{
				{
					ComponentType: "pd",
					Count:         4,
					State:         1,
				},
				{
					ComponentType: "tikv",
					Count:         7,
					State:         1,
				},

				{
					ComponentType: "tidb",
					Count:         5,
					State:         1,
				},
			},
			Timestamp: nowTS,
		},
		{
			TenantID:     "99999",
			ProjectID:    "666666",
			ClusterID:    "111111",
			Cluster:      "cccc",
			DevTier:      false,
			Poc:          true,
			CrossAccount: false,
			Provider:     "aws",
			Region:       "us-west-2",
			State:        2,
			Components: []*models.ComponentMeta{
				{
					ComponentType: "pd",
					Count:         4,
					State:         1,
				},
				{
					ComponentType: "tikv",
					Count:         7,
					State:         1,
				},

				{
					ComponentType: "tidb",
					Count:         5,
					State:         1,
				},
			},
			Timestamp: nowTS,
		},
		{
			TenantID:     "2222",
			ProjectID:    "32222",
			ClusterID:    "12222",
			Cluster:      "102222",
			DevTier:      false,
			Poc:          true,
			CrossAccount: false,
			Provider:     "aws",
			Region:       "us-west-2",
			State:        2,
			Components: []*models.ComponentMeta{
				{
					ComponentType: "pd",
					Count:         4,
					State:         1,
					NodeSKU:       "[{\"skuName\":\"node:aws:us-west-2:DEPLOY_TYPE_DEDICATED:m5.xlarge\",\"skuValue\":\"1\",\"count\":4}]",
					StoragesSKU:   "",
				},
				{
					ComponentType: "tikv",
					Count:         7,
					State:         1,
					NodeSKU:       "[{\"skuName\":\"node:aws:us-west-2:DEPLOY_TYPE_DEDICATED:m5.2xlarge\",\"skuValue\":\"1\",\"count\":7}]",
					StoragesSKU:   "[{\"skuName\":\"disk-iops:aws:us-west-2:gp2\",\"skuValue\":\"3000\",\"count\":7},{\"skuName\":\"disk-throughput:aws:us-west-2:gp2\",\"skuValue\":\"400\",\"count\":7},{\"skuName\":\"disk-storage:aws:us-west-2:gp2\",\"skuValue\":\"1000\",\"count\":7}]",
				},

				{
					ComponentType: "tidb",
					Count:         5,
					State:         1,
					NodeSKU:       "[{\"skuName\":\"node:aws:us-west-2:DEPLOY_TYPE_DEDICATED:m5.xlarge\",\"skuValue\":\"1\",\"count\":5}]",
					StoragesSKU:   "",
				},
			},
			Timestamp: nowTS,
		},
		{
			TenantID:     "22222",
			ProjectID:    "322222",
			ClusterID:    "122222",
			Cluster:      "1022222",
			DevTier:      false,
			Poc:          true,
			CrossAccount: false,
			Provider:     "aws",
			Region:       "us-west-2",
			State:        2,
			Components: []*models.ComponentMeta{
				{
					ComponentType: "pd",
					Count:         4,
					State:         1,
					NodeSKU:       "[{\"skuName\":\"node:aws:us-west-2:DEPLOY_TYPE_DEDICATED:m5.xlarge\",\"skuValue\":\"1\",\"count\":4}]",
					StoragesSKU:   "",
				},
				{
					ComponentType: "tikv",
					Count:         8,
					State:         1,
					NodeSKU:       "[{\"skuName\":\"node:aws:us-west-2:DEPLOY_TYPE_DEDICATED:m5.2xlarge\",\"skuValue\":\"1\",\"count\":8}]",
					StoragesSKU:   "[{\"skuName\":\"disk-iops:aws:us-west-2:gp2\",\"skuValue\":\"3000\",\"count\":8},{\"skuName\":\"disk-throughput:aws:us-west-2:gp2\",\"skuValue\":\"400\",\"count\":8},{\"skuName\":\"disk-storage:aws:us-west-2:gp2\",\"skuValue\":\"1000\",\"count\":8}]",
				},

				{
					ComponentType: "tidb",
					Count:         5,
					State:         1,
					NodeSKU:       "[{\"skuName\":\"node:aws:us-west-2:DEPLOY_TYPE_DEDICATED:m5.xlarge\",\"skuValue\":\"1\",\"count\":5}]",
					StoragesSKU:   "",
				},
			},
			Timestamp: nowTS,
		},
	}, nil).Times(1)

	err := ExecuteClusterMetaTask(context.TODO(), nowTS)
	assert.NoError(t, err)
	assert.True(t, cachedQueryClusterMetaResult.QueryTime >= nowTS)
	assert.Equal(t, nowTS, cachedQueryClusterMetaResult.Data[2].Timestamp)
	assert.True(t, len(cachedQueryClusterMetaResult.Data[1].TenantID) > 0)
	assert.True(t, len(cachedQueryClusterMetaResult.Data[0].Components) > 0)
	// test if cluster need use cache
	err = ExecuteClusterMetaTask(context.TODO(), nowTS-120)
	assert.NoError(t, err)
	assert.True(t, cachedQueryClusterMetaResult.QueryTime >= nowTS)
	assert.Equal(t, nowTS-120, cachedQueryClusterMetaResult.Data[2].Timestamp)
	assert.True(t, len(cachedQueryClusterMetaResult.Data[2].TenantID) > 0)
	assert.True(t, len(cachedQueryClusterMetaResult.Data[2].Components) > 0)

	err = ExecuteBillingDataTask(context.TODO(), nowTS)
	assert.NoError(t, err)

	ms := mockrepoter.NewMockMeasureSender(ctrl)
	facade.MockMeasureSender(ms)
	ms.EXPECT().SendMeasure(gomock.Any(), gomock.Any()).Return(nil).Times(15)
	err = ExecuteBillingReportTask(context.TODO(), nowTS)
	assert.NoError(t, err)

}

func TestAfterSwitchProcess(t *testing.T) {
	nowTS := billingSwitchTime + 60
	cachedQueryClusterMetaResult = QueryClusterMetaResult{
		QueryTime: nowTS - 60,
	}

	ctrl := gomock.NewController(t)
	ds := mockfacade.NewMockTiDBClusterMetaQuerier(ctrl)
	facade.MockTiDBClusterMetaQuerier(ds)

	ds.EXPECT().List(gomock.Any(), gomock.Any()).Return([]*models.ClusterMeta{
		{
			TenantID:     "111",
			ProjectID:    "222",
			ClusterID:    "333",
			Cluster:      "aaa",
			DevTier:      false,
			Poc:          true,
			CrossAccount: false,
			Provider:     "aws",
			Region:       "us-west-2",
			State:        2,
			Components: []*models.ComponentMeta{
				{
					ComponentType: "pd",
					Count:         3,
					State:         1,
				},
				{
					ComponentType: "tikv",
					Count:         5,
					State:         1,
				},

				{
					ComponentType: "tidb",
					Count:         2,
					State:         1,
				},
			},
			Timestamp: nowTS,
		},
		{
			TenantID:     "111",
			ProjectID:    "444",
			ClusterID:    "555",
			Cluster:      "bbb",
			DevTier:      false,
			Poc:          true,
			CrossAccount: false,
			Provider:     "aws",
			Region:       "us-west-2",
			State:        2,
			Components: []*models.ComponentMeta{
				{
					ComponentType: "pd",
					Count:         3,
					State:         1,
				},
				{
					ComponentType: "tikv",
					Count:         5,
					State:         1,
				},

				{
					ComponentType: "tidb",
					Count:         1,
					State:         1,
				},
			},
			Timestamp: nowTS,
		},
		{
			TenantID:     "6666",
			ProjectID:    "7777",
			ClusterID:    "8888",
			Cluster:      "cccc",
			DevTier:      false,
			Poc:          true,
			CrossAccount: false,
			Provider:     "azure",
			Region:       "eastus",
			State:        2,
			Components: []*models.ComponentMeta{
				{
					ComponentType: "pd",
					Count:         4,
					State:         1,
				},
				{
					ComponentType: "tikv",
					Count:         7,
					State:         1,
				},

				{
					ComponentType: "tidb",
					Count:         5,
					State:         1,
				},
			},
			Timestamp: nowTS,
		},
		{
			TenantID:     "99999",
			ProjectID:    "66666",
			ClusterID:    "88888",
			Cluster:      "ccccc",
			DevTier:      false,
			Poc:          true,
			CrossAccount: false,
			Provider:     "aws",
			Region:       "us-west-2",
			IsScaling:    true,
			State:        2,
			Components: []*models.ComponentMeta{
				{
					ComponentType: "pd",
					Count:         4,
					State:         1,
				},
				{
					ComponentType: "tikv",
					Count:         7,
					State:         1,
				},

				{
					ComponentType: "tidb",
					Count:         5,
					State:         1,
				},
			},
			Timestamp: nowTS,
		}, {
			TenantID:     "2222",
			ProjectID:    "32222",
			ClusterID:    "12222",
			Cluster:      "102222",
			DevTier:      false,
			Poc:          true,
			CrossAccount: false,
			Provider:     "aws",
			Region:       "us-west-2",
			State:        2,
			Components: []*models.ComponentMeta{
				{
					ComponentType: "pd",
					Count:         4,
					State:         1,
					NodeSKU:       "[{\"skuName\":\"node:aws:us-west-2:DEPLOY_TYPE_DEDICATED:m5.xlarge\",\"skuValue\":\"1\",\"count\":4}]",
					StoragesSKU:   "",
				},
				{
					ComponentType: "tikv",
					Count:         7,
					State:         1,
					NodeSKU:       "[{\"skuName\":\"node:aws:us-west-2:DEPLOY_TYPE_DEDICATED:m5.2xlarge\",\"skuValue\":\"1\",\"count\":7}]",
					StoragesSKU:   "[{\"skuName\":\"disk-iops:aws:us-west-2:gp2\",\"skuValue\":\"3000\",\"count\":7},{\"skuName\":\"disk-throughput:aws:us-west-2:gp2\",\"skuValue\":\"400\",\"count\":7},{\"skuName\":\"disk-storage:aws:us-west-2:gp2\",\"skuValue\":\"1000\",\"count\":7}]",
				},

				{
					ComponentType: "tidb",
					Count:         5,
					State:         1,
					NodeSKU:       "[{\"skuName\":\"node:aws:us-west-2:DEPLOY_TYPE_DEDICATED:m5.xlarge\",\"skuValue\":\"1\",\"count\":5}]",
					StoragesSKU:   "",
				},
			},
			Timestamp: nowTS,
		},
		{
			TenantID:     "22222",
			ProjectID:    "322222",
			ClusterID:    "122222",
			Cluster:      "1022222",
			DevTier:      false,
			Poc:          true,
			CrossAccount: false,
			Provider:     "aws",
			Region:       "us-west-2",
			State:        2,
			Components: []*models.ComponentMeta{
				{
					ComponentType: "pd",
					Count:         4,
					State:         1,
					NodeSKU:       "[{\"skuName\":\"node:aws:us-west-2:DEPLOY_TYPE_DEDICATED:m5.xlarge\",\"skuValue\":\"1\",\"count\":4}]",
					StoragesSKU:   "",
				},
				{
					ComponentType: "tikv",
					Count:         8,
					State:         1,
					NodeSKU:       "[{\"skuName\":\"node:aws:us-west-2:DEPLOY_TYPE_DEDICATED:m5.2xlarge\",\"skuValue\":\"1\",\"count\":8}]",
					StoragesSKU:   "[{\"skuName\":\"disk-iops:aws:us-west-2:gp2\",\"skuValue\":\"3000\",\"count\":8},{\"skuName\":\"disk-throughput:aws:us-west-2:gp2\",\"skuValue\":\"400\",\"count\":8},{\"skuName\":\"disk-storage:aws:us-west-2:gp2\",\"skuValue\":\"1000\",\"count\":8}]",
				},

				{
					ComponentType: "tidb",
					Count:         5,
					State:         1,
					NodeSKU:       "[{\"skuName\":\"node:aws:us-west-2:DEPLOY_TYPE_DEDICATED:m5.xlarge\",\"skuValue\":\"1\",\"count\":5}]",
					StoragesSKU:   "",
				},
			},
			Timestamp: nowTS,
		},
	}, nil).Times(1)

	ds.EXPECT().Detail(gomock.Any(), gomock.Any(), gomock.Any()).Return([]*models.ComponentMeta{
		{
			ComponentType: "pd",
			Count:         4,
		},
		{
			ComponentType: "tikv",
			InstanceType:  "m5.2xlarge",
			Count:         7,
		},
		{
			ComponentType: "tikv",
			InstanceType:  "m5.4xlarge",
			Count:         3,
		},
		{
			ComponentType: "tidb",
			Count:         5,
		},
	}, nil).Times(1)

	err := ExecuteClusterMetaTask(context.TODO(), nowTS)
	assert.NoError(t, err)
	assert.True(t, cachedQueryClusterMetaResult.QueryTime >= nowTS)
	assert.Equal(t, nowTS, cachedQueryClusterMetaResult.Data[2].Timestamp)
	assert.True(t, len(cachedQueryClusterMetaResult.Data[0].TenantID) > 0)
	assert.True(t, len(cachedQueryClusterMetaResult.Data[0].Components) > 0)

	err = ExecuteBillingDataTask(context.TODO(), nowTS)
	assert.NoError(t, err)

	ms := mockrepoter.NewMockMeasureSender(ctrl)
	facade.MockMeasureSender(ms)
	ms.EXPECT().SendMeasure(gomock.Any(), gomock.Any()).Return(nil).Times(25)
	err = ExecuteBillingReportTask(context.TODO(), nowTS)
	assert.NoError(t, err)
}

func TestExecuteBillingDataTask_error(t *testing.T) {

	ctrl := gomock.NewController(t)
	ew := mockfacade.NewMockCheckpointReaderWriter(ctrl)
	facade.MockCheckpointReaderWriter(ew)

	ds := mockfacade.NewMockScheduleTaskDataSync(ctrl)
	facade.MockScheduleTaskDataSync(ds)
	ds.EXPECT().Download(gomock.Any(), gomock.Any(), gomock.Any()).Return("/test/test.sqlite", errors.New(errors.S3Error, "")).AnyTimes()

	timestamp := int64(11111)
	err := ExecuteBillingDataTask(context.TODO(), timestamp)
	assert.Error(t, err)

	clusterMetaFile := fmt.Sprintf("%s/%d.%s", fmt.Sprintf("%s/%s/%s", constants.LocalDataRoot, constants.S3DataPrefix, constants.ClusterMetaTaskName), timestamp, "sqlite")
	os.MkdirAll(clusterMetaFile, 0755)
	err = ExecuteBillingDataTask(context.TODO(), timestamp)
	assert.Error(t, err)
}

func TestExecuteClusterMetaTaskCache(t *testing.T) {
	nowTS := time.Now().Unix()
	cachedQueryClusterMetaResult = QueryClusterMetaResult{
		QueryTime: nowTS - 60,
		Data: []models.ClusterMeta{
			{
				TenantID:     "111",
				ProjectID:    "222",
				ClusterID:    "333",
				Cluster:      "aaa",
				DevTier:      false,
				Poc:          true,
				CrossAccount: false,
				Provider:     "aws",
				Region:       "us-west-2",
				Components: []*models.ComponentMeta{
					{
						ComponentType: "pd",
						Count:         3,
					},
					{
						ComponentType: "tikv",
						Count:         5,
					},

					{
						ComponentType: "tidb",
						Count:         2,
					},
				},
				Timestamp: nowTS - 60,
			},
			{
				TenantID:     "111",
				ProjectID:    "444",
				ClusterID:    "555",
				Cluster:      "bbb",
				DevTier:      false,
				Poc:          true,
				CrossAccount: false,
				Provider:     "aws",
				Region:       "us-west-2",
				Components: []*models.ComponentMeta{
					{
						ComponentType: "pd",
						Count:         3,
					},
					{
						ComponentType: "tikv",
						Count:         5,
					},

					{
						ComponentType: "tidb",
						Count:         1,
					},
				},
				Timestamp: nowTS - 60,
			},
			{
				TenantID:     "6666",
				ProjectID:    "7777",
				ClusterID:    "8888",
				Cluster:      "cccc",
				DevTier:      false,
				Poc:          true,
				CrossAccount: false,
				Provider:     "azure",
				Region:       "eastus",
				Components: []*models.ComponentMeta{
					{
						ComponentType: "pd",
						Count:         4,
					},
					{
						ComponentType: "tikv",
						Count:         7,
					},

					{
						ComponentType: "tidb",
						Count:         5,
					},
				},
				Timestamp: nowTS - 60,
			},
		},
	}
	assert.NoError(t, ExecuteClusterMetaTask(context.TODO(), nowTS-120))
	assert.NoError(t, ExecuteClusterMetaTask(context.TODO(), nowTS-60))
	assert.Equal(t, nowTS-60, cachedQueryClusterMetaResult.QueryTime)

}

func Test_ensureBilling(t *testing.T) {
	ts := time.Now().Unix()

	ctrl := gomock.NewController(t)
	ds := mockfacade.NewMockScheduleTaskDataSync(ctrl)
	facade.MockScheduleTaskDataSync(ds)

	ds.EXPECT().Download(gomock.Any(), gomock.Any(), gomock.Any()).Return("", nil).Times(2)

	s1, err := EnsureBilling(context.TODO(), ts)
	assert.NoError(t, err)

	s2, err := EnsureBilling(context.TODO(), ts)
	assert.NoError(t, err)

	assert.Equal(t, s1, s2)
}

func Test_ensureBilling_error(t *testing.T) {
	ts := time.Now().Unix()

	ctrl := gomock.NewController(t)
	ds := mockfacade.NewMockScheduleTaskDataSync(ctrl)
	facade.MockScheduleTaskDataSync(ds)

	ds.EXPECT().Download(gomock.Any(), gomock.Any(), gomock.Any()).Return("", errors.New(errors.S3Error, "")).AnyTimes()

	_, err := EnsureBilling(context.TODO(), ts)
	assert.Error(t, err)
}

func Test_ensureMeta(t *testing.T) {
	ts := time.Now().Unix()

	ctrl := gomock.NewController(t)
	ds := mockfacade.NewMockScheduleTaskDataSync(ctrl)
	facade.MockScheduleTaskDataSync(ds)

	ds.EXPECT().Download(gomock.Any(), gomock.Any(), gomock.Any()).Return("", nil).AnyTimes()

	s1, err := EnsureMeta(context.TODO(), ts)
	assert.NoError(t, err)

	s2, err := EnsureMeta(context.TODO(), ts)
	assert.NoError(t, err)

	assert.Equal(t, s1, s2)
}

func Test_ensureMeta_error(t *testing.T) {
	ts := time.Now().Unix()

	ctrl := gomock.NewController(t)
	ds := mockfacade.NewMockScheduleTaskDataSync(ctrl)
	facade.MockScheduleTaskDataSync(ds)

	ds.EXPECT().Download(gomock.Any(), gomock.Any(), gomock.Any()).Return("", errors.New(errors.S3Error, "")).AnyTimes()

	_, err := EnsureMeta(context.TODO(), ts)
	assert.Error(t, err)

}

func Test_skipRepoterBlockList(t *testing.T) {
	oldcfg := config.GetConfig()
	defer config.Init(oldcfg)
	repoter := models.BillingReport{
		TenantID:      111,
		CostID:        "222",
		Cost:          100,
		CostTimestamp: 1234567890,
		Labels:        `{"key":"value"}`,
		Unit:          "tiproxy:aws:us-west-2:DEPLOY_TYPE_DEDICATED:m5.xlarge",
	}
	config.Init(config.ServiceConfig{
		LogLevel: "debug",
		InstanceMeteringConfig: &config.InstanceMeteringConfig{
			BillingReportSwitchTime: 1234567890,
			TenantBlockListFullSwitchTime: []config.TenantFilter{
				{
					TenantId:   "1111",
					SwitchTime: 1234567890,
				},
				{
					TenantId:   "111",
					SwitchTime: 1234567891, //block 111 tenant
				},
			},
		},
	})
	ok, err := skipRepoter(1234567890, &repoter)
	assert.NoError(t, err)
	assert.Equal(t, true, ok)
	ok, err = skipRepoter(1234567891, &repoter)
	assert.NoError(t, err)
	assert.Equal(t, false, ok)
	// test repoterv2
	repoterv2 := models.BillingReportV2{
		TenantID:      111,
		CostID:        "222",
		Cost:          100,
		CostTimestamp: 1234567890,
		Labels:        `{"key":"value"}`,
		Unit:          "tiproxy:aws:us-west-2:DEPLOY_TYPE_DEDICATED:m5.xlarge",
		UnitValue:     "1",
	}
	ok, err = skipRepoterV2(1234567890, &repoterv2)
	assert.NoError(t, err)
	assert.Equal(t, true, ok)
	ok, err = skipRepoterV2(1234567891, &repoterv2)
	assert.NoError(t, err)
	assert.Equal(t, false, ok)
}

func Test_newSkuBlockList(t *testing.T) {
	oldcfg := config.GetConfig()
	defer config.Init(oldcfg)
	repoters := []*models.BillingReport{{
		TenantID:      111,
		CostID:        "222",
		Cost:          100,
		CostTimestamp: 1234567890,
		Labels:        `{"key":"value"}`,
		Unit:          "node:aws:us-west-2:DEPLOY_TYPE_DEDICATED:m5.xlarge",
	}, {
		TenantID:      1111,
		CostID:        "333",
		Cost:          100,
		CostTimestamp: 1234567890,
		Labels:        `{"key":"value"}`,
		Unit:          "node:aws:us-west-2:DEPLOY_TYPE_DEDICATED:m6.xlarge",
	}, {
		TenantID:      111,
		CostID:        "444",
		Cost:          100,
		CostTimestamp: 1234567890,
		Labels:        `{"key":"value"}`,
		Unit:          "disk-iops:aws:us-west-2:DEPLOY_TYPE_DEDICATED:m5.xlarge",
	}, {
		TenantID:      1111,
		CostID:        "222",
		Cost:          100,
		CostTimestamp: 1234567890,
		Labels:        `{"key":"value"}`,
		Unit:          "disk-iops:aws:us-west-2:DEPLOY_TYPE_DEDICATED:m6.xlarge",
	}}
	// test repoterv2
	repoterv2s := []*models.BillingReportV2{{
		TenantID:      111,
		CostID:        "222",
		Cost:          100,
		CostTimestamp: 1234567890,
		Labels:        `{"key":"value"}`,
		Unit:          "node:aws:us-west-2:DEPLOY_TYPE_DEDICATED:m5.xlarge",
		UnitValue:     "1",
	}, {
		TenantID:      1111,
		CostID:        "333",
		Cost:          100,
		CostTimestamp: 1234567890,
		Labels:        `{"key":"value"}`,
		Unit:          "node:aws:us-west-2:DEPLOY_TYPE_DEDICATED:m6.xlarge",
		UnitValue:     "1",
	}, {
		TenantID:      111,
		CostID:        "333",
		Cost:          100,
		CostTimestamp: 1234567890,
		Labels:        `{"key":"value"}`,
		Unit:          "disk-iops:aws:us-west-2:DEPLOY_TYPE_DEDICATED:m5.xlarge",
		UnitValue:     "1",
	}, {
		TenantID:      1111,
		CostID:        "333",
		Cost:          100,
		CostTimestamp: 1234567890,
		Labels:        `{"key":"value"}`,
		Unit:          "disk-iops:aws:us-west-2:DEPLOY_TYPE_DEDICATED:m6.xlarge",
		UnitValue:     "1",
	}}
	config.Init(config.ServiceConfig{
		LogLevel: "debug",
		InstanceMeteringConfig: &config.InstanceMeteringConfig{
			BillingReportSwitchTime: 1234567890,
			FeatureGateFilter: map[string]config.FeatureGateFilter{
				constants.FeatureGateNewSKU: {
					FullSwitchTime: 1234567890,
				},
				constants.FeatureGateNewSKUDouble: {
					FullSwitchTime: 1234567890,
				},
				constants.FeatureGateNewSKUDisabled: {
					FullSwitchTime: 1999999999,
					Tenants: []config.TenantFilter{
						{
							TenantId:   "111",
							SwitchTime: 1234567888,
						},
					},
				},
			},
		},
	})
	results, err := ChooseBillingReporterVersion(1234567890, repoters, repoterv2s)
	assert.NoError(t, err)
	assert.Equal(t, 5, len(results))
	// disabled tenat  repote old node sku
	billingReport, ok := results[0].(*models.BillingReport)
	if ok {
		assert.Equal(t, "node:aws:us-west-2:DEPLOY_TYPE_DEDICATED:m5.xlarge", billingReport.Unit)
	} else {
		assert.Fail(t, "Unexpected type *models.BillingReportV2")
	}
	//  disabled tenat  repote old  disk sku
	billingReport, ok = results[1].(*models.BillingReport)
	if ok {
		assert.Equal(t, "disk-iops:aws:us-west-2:DEPLOY_TYPE_DEDICATED:m5.xlarge", billingReport.Unit)
	} else {
		assert.Fail(t, "Unexpected type *models.BillingReportV2")
	}
	// not disabled double tenat  double repoter disk sku for old
	billingReport, ok = results[2].(*models.BillingReport)
	if ok {
		assert.Equal(t, "disk-iops:aws:us-west-2:DEPLOY_TYPE_DEDICATED:m6.xlarge", billingReport.Unit)
	} else {
		assert.Fail(t, "Unexpected type *models.BillingReport")
	}
	// not disabled double tenat  double repoter node sku for new
	billingReportV2, ok := results[3].(*models.BillingReportV2)
	if ok {
		assert.Equal(t, "node:aws:us-west-2:DEPLOY_TYPE_DEDICATED:m6.xlarge", billingReportV2.Unit)
	} else {
		assert.Fail(t, "Unexpected type *models.BillingReportV2")
	}
	// not disabled double tenat  double repoter disk sku for new
	billingReportV2, ok = results[4].(*models.BillingReportV2)
	if ok {
		assert.Equal(t, "disk-iops:aws:us-west-2:DEPLOY_TYPE_DEDICATED:m6.xlarge", billingReportV2.Unit)
	} else {
		assert.Fail(t, "Unexpected type *models.BillingReportV2")
	}
}

func Test_newSkuDisableDoubleBlockList(t *testing.T) {
	oldcfg := config.GetConfig()
	defer config.Init(oldcfg)
	repoters := []*models.BillingReport{{
		TenantID:      111,
		CostID:        "222",
		Cost:          100,
		CostTimestamp: 1234567890,
		Labels:        `{"key":"value"}`,
		Unit:          "node:aws:us-west-2:DEPLOY_TYPE_DEDICATED:m5.xlarge",
	}, {
		TenantID:      111,
		CostID:        "222",
		Cost:          100,
		CostTimestamp: 1234567890,
		Labels:        `{"key":"value"}`,
		Unit:          "disk-iops:aws:us-west-2:DEPLOY_TYPE_DEDICATED:m5.xlarge",
	}, {
		TenantID:      1111,
		CostID:        "333",
		Cost:          100,
		CostTimestamp: 1234567890,
		Labels:        `{"key":"value"}`,
		Unit:          "node:aws:us-west-2:DEPLOY_TYPE_DEDICATED:m6.xlarge",
	}, {
		TenantID:      1111,
		CostID:        "222",
		Cost:          100,
		CostTimestamp: 1234567890,
		Labels:        `{"key":"value"}`,
		Unit:          "disk-iops:aws:us-west-2:DEPLOY_TYPE_DEDICATED:m6.xlarge",
	}}
	// test repoterv2
	repoterv2s := []*models.BillingReportV2{{
		TenantID:      111,
		CostID:        "222",
		Cost:          100,
		CostTimestamp: 1234567890,
		Labels:        `{"key":"value"}`,
		Unit:          "node:aws:us-west-2:DEPLOY_TYPE_DEDICATED:m5.xlarge",
		UnitValue:     "1",
	}, {
		TenantID:      1111,
		CostID:        "333",
		Cost:          100,
		CostTimestamp: 1234567890,
		Labels:        `{"key":"value"}`,
		Unit:          "node:aws:us-west-2:DEPLOY_TYPE_DEDICATED:m6.xlarge",
		UnitValue:     "1",
	}, {
		TenantID:      111,
		CostID:        "333",
		Cost:          100,
		CostTimestamp: 1234567890,
		Labels:        `{"key":"value"}`,
		Unit:          "disk-iops:aws:us-west-2:DEPLOY_TYPE_DEDICATED:m5.xlarge",
		UnitValue:     "1",
	}, {
		TenantID:      1111,
		CostID:        "333",
		Cost:          100,
		CostTimestamp: 1234567890,
		Labels:        `{"key":"value"}`,
		Unit:          "disk-iops:aws:us-west-2:DEPLOY_TYPE_DEDICATED:m6.xlarge",
		UnitValue:     "1",
	}}
	config.Init(config.ServiceConfig{
		LogLevel: "debug",
		InstanceMeteringConfig: &config.InstanceMeteringConfig{
			BillingReportSwitchTime: 1234567890,
			FeatureGateFilter: map[string]config.FeatureGateFilter{
				constants.FeatureGateNewSKU: {
					FullSwitchTime: 1234567890,
				},
				constants.FeatureGateNewSKUDouble: {
					FullSwitchTime: 1234567790,
				},
				constants.FeatureGateNewSKUDoubleDisabled: {
					FullSwitchTime: 1234567890,
				},
				constants.FeatureGateNewSKUDisabled: {
					FullSwitchTime: 1999999999,
					Tenants: []config.TenantFilter{
						{
							TenantId:   "111",
							SwitchTime: 1234567888,
						},
					},
				},
			},
		},
	})
	results, err := ChooseBillingReporterVersion(1234567890, repoters, repoterv2s)
	assert.NoError(t, err)
	assert.Equal(t, 4, len(results))
	// disabled tenat  repote old sku
	billingReport, ok := results[0].(*models.BillingReport)
	if ok {
		assert.Equal(t, "node:aws:us-west-2:DEPLOY_TYPE_DEDICATED:m5.xlarge", billingReport.Unit)
	} else {
		assert.Fail(t, "Unexpected type *models.BillingReportV2")
	}
	// disabled tenat ignore new sku double disabled
	billingReport, ok = results[1].(*models.BillingReport)
	if ok {
		assert.Equal(t, "disk-iops:aws:us-west-2:DEPLOY_TYPE_DEDICATED:m5.xlarge", billingReport.Unit)
	} else {
		assert.Fail(t, "Unexpected type *models.BillingReportV2")
	}
	// not disabled double tenat  double repoter node sku for new
	billingReportV2, ok := results[2].(*models.BillingReportV2)
	if ok {
		assert.Equal(t, "node:aws:us-west-2:DEPLOY_TYPE_DEDICATED:m6.xlarge", billingReportV2.Unit)
	} else {
		assert.Fail(t, "Unexpected type *models.BillingReportV2")
	}
	// not disabled double tenat  double repoter disk sku for new
	billingReportV2, ok = results[3].(*models.BillingReportV2)
	if ok {
		assert.Equal(t, "disk-iops:aws:us-west-2:DEPLOY_TYPE_DEDICATED:m6.xlarge", billingReportV2.Unit)
	} else {
		assert.Fail(t, "Unexpected type *models.BillingReportV2")
	}
}
