package tests

import (
	"testing"
	"time"

	"github.com/pingcap/dbaas/billing2/config"
	"github.com/pingcap/dbaas/billing2/constant"
	"github.com/pingcap/dbaas/billing2/db/entity"
	"github.com/pingcap/dbaas/billing2/forms"
	"github.com/pingcap/dbaas/billing2/handler/cachehandler"
	"github.com/pingcap/dbaas/billing2/handler/centralhandler"
	"github.com/pingcap/dbaas/billing2/handler/eventbushandler"
	"github.com/pingcap/dbaas/billing2/handler/infrahandler"
	"github.com/pingcap/dbaas/billing2/model/billing"
	"github.com/pingcap/dbaas/billing2/model/marketing"
	"github.com/pingcap/dbaas/billing2/model/marketing/plan"
	"github.com/pingcap/dbaas/billing2/model/marketing/unit_filter"
	"github.com/pingcap/dbaas/billing2/utils/tests"
	"github.com/pingcap/dbaas/billing2/utils/tests/datainit"
	"github.com/pingcap/dbaas/billing2/utils/timeutils"
	"github.com/shopspring/decimal"
	"github.com/stretchr/testify/mock"
	"github.com/stretchr/testify/suite"
)

type TenantPOCPlanSuite struct {
	tests.BillingTestSuite
	creditPackage  *forms.CreditsPackage
	creditPackage2 *forms.CreditsPackage
}

func TestTenantPOCPlanSuite(t *testing.T) {
	suite.Run(t, new(TenantPOCPlanSuite))
}

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

	tenantID := uint(1)
	err := datainit.CreatePaymentMock(tenantID)
	assert.NoError(err)
	timeutils.GetNowFunc = func() time.Time {
		return datainit.BillingDate
	}
	packageModel := &billing.PackageModel{}

	packageInfo, err := packageModel.CreatePackage(
		&forms.PackageInfo{
			UnitPrices:    forms.UnitPrices{},
			Discount:      decimal.NewFromInt(1),
			CreditsEnable: true,
			CreditsOnly:   true,
		})
	assert.NoError(err)
	config.Get().Set(config.POCPackage, packageInfo.PackageID)
	config.Get().Set(config.CreditsPricePackage, packageInfo.PackageID)
	generalUnitFilter, err := (&unit_filter.Model{}).CreateUnitFilter(&forms.UnitFilter{
		UnitFilterSlim: forms.UnitFilterSlim{Name: "General", Description: "General"},
		General:        true,
	})
	assert.NoError(err)
	config.Get().Set(config.GeneralCreditTypeID, generalUnitFilter.FilterID)
	creditsModel := &marketing.CreditsPackageModel{}
	billingConfigID := uint(1)
	billingConfigID2 := uint(2)

	datainit.CreateBillingConfig(tenantID, entity.BillingConfigType_DirectCustomer)
	datainit.CreateBillingConfig(2, entity.BillingConfigType_DirectCustomer)

	suite.creditPackage, err = creditsModel.CreateCreditsPackage(tenantID, &forms.CreditsPackage{
		StartDate:             datainit.BillingDate,
		ExpiredDate:           datainit.BillingDate.AddDate(0, 1, 0),
		TotalCredits:          decimal.NewFromInt(1),
		UnitFilters:           []*forms.UnitFilterSlim{{TypeID: config.Get().GetUint(config.GeneralCreditTypeID)}},
		Usage:                 entity.CreditsPackageUsage_POC,
		BindedBillingConfigID: &billingConfigID,
	})
	assert.NoError(err)
	suite.creditPackage2, err = creditsModel.CreateCreditsPackage(2, &forms.CreditsPackage{
		StartDate:             datainit.BillingDate,
		ExpiredDate:           datainit.BillingDate.AddDate(0, 1, 0),
		TotalCredits:          decimal.NewFromInt(1),
		UnitFilters:           []*forms.UnitFilterSlim{{TypeID: config.Get().GetUint(config.GeneralCreditTypeID)}},
		Usage:                 entity.CreditsPackageUsage_POC,
		BindedBillingConfigID: &billingConfigID2,
	})
	assert.NoError(err)

	config.Get().Set(config.EnableCache, true)
	cachehandler.InitWithLocal()
}

