package tests

import (
	"testing"
	"time"

	"github.com/pingcap/dbaas/billing2/billing_errors"
	"github.com/pingcap/dbaas/billing2/config"
	"github.com/pingcap/dbaas/billing2/db"
	"github.com/pingcap/dbaas/billing2/db/entity"
	"github.com/pingcap/dbaas/billing2/forms"
	"github.com/pingcap/dbaas/billing2/model/billing"
	"github.com/pingcap/dbaas/billing2/model/payment"
	"github.com/pingcap/dbaas/billing2/utils/panicIf"
	"github.com/pingcap/dbaas/billing2/utils/tests"
	"github.com/pingcap/dbaas/billing2/utils/tests/datainit"
	"github.com/shopspring/decimal"
	"github.com/spf13/viper"
	"github.com/stretchr/testify/suite"
)

var measureModel = &billing.MeasureModel{}

type MeasureTestSuite struct {
	tests.BillingTestSuite
}

func (suite *MeasureTestSuite) SetupTest() {
	suite.BillingTestSuite.SetupTest()
	datainit.CreatePaymentMock(uint(0))
	_, err := (&billing.UnitModel{}).CreateUnit(&forms.UnitInfo{
		UnitKey: "test-unit",
	})
	panicIf.Error(err)
	_, err = (&billing.UnitModel{}).CreateUnit(&forms.UnitInfo{
		UnitKey: "test-only-extra",
	})
	panicIf.Error(err)
}

func TestMeasureSuite(t *testing.T) {
	suite.Run(t, new(MeasureTestSuite))
}

func newPackageNormal(price int64) *forms.PackageInfo {
	return &forms.PackageInfo{
		UnitPrices: forms.UnitPrices{
			"test-unit": {Price: decimal.NewFromInt(price)},
		},
		Discount:      decimal.NewFromInt(1),
		CreditsEnable: false,
	}
}

func newPackageCredits(price, credits int64) *forms.PackageInfo {
	return &forms.PackageInfo{
		UnitPrices: forms.UnitPrices{
			"test-unit": {Price: decimal.NewFromInt(price)},
		},
		Discount:      decimal.NewFromInt(1),
		CreditsEnable: true,
		CreditsOnly:   true,
		Credits:       decimal.NewFromInt(credits),
	}
}

func (suite *MeasureTestSuite) TestMeasureCost() {
	assert := suite.Assert()
	tenantID := uint(0)

	packageInfo := newPackageCredits(1, 100)
	info, _ := (&billing.PackageModel{}).CreatePackage(packageInfo)
	bindedInfo, _ := (&billing.BindedPackageModel{}).BindPackage(tenantID, info.PackageID)
	bindedID := bindedInfo.BindedPackageID
	unitCosts := forms.UnitCosts{
		Unit: "test-unit",
		Cost: 1,
	}
	res, err := measureModel.CostUnits(tenantID, &unitCosts)
	assert.Nil(err)
	assert.Equal(res.BindedPackageID, bindedID)
	assert.Equal(res.PackageID, info.PackageID)
	assert.Equal(res.PackageVersion, info.Version)

	bindedInfo, err = (&billing.BindedPackageModel{}).GetBindedPackage(bindedID)
	assert.Nil(err)
	assert.Equal(bindedInfo.RemainingCredits, decimal.NewFromInt(99))
}

func (suite *MeasureTestSuite) TestMeasureDryrun() {
	assert := suite.Assert()
	tenantID := uint(0)

	packageInfo := newPackageCredits(1, 100)
	info, _ := (&billing.PackageModel{}).CreatePackage(packageInfo)
	bindedInfo, _ := (&billing.BindedPackageModel{}).BindPackage(tenantID, info.PackageID)
	bindedID := bindedInfo.BindedPackageID
	unitCosts := forms.UnitCosts{
		Unit: "test-unit",
		Cost: 100,
	}
	res, err := measureModel.CostUnitsDryrun(tenantID, &unitCosts)
	assert.NoError(err)

	assert.Equal(res.CostPrice, decimal.NewFromInt(100))
	assert.Equal(res.BindedPackageID, bindedID)
	bindedInfo, err = (&billing.BindedPackageModel{}).GetBindedPackage(bindedID)
	assert.NoError(err)
	assert.Equal(bindedInfo.RemainingCredits, decimal.NewFromInt(100))
}

