package tests

import (
	"encoding/json"
	"github.com/gin-gonic/gin"
	"github.com/pingcap/dbaas/billing2/api"
	"github.com/pingcap/dbaas/billing2/forms"
	"github.com/pingcap/dbaas/billing2/utils/ginutils"
	"github.com/pingcap/dbaas/billing2/utils/pp"
	"github.com/pingcap/dbaas/billing2/utils/tests"
	"github.com/shopspring/decimal"
	"github.com/stretchr/testify/suite"
	"net/http"
	"testing"
)

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

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

}

func TestCommodityTestSuite(t *testing.T) {
	suite.Run(t, new(CommodityTestSuite))

}

func (suite *CommodityTestSuite) TestCreateCommodity() {
	assert := suite.Assert()
	commodityForm := &forms.Commodity{
		CommodityCode:     "Tidb",
		CommodityShowName: "TidbPingCap",
		CommodityType:     "inner",
		Owner:             "JiuShi",
		ModifierAndCreator: forms.ModifierAndCreator{
			Modifier: "XiaoWu",
			Creator:  "Wang",
			Describe: "Test-test",
		},
	}
	w := tests.PerformRequest(suite.router, "POST", "/create_commodity", commodityForm)
	assert.Equal(http.StatusOK, w.Code)

}

func (suite *CommodityTestSuite) TestAddCommodityDimension() {
	assert := suite.Assert()
	dimensionForm := &forms.CommodityDimension{
		CommodityCode:     "Tidb",
		DimensionShowName: "TidbPingCap",
		DimensionCode:     "region",
		DimensionValue:    map[string]string{"ss": "s"},
		IsShare:           false,
		IsCharge:          false,
		ModifierAndCreator: forms.ModifierAndCreator{
			Modifier: "XiaoWu",
			Creator:  "Wang",
			Describe: "Test-test",
		},
	}
	//dimensionForm.DimensionValue["region"] = "ss"

	w := tests.PerformRequest(suite.router, "POST", "/add_commodity_dimension", dimensionForm)
	assert.Equal(http.StatusOK, w.Code)

}

func (suite *CommodityTestSuite) TestAddCommodityEdition() {
	assert := suite.Assert()
	editionForm := &forms.CommodityEdition{
		CommodityCode:   "Tidb",
		EditionCode:     "testTidb",
		EditionShowName: "sss-test",
		EditionDimensionValue: forms.EditionDimensionValue{"Edition-1": {"region": {"west": "1"}, "provider": {"aws": "1"}},
			"Edition-2": {"region": {"west2": "2"}, "provider": {"gcp": "3"}},
		},

		ModifierAndCreator: forms.ModifierAndCreator{
			Modifier: "XiaoWu",
			Creator:  "Wang",
			Describe: "Test-test",
		},
	}
	//dimensionForm.DimensionValue["region"] = "ss"

	w := tests.PerformRequest(suite.router, "POST", "/add_commodity_edition", editionForm)
	assert.Equal(http.StatusOK, w.Code)

}
func (suite *CommodityTestSuite) TestAddSkuTemplate() {
	assert := suite.Assert()
	skuTemplateForm := &forms.SkuTemplate{
		CommodityCode: "Tidb",
		EditionCode:   "testTidb",
		Template:      map[string]string{"Template-1": "aws:region:"},

		ModifierAndCreator: forms.ModifierAndCreator{
			Modifier: "XiaoWu",
			Creator:  "Wang",
			Describe: "Test-test",
		},
	}

	w := tests.PerformRequest(suite.router, "POST", "/add_sku_template", skuTemplateForm)
	assert.Equal(http.StatusOK, w.Code)

}
func (suite *CommodityTestSuite) TestAddSkuList() {
	assert := suite.Assert()
	formList := &[]forms.SkuInfo{
		{UnitKey: "key-1",
			Description:   "test",
			Category:      "t-Category",
			Provider:      "t-Provider",
			Region:        "HongKong",
			Price:         decimal.NewFromInt(1),
			EditionCode:   "tidb",
			CommodityCode: "tidb",
			MeasureUnit:   "H-G",
			SkuTemplateID: 2,
			ModifierAndCreator: forms.ModifierAndCreator{
				Modifier: "XiaoWu",
				Creator:  "Wang",
				Describe: "Test-test",
			},
		},
		{UnitKey: "key-s1",
			Description:   "test",
			Category:      "t-Category",
			Provider:      "t-Provider",
			Region:        "HongKong",
			Price:         decimal.NewFromInt(1),
			EditionCode:   "tidb",
			CommodityCode: "tidb",
			MeasureUnit:   "H-G",
			SkuTemplateID: 2,
			ModifierAndCreator: forms.ModifierAndCreator{
				Modifier: "XiaoWu",
				Creator:  "Wang",
				Describe: "Test-test",
			},
		},
	}

	w := tests.PerformRequest(suite.router, "POST", "/add_sku_list", formList)
	assert.Equal(http.StatusOK, w.Code)

}
func (suite *CommodityTestSuite) TestQueryCommodities() {

	suite.TestCreateCommodity()
	assert := suite.Assert()
	commodityQueryForm := &forms.CommodityQuery{
		//optional
		CommodityCode: "Tidb",
	}

	w := tests.PerformRequest(suite.router, "GET", "/query_commodities", commodityQueryForm)

	assert.Equal(http.StatusOK, w.Code, w.Body.String())
	res := &[]forms.Commodity{}
	assert.NoError(json.Unmarshal(w.Body.Bytes(), res))
	assert.Equal("Tidb", (*res)[0].CommodityCode)
	pp.Print(res)

	commodityQueryForm = &forms.CommodityQuery{
		//optional
		CommodityCode: "Tidb1",
	}

	w = tests.PerformRequest(suite.router, "GET", "/query_commodities", commodityQueryForm)

	assert.Equal(http.StatusOK, w.Code, w.Body.String())
	res = &[]forms.Commodity{}
	assert.NoError(json.Unmarshal(w.Body.Bytes(), res))
	assert.Equal(0, len(*res))

	commodityQueryForm = &forms.CommodityQuery{
		//optional
		CommodityShowName: "TidbPingCap",
	}

	w = tests.PerformRequest(suite.router, "GET", "/query_commodities", commodityQueryForm)

	assert.Equal(http.StatusOK, w.Code, w.Body.String())
	res = &[]forms.Commodity{}
	assert.NoError(json.Unmarshal(w.Body.Bytes(), res))
	assert.Equal("Tidb", (*res)[0].CommodityCode)
}

