package tests

import (
	"context"
	"fmt"
	"testing"
	"time"

	"github.com/pingcap/dbaas/central/db"
	"github.com/pingcap/dbaas/central/db/entity"
	"github.com/pingcap/dbaas/central/db/tenant"
	"github.com/pingcap/dbaas/central/handler/billing2"
	"github.com/pingcap/dbaas/central/model/billing"
	"github.com/pingcap/dbaas/central/test"
	"github.com/pingcap/log"
	"github.com/stretchr/testify/mock"
	"github.com/stretchr/testify/suite"
	"gorm.io/gorm"
)

type BillingDevTierTestSuite struct {
	test.CentralTestSuite
	tenant         *entity.Tenant
	model          billing.Model
	context        billing.Context
	db             *gorm.DB
	billingHandler *MockBillingHandlerDevTier
	mail           *MockMailHandler
}

func TestDevTierSuite(t *testing.T) {
	suite.Run(t, new(BillingDevTierTestSuite))
}

func (s *BillingDevTierTestSuite) SetupTest() {
	s.CentralTestSuite.SetupTest()
	s.createTenantAndAdminUser()
	s.createModelAndContext()
}

type MockBillingHandlerDevTier struct {
	billing2.BillingHandler
	mock.Mock
}

func (m *MockBillingHandlerDevTier) BindPackage(tenantID, packageID uint64) (uint64, error) {
	return m.Called().Get(0).(uint64), nil
}

func (s *BillingDevTierTestSuite) createBillingHandler() {
	s.billingHandler = &MockBillingHandlerDevTier{}
	s.billingHandler.On("BindPackage").Return(uint64(1), nil)
	billing2.SetHandler(s.billingHandler)

}

func (s *BillingDevTierTestSuite) createModelAndContext() {
	mailHandler := &MockMailHandler{}
	mailHandler.On("SendMailWithTemplate").Return().Maybe()
	s.mail = mailHandler
	s.model = billing.NewModel(log.L(), s.mail, &MockSalesforceHandler{})
	s.context = s.model.User(&tenant.User{TenantID: s.tenant.ID})
	s.createBillingHandler()
}

func (s *BillingDevTierTestSuite) createTenantAndAdminUser() {
	dbProvider := db.NewProvider()
	ctx := context.Background()
	s.db = dbProvider.WriteDB(ctx)
	tenant := &entity.Tenant{
		Name:          "unittest tenant",
		Email:         "unittest@pingcap.com",
		Country:       "CN",
		TimeZone:      "8",
		Status:        entity.TenantStatusActive,
		Plan:          entity.TenantPlanNewUser,
		AcceptService: false,
		ZendeskID:     0,
		Quotas:        nil,
		BillingEmail:  "",
	}
	err := tenant.Create(s.db)
	if err != nil {
		s.FailNow("failed to create tenant for test %s", err)
	}
	// init fake user
	dbUser := &entity.User{
		TenantID:  tenant.ID,
		FirstName: "FirstName",
		LastName:  "LastName",
		Email:     "unittest@pingcap.com",
		Status:    entity.UserStatusActive,
	}

	err = dbUser.Create(s.db)
	if err != nil {
		s.FailNow("failed to create tenant for user %s", err)
	}

	s.tenant = tenant
}

func (s *BillingDevTierTestSuite) TestPrepareDevTier() {
	assert := s.Assert()
	_ = assert
	enable, err := s.context.IsOrgDevTierEnabled()
	assert.NoError(err)
	assert.False(enable)

	err = s.context.PrepareDevTier()
	assert.NoError(err)
	s.billingHandler.AssertCalled(s.T(), "BindPackage", mock.Anything)
}

func (s *BillingDevTierTestSuite) TestEnableDevTier() {
	assert := s.Assert()
	_ = assert
	enable, err := s.context.IsOrgDevTierEnabled()
	assert.NoError(err)
	assert.False(enable)

	err = s.context.EnableOrgDevTier()
	assert.NoError(err)

	enable, err = s.context.IsOrgDevTierEnabled()
	assert.NoError(err)
	assert.True(enable)

	err = s.context.EnableOrgDevTier()
	assert.NoError(err)
}

func (s *BillingDevTierTestSuite) TestCanEnableDevTier() {
	assert := s.Assert()
	_ = assert
	enable, err := s.context.CanOrgDevTierEnable()
	assert.NoError(err)
	assert.True(enable)

	err = s.context.EnableOrgDevTier()
	assert.NoError(err)

	enable, err = s.context.CanOrgDevTierEnable()
	assert.NoError(err)
	assert.True(enable)
}

func (s *BillingDevTierTestSuite) TestGetDevTierStage() {
	assert := s.Assert()
	_ = assert
	err := s.context.EnableOrgDevTier()
	assert.NoError(err)

	stage, err := s.context.GetDevTierStage(time.Now())
	assert.NoError(err)
	fmt.Println(stage)
	now := time.Now().Add(time.Hour * 30 * 30)
	stage, err = s.context.GetDevTierStage(now)
	assert.NoError(err)
	fmt.Println(stage)
}
