package tests

import (
	"encoding/json"
	"errors"
	"net/http"
	"strconv"
	"testing"
	"time"

	"github.com/gin-gonic/gin"
	"github.com/pingcap/dbaas/billing2/api"
	"github.com/pingcap/dbaas/billing2/forms"
	"github.com/pingcap/dbaas/billing2/handler/eventbushandler"
	"github.com/pingcap/dbaas/billing2/utils/ginutils"
	"github.com/pingcap/dbaas/billing2/utils/panicIf"
	"github.com/pingcap/dbaas/billing2/utils/tests"
	"github.com/stretchr/testify/suite"
	"golang.org/x/exp/rand"
)

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

func (suite *EventTestSuite) SetupTest() {
	suite.BillingTestSuite.SetupTest()
	suite.router = gin.New()
	suite.router.Use(ginutils.ErrorMiddleWare)
	tests.MockCentralHandler()
	api.InitializeEventRouter(ginutils.MyRoute{Route: suite.router})

}

func TestEventTestSuite(t *testing.T) {
	suite.Run(t, new(EventTestSuite))
}

type D struct {
	ID       uint64 `json:"id"`
	Greeting string `json:"greeting"`
}

func (suite *EventTestSuite) TestEventPublish() {
	assert := suite.Assert()
	eventType := "test"
	var ID uint64 = 0xffffffffffffffff
	greeting := "hi"
	event := eventbushandler.Event{
		EventID:   strconv.Itoa(rand.Int()),
		EventType: eventType,
		EventData: map[string]interface{}{"greeting": greeting, "id": ID},
	}
	eb, err := tests.NewLocalEventBusHandler()
	panicIf.Error(err)
	err = eventbushandler.Get().Close()
	panicIf.Error(err)
	eventbushandler.Set(eb)
	ch := make(chan *D)
	err = eventbushandler.Get().RegisterEventHandleFunc(eventType, "1", D{}, func(event *eventbushandler.Event) error {
		ch <- event.EventData.(*D)
		return nil
	})
	assert.NoError(err)
	err = eventbushandler.Get().Run()
	assert.NoError(err)
	w := tests.PerformRequest(suite.router, "PUT", "/events", event)
	assert.Equal(http.StatusOK, w.Code)
	r := forms.OKType{}
	err = json.NewDecoder(w.Body).Decode(&r)
	assert.NoError(err)
	assert.Equal("success", r.Status)
	select {
	case recv := <-ch:
		assert.Equal(greeting, recv.Greeting)
		assert.Equal(ID, recv.ID)
	case <-time.After(2 * time.Second):
		panic(errors.New("timeout"))
	}
}
