package tests

import (
	"encoding/json"
	"fmt"
	"github.com/pingcap/dbaas/billing2/db/entity"
	"github.com/pingcap/dbaas/billing2/utils/tests/datainit"
	"net/http"
	"testing"

	"github.com/gin-gonic/gin"
	"github.com/pingcap/dbaas/billing2/api"
	"github.com/pingcap/dbaas/billing2/forms"
	"github.com/pingcap/dbaas/billing2/model/creditriskcontrol"
	"github.com/pingcap/dbaas/billing2/utils/ginutils"
	"github.com/pingcap/dbaas/billing2/utils/tests"
	"github.com/shopspring/decimal"
	"github.com/stretchr/testify/suite"
)

var costQuotaModel = &creditriskcontrol.CostQuotaModel{}

type CostQuotaTestSuite struct {
	tests.BillingTestSuite
	router *gin.Engine
}

func (suite *CostQuotaTestSuite) SetupTest() {
	suite.BillingTestSuite.SetupTest()
	suite.router = gin.New()
	suite.router.Use(ginutils.ErrorMiddleWare)
	api.InitializeCostQuotaRouter(ginutils.MyRoute{Route: suite.router})
}

func TestCostQuotaSuite(t *testing.T) {
	suite.Run(t, new(CostQuotaTestSuite))
}

func (suite *CostQuotaTestSuite) TestGetCreditRiskLevelQuota() {
	assert := suite.Assert()
	info, err := creditRiskModel.CreateCreditRiskLevel(&forms.CreditRiskLevel{
		Name: "test",
	})
	assert.NoError(err)
	_, err = costQuotaModel.SetCreditRiskLevelQuota(info.CreditRiskLevelID, &forms.CostQuota{
		CostQuotaLimit: decimal.NewFromInt(100),
	})
	assert.NoError(err)
	w := tests.PerformGetRequest(suite.router, fmt.Sprintf("/credit_risk_levels/%d/cost_quota", info.CreditRiskLevelID))
	assert.Equal(http.StatusOK, w.Code)
	response := forms.CostQuota{}
	err = json.Unmarshal(w.Body.Bytes(), &response)
	assert.Nil(err)
	assert.Equal(response.CostQuotaLimit, decimal.NewFromInt(100))
}

func (suite *CostQuotaTestSuite) TestSetCreditRiskLevelQuota() {
	assert := suite.Assert()
	info, err := creditRiskModel.CreateCreditRiskLevel(&forms.CreditRiskLevel{
		Name: "test",
	})
	assert.NoError(err)
	w := tests.PerformRequest(suite.router, "PUT", fmt.Sprintf("/credit_risk_levels/%d/cost_quota", info.CreditRiskLevelID), &forms.CostQuota{
		CostQuotaLimit: decimal.NewFromInt(100),
	})
	assert.Equal(http.StatusOK, w.Code)
	res, err := costQuotaModel.GetCreditRiskLevelQuota(info.CreditRiskLevelID)
	assert.NoError(err)
	assert.Equal(res.CostQuotaLimit, decimal.NewFromInt(100))
}

func (suite *CostQuotaTestSuite) TestGetTenantQuota() {
	assert := suite.Assert()
	tenantID := uint(1)
	_, err := costQuotaModel.SetTenantCostQuota(tenantID, &forms.CostQuota{
		CostQuotaLimit: decimal.NewFromInt(100),
	})
	datainit.CreateBillingConfig(1, entity.BillingConfigType_DirectCustomer)

	assert.NoError(err)
	w := tests.PerformGetRequest(suite.router, fmt.Sprintf("/tenants/%d/cost_quota", tenantID))
	assert.Equal(http.StatusOK, w.Code)
	response := forms.CostQuota{}
	err = json.Unmarshal(w.Body.Bytes(), &response)
	assert.Nil(err)
	assert.Equal(response.CostQuotaLimit, decimal.NewFromInt(100))
}

func (suite *CostQuotaTestSuite) TestSetTenantQuota() {
	assert := suite.Assert()
	tenantID := uint(1)
	datainit.CreateBillingConfig(1, entity.BillingConfigType_DirectCustomer)

	w := tests.PerformRequest(suite.router, "PUT", fmt.Sprintf("/tenants/%d/cost_quota", tenantID), &forms.CostQuota{
		CostQuotaLimit: decimal.NewFromInt(100),
	})
	assert.Equal(http.StatusOK, w.Code)
	res, err := costQuotaModel.GetTenantCostQuota(tenantID, 1)
	assert.NoError(err)
	assert.Equal(res.CostQuotaLimit, decimal.NewFromInt(100))
}