func (suite *TenantPOCPlanSuite) TestEnablePOC() {
	assert := suite.Assert()
	var err error
	eb, err := tests.NewLocalEventBusHandler()
	assert.NoError(err)
	err = eventbushandler.Get().Close()
	assert.NoError(err)
	eventbushandler.Set(eb)
	ch := make(chan *forms.TenantPlanEvent)
	err = eventbushandler.Get().RegisterEventHandleFunc(plan.TenantPlanEventType, "1", forms.TenantPlanEvent{}, func(event *eventbushandler.Event) error {
		ch <- event.EventData.(*forms.TenantPlanEvent)
		return nil
	})
	assert.NoError(err)
	err = eb.Run()
	assert.NoError(err)
	tenantID := uint(1)

	model := &plan.TenantPlanModel{}
	tenantPlan, err := model.GetTenantEffectivePlan(tenantID)
	assert.NoError(err)
	assert.Equal(tenantPlan.EffectivePlan, entity.TenantPlan_NewUser)
	timeutils.SetMockNow(datainit.BillingDate)
	err = model.EnableTenantPOCPlanAfterCreditsOpened(tenantID)
	assert.NoError(err)
	info, err := model.GetTenantPOCPlanInfo(tenantID)
	assert.NoError(err)
	assert.Equal(info.Status, entity.TenantPlanStatus_Active)
	assert.Equal(*info.StartedAt, datainit.BillingDate)
	select {
	case eData := <-ch:
		assert.Equal(entity.TenantPlan_POC, eData.ChangedPlan)
		assert.Equal(entity.TenantPlanStatus_Active, eData.ChangedStatus)
	case <-time.After(2 * time.Second):
		panic("timeout")
	}
	creditsModel := &marketing.CreditsPackageModel{}
	err = creditsModel.CloseCreditsPackage(suite.creditPackage.CreditsPackageID, "")
	assert.NoError(err)
	cPackage, _ := creditsModel.GetCreditsPackage(suite.creditPackage.CreditsPackageID)
	mockCentral := &MockPOCCentralHandlerImpl{}
	centralhandler.SetCentralHandler(mockCentral)
	mockCentral.On("SendTenantAdminEmailOnce", tenantID, mock.Anything, plan.TemplateID_PocCreditsExhaust_Inner, mock.Anything).Return(nil)
	mockCentral.On("SendTenantManagerEmailOnce", tenantID, mock.Anything, plan.TemplateID_PocCreditsExhaust_Inner, mock.Anything).Return(nil)

	err = model.DisableTenantPOCPlanAfterCreditsExhausted(cPackage.CreditsPackageID)
	assert.NoError(err)
	select {
	case eData := <-ch:
		assert.Equal(entity.TenantPlan_POC, eData.ChangedPlan)
		assert.Equal(entity.TenantPlanStatus_Closing, eData.ChangedStatus)
	case <-time.After(2 * time.Second):
		panic("timeout")
	}
	info, err = model.GetTenantPOCPlanInfo(tenantID)
	assert.NoError(err)
	assert.Equal(info.Status, entity.TenantPlanStatus_Closing)
	billingConfigID := uint(1)

	timeutils.SetMockNow(datainit.BillingDate.AddDate(0, 0, 1))
	_, err = creditsModel.CreateCreditsPackage(tenantID, &forms.CreditsPackage{
		StartDate:             datainit.BillingDate,
		ExpiredDate:           datainit.BillingDate.AddDate(0, 1, 0),
		TotalCredits:          decimal.NewFromInt(1),
		UnitFilters:           []*forms.UnitFilterSlim{{TypeID: config.Get().GetUint(config.GeneralCreditTypeID)}},
		Usage:                 entity.CreditsPackageUsage_POC,
		BindedBillingConfigID: &billingConfigID,
	})
	assert.NoError(err)
	err = model.EnableTenantPOCPlanAfterCreditsOpened(tenantID)
	assert.NoError(err)
	info, err = model.GetTenantPOCPlanInfo(tenantID)
	assert.NoError(err)
	assert.Equal(info.Status, entity.TenantPlanStatus_Active)
	assert.Equal(*info.StartedAt, datainit.BillingDate)
	select {
	case eData := <-ch:
		assert.Equal(entity.TenantPlan_POC, eData.ChangedPlan)
		assert.Equal(entity.TenantPlanStatus_Active, eData.ChangedStatus)
	case <-time.After(2 * time.Second):
		panic("timeout")
	}
	events := eb.GetAllEvents()
	err = model.EnableTenantPOCPlanAfterCreditsOpened(tenantID)
	assert.NoError(err)
	assert.Len(eb.GetAllEvents(), len(events)) // no new event
	info, err = model.GetTenantPOCPlanInfo(tenantID)
	assert.NoError(err)
	assert.Equal(info.Status, entity.TenantPlanStatus_Active)
	assert.Equal(*info.StartedAt, datainit.BillingDate)

	tenantPlan, err = model.GetTenantEffectivePlan(tenantID)
	assert.NoError(err)
	assert.Equal(tenantPlan.EffectivePlan, entity.TenantPlan_POC)
}