func (suite *MeasureTestSuite) TestMeasureNoCosts() {
	assert := suite.Assert()
	tenantID := uint(0)

	unitCosts := forms.UnitCosts{
		Unit: "test-unit",
		Cost: 0,
	}
	res, err := measureModel.CostUnitsDryrun(tenantID, &unitCosts)
	assert.NoError(err)

	assert.Equal(res.CostPrice, decimal.Zero)
	assert.Equal(res.BindedPackageID, uint(0))
}

func (suite *MeasureTestSuite) TestMeasureDryrunCreditsEmpty() {
	assert := suite.Assert()
	tenantID := uint(0)

	packageInfo := newPackageNormal(1)
	info, _ := (&billing.PackageModel{}).CreatePackage(packageInfo)
	bindedInfo, _ := (&billing.BindedPackageModel{}).BindPackage(tenantID, info.PackageID)
	bindedID := bindedInfo.BindedPackageID
	unitCosts := forms.UnitCosts{
		Unit: "test-unit",
		Cost: 100,
	}
	res, err := measureModel.CostUnitsDryrun(tenantID, &unitCosts)
	assert.NoError(err)

	assert.Equal(res.CostPrice, decimal.NewFromInt(100))
	assert.Equal(res.BindedPackageID, bindedID)
	bindedInfo, err = (&billing.BindedPackageModel{}).GetBindedPackage(bindedID)
	assert.NoError(err)
	assert.Equal(bindedInfo.RemainingCredits, decimal.NewFromInt(0))
}

func (suite *MeasureTestSuite) TestMeasureDryrunCompareWithGlobalPrice() {
	assert := suite.Assert()
	tenantID := uint(0)

	packageInfo := newPackageNormal(2)
	info, _ := (&billing.PackageModel{}).CreatePackage(packageInfo)
	viper.Set(config.GlobalPricePackage, info.PackageID)

	packageInfo = newPackageNormal(2)
	info, _ = (&billing.PackageModel{}).CreatePackage(packageInfo)
	bindedInfo, _ := (&billing.BindedPackageModel{}).BindPackage(tenantID, info.PackageID)
	discount := decimal.RequireFromString("0.5")
	(&billing.BindedPackageModel{}).ChangeBindedDiscount(bindedInfo.BindedPackageID, &forms.ChangeBindedDiscountInput{
		BindedDiscount: &discount,
	})

	bindedID := bindedInfo.BindedPackageID
	unitCosts := forms.UnitCosts{
		Unit: "test-unit",
		Cost: 100,
	}
	res, err := measureModel.CostUnitsDryrun(tenantID, &unitCosts)
	assert.NoError(err)

	assert.Equal(res.CostPrice, decimal.NewFromInt(100))
	assert.Equal(res.BindedPackageID, bindedID)
}

func (suite *MeasureTestSuite) TestMeasureDryrunNoPackage() {
	assert := suite.Assert()
	tenantID := uint(0)

	packageInfo := newPackageCredits(1, 0)
	info, _ := (&billing.PackageModel{}).CreatePackage(packageInfo)
	viper.Set(config.GlobalPricePackage, info.PackageID)
	unitCosts := forms.UnitCosts{
		Unit: "test-unit",
		Cost: 100,
	}
	res, err := measureModel.CostUnitsDryrun(tenantID, &unitCosts)
	assert.NoError(err)

	assert.Equal(res.CostPrice, decimal.NewFromInt(100))
	assert.Equal(res.BindedPackageID, uint(0))
}

func (suite *MeasureTestSuite) TestMeasureDryrunNotEnough() {
	assert := suite.Assert()
	tenantID := uint(0)
	viper.Set(config.GlobalPricePackage, 0)

	unitCosts := forms.UnitCosts{
		Unit: "test-unit",
		Cost: 100,
	}
	_, err := measureModel.CostUnitsDryrun(tenantID, &unitCosts)
	assert.Error(err)
	assert.ErrorIs(err, billing_errors.NotCostableError)
}

