package tests

import (
	"encoding/json"
	"net/http"
	"testing"

	"github.com/pingcap/dbaas/billing2/forms"

	"github.com/gin-gonic/gin"
	"github.com/pingcap/dbaas/billing2/api"
	"github.com/pingcap/dbaas/billing2/utils/ginutils"
	"github.com/pingcap/dbaas/billing2/utils/tests"
	"github.com/stretchr/testify/suite"
)

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

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

func TestSKUGroupsSuite(t *testing.T) {
	suite.Run(t, new(SKUGroupTestSuite))
}

func (suite *SKUGroupTestSuite) TestSKUGroupAPI() {
	assert := suite.Assert()
	//Add
	SKUGroup := forms.SKUGroup{
		UnitKeyPattern: "test",
		Name:           "Name test",
		Category:       "Category Test",
		PriceType:      "Normal",
		MeasureUnit:    "Hrs",
	}

	w := tests.PerformRequest(suite.router, "POST", "/sku_groups", SKUGroup)
	assert.Equal(http.StatusOK, w.Code)
	var response forms.SKUGroup
	err := json.Unmarshal(w.Body.Bytes(), &response)
	assert.Nil(err)
	assert.Equal(response.Category, SKUGroup.Category)
	//list
	var responseList []forms.SKUGroup
	wGetList := tests.PerformGetRequest(suite.router, "/sku_groups")
	assert.Equal(http.StatusOK, wGetList.Code)
	err = json.Unmarshal(wGetList.Body.Bytes(), &responseList)
	assert.Nil(err)
	assert.Equal(responseList[0].Category, SKUGroup.Category)
	//get
	wGet := tests.PerformGetRequest(suite.router, "/sku_groups/1")
	assert.Equal(http.StatusOK, wGet.Code)
	err = json.Unmarshal(wGet.Body.Bytes(), &response)
	assert.Nil(err)
	assert.Equal(response.Category, SKUGroup.Category)

	//update
	SKUGroup.Category = "Category Test Update"
	wUpdate := tests.PerformRequest(suite.router, "PUT", "/sku_groups/1", SKUGroup)
	assert.Equal(http.StatusOK, wUpdate.Code)
	err = json.Unmarshal(wUpdate.Body.Bytes(), &response)
	assert.Nil(err)
	assert.Equal(response.Category, "Category Test Update")

	//Delete
	var res forms.OKType
	wDel := tests.PerformRequest(suite.router, "DELETE", "/sku_groups/1", nil)
	assert.Equal(http.StatusOK, wUpdate.Code)
	err = json.Unmarshal(wDel.Body.Bytes(), &res)
	assert.Nil(err)
	assert.Equal(res.Status, "success")

	//get
	wGet = tests.PerformGetRequest(suite.router, "/sku_groups/1")
	assert.Equal(http.StatusNotFound, wGet.Code)

}

func (suite *SKUGroupTestSuite) TestCategoryItemShowAPI() {
	assert := suite.Assert()

	rootItem := forms.CategoryItemShow{
		Category:     "RootCost",
		ShowKindName: "Root Product",
		OrderMap: map[string]int32{
			"Root Product": 1,
			"RootCost":     2,
		},
	}
	w := tests.PerformRequest(suite.router, "POST", "/sku_groups/category", rootItem)
	assert.Equal(http.StatusOK, w.Code)
	var response forms.CategoryItemShow
	err := json.Unmarshal(w.Body.Bytes(), &response)
	assert.Nil(err)
	assert.Equal(rootItem.Category, response.Category)

	childItem := forms.CategoryItemShow{
		Category:         "ChildCost",
		ParentKey:        "kind:Root Product",
		ShowCategoryName: "Child Group",
		Labels:           map[string]string{"default": "Child Leaf"},
		OrderMap: map[string]int32{
			"Child Group": 3,
			"Child Leaf":  4,
		},
	}
	w = tests.PerformRequest(suite.router, "POST", "/sku_groups/category", childItem)
	assert.Equal(http.StatusOK, w.Code)
	err = json.Unmarshal(w.Body.Bytes(), &response)
	assert.Nil(err)
	assert.Equal("Root Product", response.ShowKindName)

	var tree []*forms.CategoryNode
	w = tests.PerformGetRequest(suite.router, "/sku_groups/category")
	assert.Equal(http.StatusOK, w.Code)
	err = json.Unmarshal(w.Body.Bytes(), &tree)
	assert.Nil(err)
	assert.NotEmpty(tree)
	assert.NotEmpty(tree[0].Key)
	assert.NotEmpty(tree[0].Categories)

	childItem.MeasureUnit = "RU"
	w = tests.PerformRequest(suite.router, "PUT", "/sku_groups/category/ChildCost", childItem)
	assert.Equal(http.StatusOK, w.Code)
	err = json.Unmarshal(w.Body.Bytes(), &response)
	assert.Nil(err)
	assert.Equal("RU", response.MeasureUnit)

	w = tests.PerformGetRequest(suite.router, "/sku_groups/category/ChildCost")
	assert.Equal(http.StatusOK, w.Code)

	w = tests.PerformRequest(suite.router, "DELETE", "/sku_groups/category/ChildCost", nil)
	assert.Equal(http.StatusOK, w.Code)
}
