package tests

import (
	"encoding/json"
	"fmt"
	"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/billing"
	"github.com/pingcap/dbaas/billing2/utils/ginutils"
	"github.com/pingcap/dbaas/billing2/utils/tests"
	"github.com/stretchr/testify/suite"
)

var model = &billing.UnitModel{}

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

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

func TestUnitSuite(t *testing.T) {
	suite.Run(t, new(UnitTestSuite))
}

func (suite *UnitTestSuite) TestGetAllUnits() {
	assert := suite.Assert()
	w := tests.PerformGetRequest(suite.router, "/units")
	assert.Equal(http.StatusOK, w.Code)
	model.CreateUnit(&forms.UnitInfo{
		UnitKey: "TestKey",
	})
	w = tests.PerformGetRequest(suite.router, "/units")
	assert.Equal(http.StatusOK, w.Code)
	var response []forms.UnitInfo
	err := json.Unmarshal(w.Body.Bytes(), &response)
	assert.Nil(err)
	assert.Equal(len(response), 1)
}

func (suite *UnitTestSuite) TestCreateUnit() {
	assert := suite.Assert()
	unit := &forms.UnitInfo{
		UnitKey: "TestKey",
	}
	w := tests.PerformRequest(suite.router, "POST", "/units", unit)
	assert.Equal(http.StatusOK, w.Code)
	fmt.Println(w.Body)
	_, err := model.GetUnit("TestKey")
	assert.Nil(err)
}

func (suite *UnitTestSuite) TestCreateUnitWithEmptyKey() {
	assert := suite.Assert()
	unit := &forms.UnitInfo{
		UnitKey: "",
	}
	w := tests.PerformRequest(suite.router, "POST", "/units", unit)
	assert.Equal(http.StatusBadRequest, w.Code)
	fmt.Println(w.Body)
}

func (suite *UnitTestSuite) TestDeleteUnit() {
	assert := suite.Assert()
	unit := &forms.UnitInfo{
		UnitKey: "test_key",
	}
	_, err := model.CreateUnit(unit)
	assert.Nil(err)
	w := tests.PerformRequest(suite.router, "DELETE", "/units/test_key", nil)
	assert.Equal(http.StatusOK, w.Code)
	_, err = model.GetUnit("TestKey")
	assert.NotNil(err)
}

func (suite *UnitTestSuite) TestGetUnit() {
	assert := suite.Assert()
	unit := &forms.UnitInfo{
		UnitKey: "test_key",
	}
	model.CreateUnit(unit)
	w := tests.PerformGetRequest(suite.router, "/units/test_key")
	assert.Equal(http.StatusOK, w.Code)
}

func (suite *UnitTestSuite) TestUpdateUnit() {
	assert := suite.Assert()
	unit := &forms.UnitInfo{
		UnitKey:     "test_key",
		Description: "test description",
	}
	model.CreateUnit(unit)
	description := "test description"
	w := tests.PerformRequest(suite.router, "PUT", "/units/test_key", unit)
	assert.Equal(http.StatusOK, w.Code)
	unitResp, err := model.GetUnit("test_key")
	assert.Nil(err)
	assert.Equal(unitResp.Description, description)
}

func (suite *UnitTestSuite) TestBulkUpdateUnit() {
	assert := suite.Assert()
	units := []forms.UnitInfo{
		{
			UnitKey: "test_key",
		},
		{
			UnitKey: "test_key1",
		},
	}
	w := tests.PerformRequest(suite.router, "POST", "/units/_bulk", units)
	assert.Equal(http.StatusOK, w.Code)

	units = []forms.UnitInfo{
		{
			UnitKey: "test_key",
		},
		{
			UnitKey: "",
		},
	}
	w = tests.PerformRequest(suite.router, "POST", "/units/_bulk", units)
	assert.Equal(http.StatusBadRequest, w.Code, w.Body.String())
}