func (suite *MeasureTestSuite) TestMeasureCostDiscount() {
	assert := suite.Assert()
	tenantID := uint(0)

	packageInfo := newPackageCredits(1, 100)
	packageInfo.Discount = decimal.NewFromInt(2)
	info, _ := (&billing.PackageModel{}).CreatePackage(packageInfo)
	bindedInfo, _ := (&billing.BindedPackageModel{}).BindPackage(tenantID, info.PackageID)
	bindedID := bindedInfo.BindedPackageID
	unitCosts := forms.UnitCosts{
		Unit: "test-unit",
		Cost: 1,
	}
	_, err := measureModel.CostUnits(tenantID, &unitCosts)
	assert.Nil(err)

	bindedInfo, err = (&billing.BindedPackageModel{}).GetBindedPackage(bindedID)
	assert.Nil(err)
	assert.Equal(bindedInfo.RemainingCredits, decimal.NewFromInt(98))
}

func (suite *MeasureTestSuite) TestMeasureCostWithoutPackageBinded() {
	assert := suite.Assert()
	tenantID := uint(0)
	unitCosts := forms.UnitCosts{
		Unit: "test-unit",
		Cost: 1,
	}
	_, err := measureModel.CostUnits(tenantID, &unitCosts)
	assert.Error(err)
	assert.ErrorIs(err, billing_errors.NotCostableError)
}

func (suite *MeasureTestSuite) TestMeasureCostWithLabels() {
	assert := suite.Assert()
	tenantID := uint(0)

	packageInfo := newPackageCredits(2, 100)

	packageInfo2 := &forms.PackageInfo{
		UnitPrices: forms.UnitPrices{
			"test-unit": {Price: decimal.NewFromInt(1)},
		},
		CreditsEnable: true,
		Discount:      decimal.NewFromInt(1),
		Credits:       decimal.NewFromInt(100),
		Labels: map[string]string{
			"test": "true",
		},
	}

	info1, _ := (&billing.PackageModel{}).CreatePackage(packageInfo)
	info2, _ := (&billing.PackageModel{}).CreatePackage(packageInfo2)
	bindedInfo1, _ := (&billing.BindedPackageModel{}).BindPackage(tenantID, info1.PackageID)
	bindedInfo2, _ := (&billing.BindedPackageModel{}).BindPackage(tenantID, info2.PackageID)
	bindedID1 := bindedInfo1.BindedPackageID
	bindedID2 := bindedInfo2.BindedPackageID

	unitCosts := forms.UnitCosts{
		Unit: "test-unit",
		Cost: 1,
	}

	_, err := measureModel.CostUnits(tenantID, &unitCosts)
	assert.NoError(err)
	bindedInfo1, err = (&billing.BindedPackageModel{}).GetBindedPackage(bindedID1)
	assert.NoError(err)
	assert.Equal(bindedInfo1.RemainingCredits, decimal.NewFromInt(98))
	bindedInfo2, err = (&billing.BindedPackageModel{}).GetBindedPackage(bindedID2)
	assert.NoError(err)
	assert.Equal(bindedInfo2.RemainingCredits, decimal.NewFromInt(100))

	unitCosts = forms.UnitCosts{
		Unit: "test-unit",
		Cost: 1,
		Labels: map[string]string{
			"test": "true",
		},
	}

	_, err = measureModel.CostUnits(tenantID, &unitCosts)
	assert.NoError(err)
	bindedInfo1, err = (&billing.BindedPackageModel{}).GetBindedPackage(bindedID1)
	assert.NoError(err)
	assert.Equal(bindedInfo1.RemainingCredits, decimal.NewFromInt(98))
	bindedInfo2, err = (&billing.BindedPackageModel{}).GetBindedPackage(bindedID2)
	assert.NoError(err)
	assert.Equal(bindedInfo2.RemainingCredits, decimal.NewFromInt(99))
}