func (suite *CommodityTestSuite) TestQueryCommodityDimensions() {

	suite.TestAddCommodityDimension()
	assert := suite.Assert()
	DimensionQueryForm := &forms.CommodityDimensionQuery{
		//optional
		CommodityCode: "Tidb",
	}

	w := tests.PerformRequest(suite.router, "GET", "/query_commodity_dimensions", DimensionQueryForm)

	assert.Equal(http.StatusOK, w.Code, w.Body.String())
	res := &[]forms.CommodityDimension{}
	assert.NoError(json.Unmarshal(w.Body.Bytes(), res))
	assert.Equal("region", (*res)[0].DimensionCode)

	DimensionQueryForm = &forms.CommodityDimensionQuery{
		//optional
		CommodityCode: "Tidb1",
	}

	w = tests.PerformRequest(suite.router, "GET", "/query_commodity_dimensions", DimensionQueryForm)

	assert.Equal(http.StatusOK, w.Code, w.Body.String())
	res = &[]forms.CommodityDimension{}
	assert.NoError(json.Unmarshal(w.Body.Bytes(), res))
	assert.Equal(0, len(*res))

	DimensionQueryForm = &forms.CommodityDimensionQuery{
		//optional
		DimensionShowName: "TidbPingCap",
	}
	w = tests.PerformRequest(suite.router, "GET", "/query_commodity_dimensions", DimensionQueryForm)

	assert.Equal(http.StatusOK, w.Code, w.Body.String())
	res = &[]forms.CommodityDimension{}
	assert.NoError(json.Unmarshal(w.Body.Bytes(), res))
	assert.Equal("region", (*res)[0].DimensionCode)
}

