package tests

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

	"github.com/gin-gonic/gin"
	"github.com/pingcap/dbaas/billing2/api"
	"github.com/pingcap/dbaas/billing2/db/entity"
	"github.com/pingcap/dbaas/billing2/forms"
	"github.com/pingcap/dbaas/billing2/model/marketing/plan"
	"github.com/pingcap/dbaas/billing2/utils/ginutils"
	"github.com/pingcap/dbaas/billing2/utils/tests"
	"github.com/pingcap/dbaas/billing2/utils/tests/datainit"
	"github.com/stretchr/testify/suite"
)

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

func (suite *InnerTenantPlanAPITestSuite) SetupTest() {
	suite.BillingTestSuite.SetupTest()
	assert := suite.Assert()

	// Seed a billing config + a payable payment method so the on-demand plan
	// can be enabled below.
	_, err := datainit.CreateBillingConfig(1, entity.BillingConfigType_DirectCustomer)
	assert.NoError(err)
	assert.NoError(datainit.CreatePaymentMock(1))

	// central is consulted in the POC branch of GetTenantPlanInfo.
	tests.MockCentralHandler()

	suite.router = gin.New()
	suite.router.Use(ginutils.ErrorMiddleWare)
	api.InitializeInnerTenantPlanRouter(ginutils.MyRoute{Route: suite.router})
}

func TestInnerTenantPlanAPISuite(t *testing.T) {
	suite.Run(t, new(InnerTenantPlanAPITestSuite))
}

// Inner route mirrors the public /tenants/:tenant_id/plans: same params (path
// only), same response shape (forms.TenantPlanInfo). With no plan records the
// effective plan defaults to NewUser.
func (suite *InnerTenantPlanAPITestSuite) TestGetInnerTenantPlanInfoDefault() {
	assert := suite.Assert()

	w := tests.PerformGetRequest(suite.router, "/tenants/1/plans")
	assert.Equal(http.StatusOK, w.Code)

	var info forms.TenantPlanInfo
	err := json.NewDecoder(w.Body).Decode(&info)
	assert.NoError(err)
	assert.Equal(uint(1), info.TenantID)
	assert.Equal(entity.TenantPlan_NewUser, info.EffectivePlan)
	assert.NotNil(info.DevTierPlanInfo)
	assert.Equal(entity.TenantPlanStatus_NotStarted, info.DevTierPlanInfo.Status)
	assert.NotNil(info.POCPlanInfo)
	assert.Equal(entity.TenantPlanStatus_NotStarted, info.POCPlanInfo.Status)
	assert.NotNil(info.OnDemandPlanInfo)
	assert.Equal(entity.TenantPlanStatus_NotStarted, info.OnDemandPlanInfo.Status)
}

// After enabling the on-demand plan, the inner endpoint must surface
// EffectivePlan = OnDemand and an Active status — proving the inner route hits
// the same handler as the public one.
func (suite *InnerTenantPlanAPITestSuite) TestGetInnerTenantPlanInfoOnDemand() {
	assert := suite.Assert()

	assert.NoError((&plan.TenantPlanModel{}).EnableTenantOnDemandPlan(1))

	w := tests.PerformGetRequest(suite.router, "/tenants/1/plans")
	assert.Equal(http.StatusOK, w.Code)

	var info forms.TenantPlanInfo
	err := json.NewDecoder(w.Body).Decode(&info)
	assert.NoError(err)
	assert.Equal(uint(1), info.TenantID)
	assert.Equal(entity.TenantPlan_OnDemand, info.EffectivePlan)
	assert.NotNil(info.OnDemandPlanInfo)
	assert.Equal(entity.TenantPlanStatus_Active, info.OnDemandPlanInfo.Status)
}

// Missing :tenant_id in the path should fail URI binding and return 400 — same
// behavior as the public endpoint, just exercised through the inner router.
func (suite *InnerTenantPlanAPITestSuite) TestGetInnerTenantPlanInfoInvalidURI() {
	assert := suite.Assert()

	w := tests.PerformGetRequest(suite.router, "/tenants//plans")
	assert.Equal(http.StatusBadRequest, w.Code)
}