func (suite *MeasureTestSuite) TestMeasureCostWithLeastPriceCredits() {
	assert := suite.Assert()
	tenantID := uint(0)

	packageInfo := newPackageCredits(2, 100)

	packageInfo2 := newPackageCredits(1, 100)

	info1, _ := (&billing.PackageModel{}).CreatePackage(packageInfo)
	info2, _ := (&billing.PackageModel{}).CreatePackage(packageInfo2)
	bindedInfo1, _ := (&billing.BindedPackageModel{}).BindPackage(tenantID, info1.PackageID)
	bindedInfo2, _ := (&billing.BindedPackageModel{}).BindPackage(tenantID, info2.PackageID)
	bindedID1 := bindedInfo1.BindedPackageID
	bindedID2 := bindedInfo2.BindedPackageID

	unitCosts := forms.UnitCosts{
		Unit: "test-unit",
		Cost: 1,
	}

	_, err := measureModel.CostUnits(tenantID, &unitCosts)
	assert.NoError(err)
	bindedInfo1, err = (&billing.BindedPackageModel{}).GetBindedPackage(bindedID1)
	assert.NoError(err)
	assert.Equal(bindedInfo1.RemainingCredits, decimal.NewFromInt(100))
	bindedInfo2, err = (&billing.BindedPackageModel{}).GetBindedPackage(bindedID2)
	assert.NoError(err)
	assert.Equal(bindedInfo2.RemainingCredits, decimal.NewFromInt(99))
}

func (suite *MeasureTestSuite) TestMeasureCostWithLeastPricePayments() {
	assert := suite.Assert()
	tenantID := uint(0)

	packageInfo := newPackageNormal(2)

	packageInfo2 := newPackageNormal(1)

	info1, _ := (&billing.PackageModel{}).CreatePackage(packageInfo)
	info2, _ := (&billing.PackageModel{}).CreatePackage(packageInfo2)
	bindedInfo1, _ := (&billing.BindedPackageModel{}).BindPackage(tenantID, info1.PackageID)
	bindedInfo2, _ := (&billing.BindedPackageModel{}).BindPackage(tenantID, info2.PackageID)
	bindedID1 := bindedInfo1.BindedPackageID
	bindedID2 := bindedInfo2.BindedPackageID
	_ = bindedID1
	_ = bindedID2
	unitCosts := forms.UnitCosts{
		Unit: "test-unit",
		Cost: 1,
	}

	info, err := measureModel.CostUnits(tenantID, &unitCosts)
	assert.NoError(err)

	assert.Equal(info.BindedPackageID, bindedID2)

}

func (suite *MeasureTestSuite) TestMeasureCostFail() {
	assert := suite.Assert()
	tenantID := uint(0)

	unitCosts := forms.UnitCosts{
		CostID: "Test",
		Unit:   "test-unit",
		Cost:   3,
	}

	_, err := measureModel.CostUnits(tenantID, &unitCosts)
	assert.Error(err)
	assert.ErrorIs(err, billing_errors.NotCostableError)

	costEntity := &entity.UserUnitCost{}
	err = entity.NewUserUnitCostQuerySet(db.GetDB()).One(costEntity)
	assert.NoError(err)
	assert.Equal(costEntity.Status, entity.UserUnitCostStatus_Failed)

	_, err = measureModel.CostUnits(tenantID, &unitCosts)
	assert.Error(err)
	assert.ErrorIs(err, billing_errors.NotCostableError)
}