func (suite *CommodityTestSuite) TestQueryCommodityEditions() {

	suite.TestAddCommodityEdition()
	assert := suite.Assert()
	commodityEditionQueryForm := &forms.CommodityEditionQuery{
		//optional
		CommodityCode: "Tidb",
	}

	w := tests.PerformRequest(suite.router, "GET", "/query_commodity_editions", commodityEditionQueryForm)

	assert.Equal(http.StatusOK, w.Code, w.Body.String())
	res := &[]forms.CommodityEdition{}
	assert.NoError(json.Unmarshal(w.Body.Bytes(), res))
	assert.Equal("testTidb", (*res)[0].EditionCode)
	commodityEditionQueryForm = &forms.CommodityEditionQuery{
		//optional
		CommodityCode: "Tidb1",
	}

	w = tests.PerformRequest(suite.router, "GET", "/query_commodity_editions", commodityEditionQueryForm)

	assert.Equal(http.StatusOK, w.Code, w.Body.String())
	res = &[]forms.CommodityEdition{}
	assert.NoError(json.Unmarshal(w.Body.Bytes(), res))
	assert.Equal(0, len(*res))

	commodityEditionQueryForm = &forms.CommodityEditionQuery{
		//optional
		EditionShowName: "sss-test",
	}
	w = tests.PerformRequest(suite.router, "GET", "/query_commodity_editions", commodityEditionQueryForm)

	assert.Equal(http.StatusOK, w.Code, w.Body.String())
	res = &[]forms.CommodityEdition{}
	assert.NoError(json.Unmarshal(w.Body.Bytes(), res))
	//pp.Print(res)

	assert.Equal("testTidb", (*res)[0].EditionCode)
}

func (suite *CommodityTestSuite) TestQuerySkuTemplates() {

	suite.TestAddSkuTemplate()
	assert := suite.Assert()
	skuTemplateQueryForm := &forms.SkuTemplateQuery{
		//optional
		CommodityCode: "Tidb",
	}

	w := tests.PerformRequest(suite.router, "GET", "/query_commodity_sku_templates", skuTemplateQueryForm)

	assert.Equal(http.StatusOK, w.Code, w.Body.String())
	res := &[]forms.SkuTemplate{}
	assert.NoError(json.Unmarshal(w.Body.Bytes(), res))
	assert.Equal("testTidb", (*res)[0].EditionCode)
	skuTemplateQueryForm = &forms.SkuTemplateQuery{
		//optional
		CommodityCode: "Tidb1",
	}

	w = tests.PerformRequest(suite.router, "GET", "/query_commodity_sku_templates", skuTemplateQueryForm)

	assert.Equal(http.StatusOK, w.Code, w.Body.String())
	res = &[]forms.SkuTemplate{}
	assert.NoError(json.Unmarshal(w.Body.Bytes(), res))
	assert.Equal(0, len(*res))

	skuTemplateQueryForm = &forms.SkuTemplateQuery{
		//optional
		EditionCode: "testTidb",
	}
	w = tests.PerformRequest(suite.router, "GET", "/query_commodity_sku_templates", skuTemplateQueryForm)

	assert.Equal(http.StatusOK, w.Code, w.Body.String())
	res = &[]forms.SkuTemplate{}
	assert.NoError(json.Unmarshal(w.Body.Bytes(), res))
	pp.Print(res)

	assert.Equal("testTidb", (*res)[0].EditionCode)
}

func (suite *CommodityTestSuite) TestQuerySkuList() {

	suite.TestAddSkuList()
	assert := suite.Assert()
	skuInfoQueryForm := &forms.SkuInfoQuery{
		//optional
		CommodityCode: "tidb",
	}

	w := tests.PerformRequest(suite.router, "GET", "/query_sku_list", skuInfoQueryForm)

	assert.Equal(http.StatusOK, w.Code, w.Body.String())
	res := &[]forms.SkuInfo{}
	assert.NoError(json.Unmarshal(w.Body.Bytes(), res))
	assert.Equal("tidb", (*res)[0].EditionCode)
	skuInfoQueryForm = &forms.SkuInfoQuery{
		//optional
		CommodityCode: "Tidb1",
	}

	w = tests.PerformRequest(suite.router, "GET", "/query_sku_list", skuInfoQueryForm)

	assert.Equal(http.StatusOK, w.Code, w.Body.String())
	res = &[]forms.SkuInfo{}
	assert.NoError(json.Unmarshal(w.Body.Bytes(), res))
	assert.Equal(0, len(*res))

	skuInfoQueryForm = &forms.SkuInfoQuery{
		//optional
		UnitKey: "key-s1",
	}
	w = tests.PerformRequest(suite.router, "GET", "/query_sku_list", skuInfoQueryForm)

	assert.Equal(http.StatusOK, w.Code, w.Body.String())
	res = &[]forms.SkuInfo{}
	assert.NoError(json.Unmarshal(w.Body.Bytes(), res))
	//pp.Print(res)

	assert.Equal("tidb", (*res)[0].EditionCode)
}