func (suite *TenantPOCPlanSuite) TestDisablePOC() {
	assert := suite.Assert()
	var err error
	eb, err := tests.NewLocalEventBusHandler()
	assert.NoError(err)
	err = eventbushandler.Get().Close()
	assert.NoError(err)
	eventbushandler.Set(eb)
	ch := make(chan *forms.TenantPlanEvent)
	err = eventbushandler.Get().RegisterEventHandleFunc(plan.TenantPlanEventType, "1", forms.TenantPlanEvent{}, func(event *eventbushandler.Event) error {
		ch <- event.EventData.(*forms.TenantPlanEvent)
		return nil
	})
	assert.NoError(err)
	err = eb.Run()
	assert.NoError(err)
	tenantID := uint(1)
	model := &plan.TenantPlanModel{}
	timeutils.SetMockNow(datainit.BillingDate)
	mockCentral := &MockPOCCentralHandlerImpl{}
	centralhandler.SetCentralHandler(mockCentral)

	err = model.EnableTenantPOCPlanAfterCreditsOpened(tenantID)
	assert.NoError(err)
	select {
	case eData := <-ch:
		assert.Equal(entity.TenantPlan_POC, eData.ChangedPlan)
		assert.Equal(entity.TenantPlanStatus_Active, eData.ChangedStatus)
	case <-time.After(2 * time.Second):
		panic("timeout")
	}
	creditsModel := &marketing.CreditsPackageModel{}
	err = creditsModel.CloseCreditsPackage(suite.creditPackage.CreditsPackageID, "")
	assert.NoError(err)
	cPackage, _ := creditsModel.GetCreditsPackage(suite.creditPackage.CreditsPackageID)
	mockCentral.On("SendTenantAdminEmailOnce", tenantID, mock.Anything, plan.TemplateID_PocCreditsExhaust_Inner, mock.Anything).Return(nil)
	mockCentral.On("SendTenantManagerEmailOnce", tenantID, mock.Anything, plan.TemplateID_PocCreditsExhaust_Inner, mock.Anything).Return(nil)

	err = model.DisableTenantPOCPlanAfterCreditsExhausted(cPackage.CreditsPackageID)
	assert.NoError(err)
	info, err := model.GetTenantPOCPlanInfo(tenantID)
	assert.NoError(err)
	select {
	case eData := <-ch:
		assert.Equal(entity.TenantPlan_POC, eData.ChangedPlan)
		assert.Equal(entity.TenantPlanStatus_Closing, eData.ChangedStatus)
	case <-time.After(2 * time.Second):
		panic("timeout")
	}
	assert.Equal(info.Status, entity.TenantPlanStatus_Closing)
	assert.Equal(*info.ClosedAt, datainit.BillingDate)

	timeutils.SetMockNow(datainit.BillingDate.AddDate(0, 0, 1))

	mockCentral.On("SendTenantAdminEmailOnce", tenantID, mock.Anything, plan.TemplateID_PocCreditsExhaust_Inner, mock.Anything).Return(nil)
	mockCentral.On("SendTenantManagerEmailOnce", tenantID, mock.Anything, plan.TemplateID_PocCreditsExhaust_Inner, mock.Anything).Return(nil)

	err = model.DisableTenantPOCPlanAfterCreditsExhausted(cPackage.CreditsPackageID)
	assert.NoError(err)
	info, err = model.GetTenantPOCPlanInfo(tenantID)
	assert.NoError(err)
	assert.Equal(info.Status, entity.TenantPlanStatus_Closing)
	assert.Equal(*info.ClosedAt, datainit.BillingDate)
	assert.NotZero(info.BindedPackageID)
	bindedPackageInfo, err := (&billing.BindedPackageModel{}).GetBindedPackage(info.BindedPackageID)
	assert.NoError(err)
	assert.Equal(bindedPackageInfo.RemainingCredits, decimal.NewFromInt(config.Get().GetInt64(config.POCRemainDaysCredits)))
	assert.Equal(bindedPackageInfo.Active, entity.BindedPackageStatus_Active)
	billingConfigID := uint(1)

	creditsPackage, err := creditsModel.CreateCreditsPackage(tenantID, &forms.CreditsPackage{
		StartDate:             datainit.BillingDate,
		ExpiredDate:           datainit.BillingDate.AddDate(0, 1, 0),
		TotalCredits:          decimal.NewFromInt(1),
		UnitFilters:           []*forms.UnitFilterSlim{{FilterID: config.Get().GetUint(config.GeneralCreditTypeID)}},
		Usage:                 entity.CreditsPackageUsage_POC,
		BindedBillingConfigID: &billingConfigID,
	})
	err = model.EnableTenantPOCPlanAfterCreditsOpened(tenantID)
	assert.NoError(err)
	timeutils.SetMockNow(timeutils.GetNow().Add(config.Get().GetDuration(config.BindedPackageInactiveDelayHour) * time.Hour))
	_, err = (&billing.BindedPackageModel{}).InactiveTimeoutBindedPackages()
	assert.NoError(err)
	bindedPackageInfo, err = (&billing.BindedPackageModel{}).GetBindedPackage(info.BindedPackageID)
	assert.NoError(err)
	assert.Equal(bindedPackageInfo.Active, entity.BindedPackageStatus_InActive)
	select {
	case eData := <-ch:
		assert.Equal(entity.TenantPlan_POC, eData.ChangedPlan)
		assert.Equal(entity.TenantPlanStatus_Active, eData.ChangedStatus)
	case <-time.After(2 * time.Second):
		panic("timeout")
	}

	info, err = model.GetTenantPOCPlanInfo(tenantID)
	assert.NoError(err)
	assert.Zero(info.BindedPackageID)

	packageModel := &billing.PackageModel{}

	packageInfo, err := packageModel.CreatePackage(
		&forms.PackageInfo{
			UnitPrices:           forms.UnitPrices{},
			Discount:             decimal.NewFromInt(1),
			TenantMaxBindedTimes: 1,
		})
	assert.NoError(err)
	config.Get().Set(config.OnDemandPackage, packageInfo.PackageID)

	err = model.EnableTenantOnDemandPlan(tenantID)
	assert.NoError(err)
	select {
	case eData := <-ch:
		assert.Equal(entity.TenantPlan_OnDemand, eData.ChangedPlan)
		assert.Equal(entity.TenantPlanStatus_Active, eData.ChangedStatus)
	case <-time.After(2 * time.Second):
		panic("timeout")
	}

	events := eb.GetAllEvents()
	err = model.EnableTenantPOCPlanAfterCreditsOpened(tenantID)
	assert.NoError(err)
	assert.Len(eb.GetAllEvents(), len(events)) // no events

	err = creditsModel.CloseCreditsPackage(creditsPackage.CreditsPackageID, "")
	assert.NoError(err)
	cPackage, _ = creditsModel.GetCreditsPackage(creditsPackage.CreditsPackageID)
	err = model.DisableTenantPOCPlanAfterCreditsExhausted(cPackage.CreditsPackageID)
	assert.NoError(err)
	info, err = model.GetTenantPOCPlanInfo(tenantID)
	assert.NoError(err)
	assert.Equal(info.Status, entity.TenantPlanStatus_Closed)
	//assert.Zero(info.BindedPackageID)
	assert.Equal(*info.ClosedAt, timeutils.GetNow())
	select {
	case eData := <-ch:
		assert.Equal(entity.TenantPlan_POC, eData.ChangedPlan)
		assert.Equal(entity.TenantPlanStatus_Closed, eData.ChangedStatus)
	case <-time.After(2 * time.Second):
		panic("timeout")
	}
}