func (suite *MeasureTestSuite) TestMeasureCostSummary() {
	assert := suite.Assert()
	costs := []forms.UnitCostSummary{
		{
			Unit:      "TestA1",
			CostPrice: decimal.NewFromInt(1),
			RawPrice:  decimal.NewFromInt(2),
			Labels:    map[string]string{"project": "test1"},
		},
		{
			Unit:      "TestA2",
			CostPrice: decimal.NewFromInt(1),
			RawPrice:  decimal.NewFromInt(2),
			Labels:    map[string]string{"project": "test2"},
		},
		{
			Unit:      "TestB1",
			CostPrice: decimal.NewFromInt(1),
			RawPrice:  decimal.NewFromInt(1),
		},
		{
			Unit:      "TestNo",
			CostPrice: decimal.NewFromInt(1),
			RawPrice:  decimal.NewFromInt(2),
		},
	}
	units := []forms.UnitInfo{
		{
			UnitKey:  "TestA1",
			Category: "TestA",
		},
		{
			UnitKey:  "TestA2",
			Category: "TestA",
		},
		{
			UnitKey:  "TestB1",
			Category: "TestB",
		},
	}
	res := billing.CostSummaryFromUnitCosts(costs, units)
	assert.NotNil(res)
	assert.Equal(res.CostPrice, decimal.NewFromInt(4))
	assert.Len(res.CategoryUnitsCosts, 3)
	assert.Equal(res.CategoryUnitsCosts["TestA"].CostPrice, decimal.NewFromInt(2))
	assert.Equal(res.CategoryUnitsCosts["TestA"].RawPrice, decimal.NewFromInt(4))
	assert.Equal(res.CategoryUnitsCosts["TestB"].CostPrice, decimal.NewFromInt(1))
	assert.Equal(res.CategoryUnitsCosts["TestB"].RawPrice, decimal.NewFromInt(1))
	assert.Equal(res.CategoryUnitsCosts[viper.GetString(config.DefaultUnitCategory)].CostPrice, decimal.NewFromInt(1))
	assert.Equal(res.CategoryUnitsCosts[viper.GetString(config.DefaultUnitCategory)].RawPrice, decimal.NewFromInt(2))
	assert.Equal(res.LabelsUnitsCosts["project"]["test1"].CostPrice, decimal.NewFromInt(1))
	assert.Equal(res.LabelsUnitsCosts["project"]["test1"].RawPrice, decimal.NewFromInt(2))
	assert.Equal(res.LabelsUnitsCosts["project"]["test2"].CostPrice, decimal.NewFromInt(1))
	assert.Equal(res.LabelsUnitsCosts["project"]["test2"].RawPrice, decimal.NewFromInt(2))
	assert.Len(res.LabelsUnitsCosts, 1)
	assert.Len(res.LabelsUnitsCosts["project"], 3)
}

func (suite *MeasureTestSuite) TestMeasureWithDiscountOverride() {
	assert := suite.Assert()
	tenantID := uint(0)

	packageInfo := &forms.PackageInfo{
		UnitPrices: forms.UnitPrices{
			"test-unit": {Price: decimal.NewFromInt(1)},
		},
		Discount:      decimal.NewFromInt(10),
		CreditsEnable: false,
	}

	info1, _ := (&billing.PackageModel{}).CreatePackage(packageInfo)
	bindedInfo1, _ := (&billing.BindedPackageModel{}).BindPackage(tenantID, info1.PackageID)
	bindedID1 := bindedInfo1.BindedPackageID
	_ = bindedID1
	unitCosts := forms.UnitCosts{
		Unit: "test-unit",
		Cost: 1,
	}

	res, err := measureModel.CostUnits(tenantID, &unitCosts)
	assert.NoError(err)
	assert.Equal(res.BindedPackageID, bindedID1)
	assert.Equal(res.CostPrice, decimal.NewFromInt(10))
	assert.Equal(res.RawPrice, decimal.NewFromInt(1))

	(&billing.BindedPackageModel{}).ChangeBindedDiscount(bindedID1, &forms.ChangeBindedDiscountInput{
		BindedDiscount: tests.AddrDecimal(decimal.NewFromInt(15)),
	})
	res, err = measureModel.CostUnits(tenantID, &unitCosts)
	assert.NoError(err)
	assert.Equal(res.CostPrice, decimal.NewFromInt(10))
	assert.Equal(res.RawPrice, decimal.NewFromInt(1))

	(&billing.BindedPackageModel{}).ChangeBindedDiscount(bindedID1, &forms.ChangeBindedDiscountInput{
		BindedDiscount: tests.AddrDecimal(decimal.NewFromInt(5)),
	})
	res, err = measureModel.CostUnits(tenantID, &unitCosts)
	assert.NoError(err)
	assert.Equal(res.CostPrice, decimal.NewFromInt(5))
	assert.Equal(res.RawPrice, decimal.NewFromInt(1))

	(&billing.BindedPackageModel{}).ChangeBindedDiscount(bindedID1, &forms.ChangeBindedDiscountInput{
		BindedDiscount: nil,
	})
	res, err = measureModel.CostUnits(tenantID, &unitCosts)
	assert.NoError(err)
	assert.Equal(res.CostPrice, decimal.NewFromInt(10))
	assert.Equal(res.RawPrice, decimal.NewFromInt(1))
}