func (suite *CommodityTestSuite) TestModifyCommodity() {

	suite.TestCreateCommodity()
	assert := suite.Assert()
	commodityModifyForm := &forms.CommodityModify{
		Commodity: forms.Commodity{
			CommodityShowName: "testModify",
		},
		ModifyID: 1,
	}

	w := tests.PerformRequest(suite.router, "PUT", "/modify_commodity", commodityModifyForm)
	assert.Equal(http.StatusOK, w.Code, w.Body.String())
	res := &forms.Commodity{}
	assert.NoError(json.Unmarshal(w.Body.Bytes(), res))
	assert.Equal("testModify", res.CommodityShowName)

	commodityModifyForm = &forms.CommodityModify{
		Commodity: forms.Commodity{
			Owner: "testModify1",
		},
		ModifyID: 2,
	}

	w = tests.PerformRequest(suite.router, "PUT", "/modify_commodity", commodityModifyForm)
	assert.NotEqual(http.StatusOK, w.Code, w.Body.String())

	commodityModifyForm = &forms.CommodityModify{
		Commodity: forms.Commodity{
			Owner: "testModify1",
		},
		ModifyID: 1,
	}
	w = tests.PerformRequest(suite.router, "PUT", "/modify_commodity", commodityModifyForm)

	assert.Equal(http.StatusOK, w.Code, w.Body.String())
	res = &forms.Commodity{}
	assert.NoError(json.Unmarshal(w.Body.Bytes(), res))
	//pp.Print(res)

	assert.Equal("testModify1", res.Owner)
}

func (suite *CommodityTestSuite) TestModifyCommodityDimension() {

	suite.TestAddCommodityDimension()
	assert := suite.Assert()
	dimensionModifyForm := &forms.CommodityDimensionModify{
		CommodityDimension: forms.CommodityDimension{
			DimensionShowName: "testModify",
		},
		ModifyID: 1,
	}

	w := tests.PerformRequest(suite.router, "PUT", "/modify_commodity_dimension", dimensionModifyForm)
	assert.Equal(http.StatusOK, w.Code, w.Body.String())
	res := &forms.CommodityDimension{}
	assert.NoError(json.Unmarshal(w.Body.Bytes(), res))
	assert.Equal("testModify", res.DimensionShowName)

	dimensionModifyForm = &forms.CommodityDimensionModify{
		CommodityDimension: forms.CommodityDimension{
			DimensionShowName: "testModify",
		},
		ModifyID: 2,
	}

	w = tests.PerformRequest(suite.router, "PUT", "/modify_commodity_dimension", dimensionModifyForm)
	assert.NotEqual(http.StatusOK, w.Code, w.Body.String())

	dimensionModifyForm = &forms.CommodityDimensionModify{
		CommodityDimension: forms.CommodityDimension{
			DimensionCode:  "testModify-2",
			DimensionValue: map[string]string{"ss1111": "s"},
		},
		ModifyID: 1,
	}
	w = tests.PerformRequest(suite.router, "PUT", "/modify_commodity_dimension", dimensionModifyForm)

	assert.Equal(http.StatusOK, w.Code, w.Body.String())
	res = &forms.CommodityDimension{}
	assert.NoError(json.Unmarshal(w.Body.Bytes(), res))
	pp.Print(res)

	assert.Equal("testModify-2", res.DimensionCode)
}

func (suite *CommodityTestSuite) TestModifyCommodityEdition() {

	suite.TestAddCommodityEdition()
	assert := suite.Assert()
	editionModifyForm := &forms.CommodityEditionModify{
		CommodityEdition: forms.CommodityEdition{
			EditionShowName: "testModify",
		},
		ModifyID: 1,
	}

	w := tests.PerformRequest(suite.router, "PUT", "/modify_commodity_edition", editionModifyForm)
	assert.Equal(http.StatusOK, w.Code, w.Body.String())
	res := &forms.CommodityEdition{}
	assert.NoError(json.Unmarshal(w.Body.Bytes(), res))
	assert.Equal("testModify", res.EditionShowName)

	editionModifyForm = &forms.CommodityEditionModify{
		CommodityEdition: forms.CommodityEdition{
			EditionShowName: "testModify",
		},
		ModifyID: 2,
	}

	w = tests.PerformRequest(suite.router, "PUT", "/modify_commodity_edition", editionModifyForm)
	assert.NotEqual(http.StatusOK, w.Code, w.Body.String())

	editionModifyForm = &forms.CommodityEditionModify{
		CommodityEdition: forms.CommodityEdition{
			EditionDimensionValue: forms.EditionDimensionValue{"Edition-1": {"region": {"west_ss": "1"}, "provider": {"aws_ss": "1"}},
				"Edition-2": {"region": {"west2": "2"}, "provider": {"gcp": "3"}},
			},
		},
		ModifyID: 1,
	}
	w = tests.PerformRequest(suite.router, "PUT", "/modify_commodity_edition", editionModifyForm)

	assert.Equal(http.StatusOK, w.Code, w.Body.String())
	res = &forms.CommodityEdition{}
	assert.NoError(json.Unmarshal(w.Body.Bytes(), res))
	pp.Print(res)

}