func (suite *TenantPOCPlanSuite) TestPOCCleanupJustSkip() {
	assert := suite.Assert()
	var err error
	eb, err := tests.NewLocalEventBusHandler()
	assert.NoError(err)
	err = eventbushandler.Get().Close()
	assert.NoError(err)
	eventbushandler.Set(eb)
	ch := make(chan *forms.TenantPlanEvent)
	err = eventbushandler.Get().RegisterEventHandleFunc(plan.TenantPlanEventType, "1", forms.TenantPlanEvent{}, func(event *eventbushandler.Event) error {
		ch <- event.EventData.(*forms.TenantPlanEvent)
		return nil
	})
	assert.NoError(err)
	err = eb.Run()
	assert.NoError(err)
	tenantID := uint(1)
	model := &plan.TenantPlanModel{}
	timeutils.SetMockNow(datainit.BillingDate)
	events := eb.GetAllEvents()
	err = model.POCCleanup(tenantID)
	assert.NoError(err)
	assert.Len(eb.GetAllEvents(), len(events)) // no events

	err = model.EnableTenantPOCPlanAfterCreditsOpened(tenantID)
	assert.NoError(err)
	select {
	case eData := <-ch:
		assert.Equal(entity.TenantPlan_POC, eData.ChangedPlan)
		assert.Equal(entity.TenantPlanStatus_Active, eData.ChangedStatus)
	case <-time.After(2 * time.Second):
		panic("timeout")
	}

	events = eb.GetAllEvents()
	err = model.POCCleanup(tenantID)
	assert.NoError(err)
	assert.Len(eb.GetAllEvents(), len(events)) // no events
	creditsModel := &marketing.CreditsPackageModel{}
	err = creditsModel.CloseCreditsPackage(suite.creditPackage.CreditsPackageID, "")
	assert.NoError(err)
	cPackage, _ := creditsModel.GetCreditsPackage(suite.creditPackage.CreditsPackageID)

	mockCentral := &MockPOCCentralHandlerImpl{}
	centralhandler.SetCentralHandler(mockCentral)
	mockCentral.On("SendTenantAdminEmailOnce", tenantID, mock.Anything, mock.Anything, mock.Anything).Return(nil)
	mockCentral.On("SendTenantManagerEmailOnce", tenantID, mock.Anything, mock.Anything, mock.Anything).Return(nil)

	err = model.DisableTenantPOCPlanAfterCreditsExhausted(cPackage.CreditsPackageID)
	assert.NoError(err)
	assert.Len(mockCentral.Calls, 2)

	select {
	case eData := <-ch:
		assert.Equal(entity.TenantPlan_POC, eData.ChangedPlan)
		assert.Equal(entity.TenantPlanStatus_Closing, eData.ChangedStatus)
	case <-time.After(2 * time.Second):
		panic("timeout")
	}

	info, err := model.GetTenantPOCPlanInfo(tenantID)
	assert.NoError(err)
	assert.Equal(info.Status, entity.TenantPlanStatus_Closing)
	assert.Equal(*info.ClosedAt, datainit.BillingDate)
	assert.NotZero(info.BindedPackageID)
	bindedPackageInfo, err := (&billing.BindedPackageModel{}).GetBindedPackage(info.BindedPackageID)
	assert.NoError(err)
	assert.Equal(bindedPackageInfo.RemainingCredits, decimal.NewFromInt(config.Get().GetInt64(config.POCRemainDaysCredits)))
	assert.Equal(bindedPackageInfo.Active, entity.BindedPackageStatus_Active)

	packageModel := &billing.PackageModel{}

	packageInfo, err := packageModel.CreatePackage(
		&forms.PackageInfo{
			UnitPrices:           forms.UnitPrices{},
			Discount:             decimal.NewFromInt(1),
			TenantMaxBindedTimes: 1,
		})
	assert.NoError(err)
	config.Get().Set(config.OnDemandPackage, packageInfo.PackageID)
	err = model.EnableTenantOnDemandPlan(tenantID)
	assert.NoError(err)
	select {
	case eData := <-ch:
		assert.Equal(entity.TenantPlan_OnDemand, eData.ChangedPlan)
		assert.Equal(entity.TenantPlanStatus_Active, eData.ChangedStatus)
	case <-time.After(2 * time.Second):
		panic("timeout")
	}

	err = model.POCCleanup(tenantID)
	assert.NoError(err)

	info, err = model.GetTenantPOCPlanInfo(tenantID)
	assert.NoError(err)
	assert.Equal(info.Status, entity.TenantPlanStatus_Closed)
	assert.Zero(info.BindedPackageID, 0)
	select {
	case eData := <-ch:
		assert.Equal(entity.TenantPlan_POC, eData.ChangedPlan)
		assert.Equal(entity.TenantPlanStatus_Closed, eData.ChangedStatus)
	case <-time.After(2 * time.Second):
		panic("timeout")
	}
}