func (suite *MeasureTestSuite) TestMeasureCostWithCombine() {
	assert := suite.Assert()
	tenantID := uint(0)

	packageInfo := &forms.PackageInfo{
		UnitPrices: forms.UnitPrices{
			"test-unit": {Price: decimal.NewFromInt(1)},
		},
		Discount:      decimal.NewFromInt(1),
		CreditsEnable: true,
		CreditsOnly:   false,
		Credits:       decimal.NewFromInt(0),
	}

	info1, _ := (&billing.PackageModel{}).CreatePackage(packageInfo)
	bindedInfo1, _ := (&billing.BindedPackageModel{}).BindPackage(tenantID, info1.PackageID)
	bindedID1 := bindedInfo1.BindedPackageID
	_ = bindedID1
	unitCosts := forms.UnitCosts{
		Unit: "test-unit",
		Cost: 3,
	}

	res, err := measureModel.CostUnits(tenantID, &unitCosts)
	assert.NoError(err)
	assert.Equal(res.BindedPackageID, bindedID1)
	assert.Equal(res.ConsumedSource, entity.ConsumedSource_Invoice)
}

func (suite *MeasureTestSuite) TestMeasureCostZeroPrice() {
	assert := suite.Assert()
	tenantID := uint(0)

	packageInfo := newPackageCredits(2, 4)

	packageInfo2 := newPackageNormal(0)

	info1, _ := (&billing.PackageModel{}).CreatePackage(packageInfo)
	info2, _ := (&billing.PackageModel{}).CreatePackage(packageInfo2)
	bindedInfo1, _ := (&billing.BindedPackageModel{}).BindPackage(tenantID, info1.PackageID)
	bindedInfo2, _ := (&billing.BindedPackageModel{}).BindPackage(tenantID, info2.PackageID)
	bindedID1 := bindedInfo1.BindedPackageID
	bindedID2 := bindedInfo2.BindedPackageID
	_ = bindedID1
	_ = bindedID2

	unitCosts := forms.UnitCosts{
		Unit: "test-unit",
		Cost: 3,
	}

	res, err := measureModel.CostUnits(tenantID, &unitCosts)
	assert.NoError(err)
	assert.Equal(res.BindedPackageID, bindedID2)
	assert.Equal(res.ConsumedSource, entity.ConsumedSource_Invoice)
}

func (suite *MeasureTestSuite) TestMeasureCostWithoutPayment() {
	assert := suite.Assert()
	// use not 0 tenant to disable payment
	tenantID := uint(2)

	packageInfo := newPackageNormal(1)

	info1, _ := (&billing.PackageModel{}).CreatePackage(packageInfo)
	bindedInfo1, _ := (&billing.BindedPackageModel{}).BindPackage(tenantID, info1.PackageID)
	bindedID1 := bindedInfo1.BindedPackageID
	_ = bindedID1

	unitCosts := forms.UnitCosts{
		Unit: "test-unit",
		Cost: 3,
	}

	_, err := measureModel.CostUnits(tenantID, &unitCosts)
	assert.Error(err)
	assert.ErrorIs(err, billing_errors.NotCostableError)
}

func (suite *MeasureTestSuite) TestMeasureCostExpressionLabels() {
	assert := suite.Assert()
	tenantID := uint(0)

	packageInfo := &forms.PackageInfo{
		UnitPrices: forms.UnitPrices{
			"test-unit": {Price: decimal.NewFromInt(1)},
		},
		ExpressionLabels: []forms.ExpressionLabel{
			{
				Label:    "label",
				Operator: "<=",
				Value:    "1500",
			},
		},
		Discount:      decimal.NewFromInt(1),
		CreditsEnable: true,
		CreditsOnly:   true,
		Credits:       decimal.NewFromInt(100),
	}

	info1, _ := (&billing.PackageModel{}).CreatePackage(packageInfo)
	bindedInfo1, _ := (&billing.BindedPackageModel{}).BindPackage(tenantID, info1.PackageID)
	bindedID1 := bindedInfo1.BindedPackageID
	_ = bindedID1

	unitCosts := forms.UnitCosts{
		Unit:   "test-unit",
		Cost:   3,
		Labels: map[string]string{},
	}

	_, err := measureModel.CostUnits(tenantID, &unitCosts)
	assert.Error(err)
	assert.ErrorIs(err, billing_errors.NotCostableError)

	unitCosts.Labels["label"] = "2000"
	_, err = measureModel.CostUnits(tenantID, &unitCosts)
	assert.Error(err)
	assert.ErrorIs(err, billing_errors.NotCostableError)

	unitCosts.Labels["label"] = "1000"
	_, err = measureModel.CostUnits(tenantID, &unitCosts)
	assert.NoError(err)
}