func (suite *CommodityTestSuite) TestModifySkuTemplate() {

	suite.TestAddSkuTemplate()
	assert := suite.Assert()
	skuTemplateModifyForm := &forms.SkuTemplateModify{
		SkuTemplate: forms.SkuTemplate{
			Template: map[string]string{"Template-1-Modify": "aws:region:--Modify"},

			ModifierAndCreator: forms.ModifierAndCreator{
				Modifier: "XiaoWu-Modify",
				Creator:  "Wang-Modify",
				Describe: "Test-test-Modify",
			},
		},
		ModifyID: 1,
	}

	w := tests.PerformRequest(suite.router, "PUT", "/modify_commodity_sku_template", skuTemplateModifyForm)
	assert.Equal(http.StatusOK, w.Code, w.Body.String())
	res := &forms.SkuTemplate{}
	assert.NoError(json.Unmarshal(w.Body.Bytes(), res))
	pp.Print(res)

	//assert.Equal("testModify", res.EditionShowName)

	skuTemplateModifyForm = &forms.SkuTemplateModify{
		SkuTemplate: forms.SkuTemplate{
			Template: map[string]string{"Template-1-Modify": "aws:region:--Modify"},
		},
		ModifyID: 2,
	}
	w = tests.PerformRequest(suite.router, "PUT", "/modify_commodity_sku_template", skuTemplateModifyForm)
	assert.NotEqual(http.StatusOK, w.Code, w.Body.String())

	skuTemplateModifyForm = &forms.SkuTemplateModify{
		SkuTemplate: forms.SkuTemplate{
			Template: map[string]string{"Template-1": "aws:region:"},
		},
		ModifyID: 1,
	}
	w = tests.PerformRequest(suite.router, "PUT", "/modify_commodity_sku_template", skuTemplateModifyForm)

	assert.Equal(http.StatusOK, w.Code, w.Body.String())
	res = &forms.SkuTemplate{}
	assert.NoError(json.Unmarshal(w.Body.Bytes(), res))
	//pp.Print(res)

}

func (suite *CommodityTestSuite) TestModifySkuList() {

	suite.TestAddSkuList()
	assert := suite.Assert()

	skuModify := forms.SkuInfo{
		UnitKey:  "key-1",
		Category: "test-Category",
	}

	skuModifyForms := &forms.SkuModify{
		ModifyMap: map[string]forms.SkuInfo{
			"key-1": skuModify,
		},
	}

	w := tests.PerformRequest(suite.router, "PUT", "/modify_sku_list", skuModifyForms)
	assert.Equal(http.StatusOK, w.Code, w.Body.String())
	res := &[]forms.SkuInfo{}
	assert.NoError(json.Unmarshal(w.Body.Bytes(), res))

	skuModify = forms.SkuInfo{
		UnitKey:  "key-1-s1",
		Category: "test-Category",
	}
	skuModifyForms = &forms.SkuModify{
		ModifyMap: map[string]forms.SkuInfo{
			"sss11": skuModify,
		},
	}
	w = tests.PerformRequest(suite.router, "PUT", "/modify_sku_list", skuModifyForms)
	assert.NotEqual(http.StatusOK, w.Code, w.Body.String())

	skuModify = forms.SkuInfo{
		UnitKey:  "key-1",
		Category: "test-Category",
	}
	skuModifyForms = &forms.SkuModify{
		ModifyMap: map[string]forms.SkuInfo{
			"sss": skuModify,
		},
	}
	w = tests.PerformRequest(suite.router, "PUT", "/modify_sku_list", skuModifyForms)

	assert.Equal(http.StatusOK, w.Code, w.Body.String())
	res = &[]forms.SkuInfo{}
	assert.NoError(json.Unmarshal(w.Body.Bytes(), res))
	pp.Print(res)

}