type MockPOCCentralHandlerImpl struct {
	mock.Mock
	centralhandler.CentralHandler
}

func (m *MockPOCCentralHandlerImpl) SendTenantAdminEmailOnce(tenantID uint, key string, templateID string, vars map[string]string) error {
	m.Called(tenantID, key, templateID, vars)
	return nil
}

func (m *MockPOCCentralHandlerImpl) SendTenantManagerEmailOnce(tenantID uint, key string, templateID string, vars map[string]string) error {
	m.Called(tenantID, key, templateID, vars)
	return nil
}

func (m *MockPOCCentralHandlerImpl) ResetOnceEmailStatus(tenantID uint, key string) error {
	m.Called(tenantID, key)
	return nil
}

func (m *MockPOCCentralHandlerImpl) GetTenant(tenantID uint) (*forms.Tenant, error) {
	if tenantID == 1 {
		return &forms.Tenant{
			TenantID: tenantID,
			Status:   centralhandler.TenantStatusActive,
			Kind:     forms.TenantKindInternal,
		}, nil
	}
	if tenantID == 2 {
		return &forms.Tenant{
			TenantID: tenantID,
			Status:   centralhandler.TenantStatusActive,
			Kind:     forms.TenantKindExternal,
		}, nil
	}

	return &forms.Tenant{
		TenantID: tenantID,
		Status:   centralhandler.TenantStatusActive,
	}, nil
}