func (suite *MeasureTestSuite) TestMeasureCostExtraInfos() {
	assert := suite.Assert()
	tenantID := uint(0)

	packageInfo := &forms.PackageInfo{
		Discount:      decimal.NewFromInt(1),
		CreditsEnable: true,
		CreditsOnly:   true,
		Credits:       decimal.NewFromInt(100),
		UnitPrices: forms.UnitPrices{
			"test-unit": {Price: decimal.NewFromInt(2)},
		},
		ExtraPricingInfos: []forms.PricingInfo{
			{
				Labels: map[string]string{
					"label": "test",
				},
				UnitPrices: forms.UnitPrices{
					"test-unit":       {Price: decimal.NewFromInt(2)},
					"test-only-extra": {Price: decimal.NewFromInt(4)},
				},
				Discount: tests.AddrDecimal(decimal.RequireFromString("0.5")),
			},
		},
	}

	info1, _ := (&billing.PackageModel{}).CreatePackage(packageInfo)
	bindedInfo1, _ := (&billing.BindedPackageModel{}).BindPackage(tenantID, info1.PackageID)
	bindedID1 := bindedInfo1.BindedPackageID
	_ = bindedID1

	unitCosts := forms.UnitCosts{
		Unit:   "test-unit",
		Cost:   1,
		Labels: map[string]string{},
	}

	info, err := measureModel.CostUnits(tenantID, &unitCosts)
	assert.NoError(err)
	assert.Equal(info.CostPrice, decimal.NewFromInt(2))

	unitCosts.Labels["label"] = "test"
	info, err = measureModel.CostUnits(tenantID, &unitCosts)
	assert.NoError(err)
	assert.Equal(info.CostPrice, decimal.NewFromInt(1))
	assert.Equal(info.RawPrice, decimal.NewFromInt(2))

	unitCosts.Unit = "test-only-extra"

	info, err = measureModel.CostUnits(tenantID, &unitCosts)
	assert.NoError(err)
	assert.Equal(info.CostPrice, decimal.NewFromInt(2))

	assert.Equal(info.RawPrice, decimal.NewFromInt(4))
}

func (suite *MeasureTestSuite) TestMeasureCostMultipleFactorLabel() {
	assert := suite.Assert()
	tenantID := uint(0)

	packageInfo := &forms.PackageInfo{
		Discount:      decimal.NewFromInt(1),
		CreditsEnable: true,
		CreditsOnly:   true,
		Credits:       decimal.NewFromInt(100),
		UnitPrices: forms.UnitPrices{
			"test-unit": {
				Price: decimal.NewFromInt(2),
				LabelMultipleFactorPrice: forms.LabelMultipleFactorPrice{
					MultipleFactorLabel:     "iops",
					MultipleFactorThreshold: 30,
				},
			},
		},
	}

	info1, _ := (&billing.PackageModel{}).CreatePackage(packageInfo)
	bindedInfo1, _ := (&billing.BindedPackageModel{}).BindPackage(tenantID, info1.PackageID)
	bindedID1 := bindedInfo1.BindedPackageID
	_ = bindedID1

	unitCosts := forms.UnitCosts{
		Unit:   "test-unit",
		Cost:   1,
		Labels: map[string]string{},
	}

	_, err := measureModel.CostUnits(tenantID, &unitCosts)
	assert.ErrorIs(err, billing_errors.NotCostableError)

	unitCosts.Labels["iops"] = "15"
	info, err := measureModel.CostUnits(tenantID, &unitCosts)
	assert.NoError(err)
	assert.Equal(info.CostPrice, decimal.NewFromInt(0))
	assert.Equal(info.RawPrice, decimal.NewFromInt(0))

	unitCosts.Labels["iops"] = "60"

	info, err = measureModel.CostUnits(tenantID, &unitCosts)
	assert.NoError(err)
	assert.Equal(info.CostPrice, decimal.NewFromInt(60))
	assert.Equal(info.RawPrice, decimal.NewFromInt(60))
}

func (suite *MeasureTestSuite) TestMeasureRemoveUnusedCosts() {
	assert := suite.Assert()
	tenantID := uint(0)

	packageInfo := newPackageCredits(1, 100)
	info, _ := (&billing.PackageModel{}).CreatePackage(packageInfo)
	_, _ = (&billing.BindedPackageModel{}).BindPackage(tenantID, info.PackageID)
	unitCosts := forms.UnitCosts{
		Unit:          "test-unit",
		Cost:          1,
		CostTimeStamp: datainit.BillingDate.Unix(),
	}
	_, err := measureModel.CostUnits(tenantID, &unitCosts)
	assert.NoError(err)

	unitCosts.Unit = "test-unit-no-exists"
	_, err = measureModel.CostUnits(tenantID, &unitCosts)
	assert.Error(err)

	unitCosts.CostTimeStamp = datainit.BillingDate.Unix() - 1
	_, err = measureModel.CostUnits(tenantID, &unitCosts)
	assert.Error(err)

	res, err := (&payment.CostExplorerModel{}).CalculateCost(tenantID, &forms.CostExplorerQuery{
		StartDate: datainit.BillingDate,
		EndDate:   datainit.BillingDate.Add(time.Hour),
	})
	assert.NoError(err)

	cnt, err := entity.NewUserUnitCostQuerySet(db.GetDB()).Count()
	assert.NoError(err)
	assert.EqualValues(cnt, 3)

	err = measureModel.RemoveUnusedCosts(datainit.BillingDate, datainit.BillingDate.Add(time.Hour))
	assert.NoError(err)

	resRemoved, err := (&payment.CostExplorerModel{}).CalculateCost(tenantID, &forms.CostExplorerQuery{
		StartDate: datainit.BillingDate,
		EndDate:   datainit.BillingDate.Add(time.Hour),
	})
	assert.NoError(err)

	assert.Equal(res, resRemoved)

	cnt, err = entity.NewUserUnitCostQuerySet(db.GetDB()).Count()
	assert.NoError(err)
	assert.EqualValues(cnt, 2)
}

func (suite *MeasureTestSuite) TestMeasureMergeCosts() {
	assert := suite.Assert()
	tenantID := uint(0)

	packageInfo := newPackageCredits(1, 100)
	info, _ := (&billing.PackageModel{}).CreatePackage(packageInfo)
	_, _ = (&billing.BindedPackageModel{}).BindPackage(tenantID, info.PackageID)
	unitCosts := forms.UnitCosts{
		Unit:          "test-unit",
		Cost:          1,
		CostTimeStamp: datainit.BillingDate.Unix(),
	}

	for i := range [11]int{} {
		unitCosts.CostTimeStamp = datainit.BillingDate.Unix() + int64(i) - 1
		_, err := measureModel.CostUnits(tenantID, &unitCosts)
		assert.NoError(err)
	}

	unitCosts.Unit = "test-unit-no-exists"
	_, err := measureModel.CostUnits(tenantID, &unitCosts)
	assert.Error(err)

	res, err := (&payment.CostExplorerModel{}).CalculateCost(tenantID, &forms.CostExplorerQuery{
		StartDate: datainit.BillingDate.Add(-time.Hour),
		EndDate:   datainit.BillingDate.Add(time.Hour),
	})
	assert.NoError(err)

	cnt, err := entity.NewUserUnitCostQuerySet(db.GetDB()).StatusEq(entity.UserUnitCostStatus_DONE).Count()
	assert.NoError(err)
	assert.EqualValues(cnt, 11)

	err = measureModel.MergeSmallUnits(datainit.BillingDate, datainit.BillingDate.Add(time.Hour))
	assert.NoError(err)

	resRemoved, err := (&payment.CostExplorerModel{}).CalculateCost(tenantID, &forms.CostExplorerQuery{
		StartDate: datainit.BillingDate.Add(-time.Hour),
		EndDate:   datainit.BillingDate.Add(time.Hour),
	})
	assert.NoError(err)

	assert.Equal(res, resRemoved)

	cnt, err = entity.NewUserUnitCostQuerySet(db.GetDB()).StatusEq(entity.UserUnitCostStatus_DONE).Count()
	assert.NoError(err)
	assert.EqualValues(cnt, 2)
}