type MockPOCInfraHandlerImpl struct {
	infrahandler.InfraHandler
	mock.Mock
}

func (m *MockPOCInfraHandlerImpl) CleanupTenantDedicateClusters(tenantID uint) error {
	m.Called(tenantID)
	return nil
}
func (m *MockPOCInfraHandlerImpl) CleanupTenantBackups(tenantID uint) error {
	m.Called(tenantID)
	return nil
}

func (m *MockPOCInfraHandlerImpl) GetCluster(tenantID, clusterID uint) (ret *forms.Cluster, err error) {
	m.Called(tenantID, clusterID)
	return &forms.Cluster{
		ID:       clusterID,
		Name:     constant.UnknownClusterName,
		TenantID: tenantID,
	}, nil
}
func drainChannel(ch chan *forms.TenantPlanEvent) {
	for {
		select {
		case <-ch:
		// skip
		case <-time.After(2 * time.Second):
			panic("timeout")
		default:
			return
		}
	}
}

func (suite *TenantPOCPlanSuite) TestPOCCleanup() {
	assert := suite.Assert()
	//var BillingDate = time.Date(2021, 11, 1, 0, 0, 0, 0, time.UTC)
	config.Get().Set(config.PocAfterNoPayable, time.Date(2021, 10, 1, 0, 0, 0, 0, time.UTC))

	var err error
	eb, err := tests.NewLocalEventBusHandler()
	assert.NoError(err)
	err = eventbushandler.Get().Close()
	assert.NoError(err)
	eventbushandler.Set(eb)
	ch := make(chan *forms.TenantPlanEvent)
	err = eventbushandler.Get().RegisterEventHandleFunc(plan.TenantPlanEventType, "1", forms.TenantPlanEvent{}, func(event *eventbushandler.Event) error {
		ch <- event.EventData.(*forms.TenantPlanEvent)
		return nil
	})
	assert.NoError(err)
	err = eb.Run()
	assert.NoError(err)

	tenantID := uint(1)
	model := &plan.TenantPlanModel{}
	timeutils.SetMockNow(datainit.BillingDate)

	err = model.EnableTenantPOCPlanAfterCreditsOpened(tenantID)
	assert.NoError(err)
	select {
	case eData := <-ch:
		assert.Equal(entity.TenantPlan_POC, eData.ChangedPlan)
		assert.Equal(entity.TenantPlanStatus_Active, eData.ChangedStatus)
	case <-time.After(2 * time.Second):
		panic("timeout")
	}

	creditsModel := &marketing.CreditsPackageModel{}
	err = creditsModel.CloseCreditsPackage(suite.creditPackage.CreditsPackageID, "")
	assert.NoError(err)
	cPackage, _ := creditsModel.GetCreditsPackage(suite.creditPackage.CreditsPackageID)
	mockCentral := &MockPOCCentralHandlerImpl{}
	centralhandler.SetCentralHandler(mockCentral)
	mockCentral.On("SendTenantAdminEmailOnce", tenantID, mock.Anything, plan.TemplateID_PocCreditsExhaust_Inner, mock.Anything).Return(nil)
	mockCentral.On("SendTenantManagerEmailOnce", tenantID, mock.Anything, plan.TemplateID_PocCreditsExhaust_Inner, mock.Anything).Return(nil)

	err = model.DisableTenantPOCPlanAfterCreditsExhausted(cPackage.CreditsPackageID)
	assert.NoError(err)
	assert.Len(mockCentral.Calls, 2)

	select {
	case eData := <-ch:
		assert.Equal(entity.TenantPlan_POC, eData.ChangedPlan)
		assert.Equal(entity.TenantPlanStatus_Closing, eData.ChangedStatus)
	case <-time.After(2 * time.Second):
		panic("timeout")
	}

	time.Sleep(2000 * time.Millisecond)

	drainChannel(ch)

	// tenantID 2  forms.TenantKindInternal
	tenantID2 := uint(2)
	err = model.EnableTenantPOCPlanAfterCreditsOpened(tenantID2)
	assert.NoError(err)

	select {
	case eData := <-ch:
		assert.Equal(entity.TenantPlan_POC, eData.ChangedPlan)
		assert.Equal(entity.TenantPlanStatus_Active, eData.ChangedStatus)
	case <-time.After(2 * time.Second):
		panic("timeout")
	}
	err = creditsModel.CloseCreditsPackage(suite.creditPackage2.CreditsPackageID, "")
	assert.NoError(err)
	cPackage2, _ := creditsModel.GetCreditsPackage(suite.creditPackage2.CreditsPackageID)

	mockCentral.On("SendTenantAdminEmailOnce", tenantID2, mock.Anything, plan.TemplateID_PocCreditsExhaust, mock.Anything).Return(nil)
	mockCentral.On("SendTenantManagerEmailOnce", tenantID2, mock.Anything, plan.TemplateID_PocCreditsExhaust, mock.Anything).Return(nil)
	err = model.DisableTenantPOCPlanAfterCreditsExhausted(cPackage2.CreditsPackageID)
	assert.NoError(err)

	select {
	case eData := <-ch:
		assert.Equal(tenantID2, eData.TenantID)
		assert.Equal(entity.TenantPlan_POC, eData.ChangedPlan)
		assert.Equal(entity.TenantPlanStatus_Closed, eData.ChangedStatus)
	case <-time.After(2 * time.Second):
		panic("timeout")
	}

	err = model.POCCleanup(tenantID2)
	assert.NoError(err)

	assert.Len(mockCentral.Calls, 4)

	info, err := model.GetTenantPOCPlanInfo(tenantID)
	assert.NoError(err)
	assert.Equal(info.Status, entity.TenantPlanStatus_Closing)
	err = model.POCCleanup(tenantID)
	assert.NoError(err)
	info, err = model.GetTenantPOCPlanInfo(tenantID)
	assert.NoError(err)
	assert.Equal(info.Status, entity.TenantPlanStatus_Closed)

	mockInfra := &MockPOCInfraHandlerImpl{}
	infrahandler.Set(mockInfra)

	mockInfra.On("CleanupTenantDedicateClusters", tenantID).Return(nil)
	assert.Len(mockInfra.Calls, 0)

	mockCentral.Calls = nil
	events := eb.GetAllEvents()
	err = model.POCCleanup(tenantID)
	assert.NoError(err)
	assert.Len(eb.GetAllEvents(), len(events)) // no new event

	mockCentral.Calls = nil
	mockInfra.On("CleanupTenantBackups", tenantID).Return(nil)
	assert.Len(mockInfra.Calls, 0)
}
