package event_svc

import (
	"context"
	"testing"

	. "github.com/onsi/gomega"
	core_event "github.com/tidbcloud/core-svc/event"
	"github.com/tidbcloud/pkgv2/bizerr"
	"github.com/tidbcloud/pkgv2/db/mock_db"
	"github.com/tidbcloud/serverless-service/internal/domain/facade"
	"github.com/tidbcloud/serverless-service/internal/domain/facade/mock_facade"
	"github.com/tidbcloud/serverless-service/internal/domain/repo/mock_repo"
	"go.uber.org/mock/gomock"
)

func Test_ClusterEventService_HandleEvent(t *testing.T) {
	g := NewGomegaWithT(t)
	ctx := context.Background()
	ctrl := gomock.NewController(t)
	defer ctrl.Finish()
	billingFacade := mock_facade.NewMockBillingFacade(ctrl)
	clusterRepo := mock_repo.NewMockClusterRepo(ctrl)
	clusterTidbPool := mock_repo.NewMockClusterTidbPoolRepo(ctrl)
	canaryRepo := mock_repo.NewMockCanaryRepo(ctrl)
	dbProvider := mock_db.NewMockTransProvider(ctrl)
	mgmtFacade := mock_facade.NewMockMgmtSvcFacade(ctrl)
	accountFacade := mock_facade.NewMockAccountFacade(ctrl)
	svc := NewClusterEventService(
		billingFacade,
		clusterRepo,
		clusterTidbPool,
		canaryRepo,
		dbProvider,
		mgmtFacade,
		accountFacade,
	)

	canaryRepo.EXPECT().GetProject(gomock.Any(), gomock.Any()).Return(nil, nil).AnyTimes()
	canaryRepo.EXPECT().AddClusters(gomock.Any(), gomock.Any()).Return(nil).AnyTimes()
	clusterRepo.EXPECT().
		GetClusterByID(gomock.Any(), gomock.Any()).
		Return(nil, bizerr.New(bizerr.ErrCodeUnknown, "not found")).
		AnyTimes()
	mgmtFacade.EXPECT().GetCluster(gomock.Any(), gomock.Any(), gomock.Any()).Return(nil, nil).AnyTimes()
	accountFacade.EXPECT().GetTenant(gomock.Any(), gomock.Any()).Return(nil, nil).AnyTimes()

	event := &core_event.ClusterEvent{
		ClusterID: 1,
		TenantID:  101,
		ProjectID: 1001,
		IsDevTier: true,
		EventType: core_event.ClusterEventTypeDeleted,
	}

	dbProvider.EXPECT().Transaction(gomock.Any(), gomock.Any()).DoAndReturn(func(ctx context.Context,
		cb func(ctx context.Context) error,
	) error {
		return svc.handleCreatedImpl(ctx, event.ClusterID, event.ProjectID)
	}).AnyTimes()

	setting := &facade.SpendLimitSetting{
		SpendLimitSettingID: 8001,
		TenantID:            101,
		RangeID:             1,
		RangeType:           "cluster",
	}

	{
		err := bizerr.New(bizerr.ErrCodeDB, "failed to remove")
		billingFacade.EXPECT().GetSpendLimit(gomock.Any(), uint64(101), uint64(1)).Return(setting, nil)
		billingFacade.EXPECT().DeleteSpendLimit(gomock.Any(), uint64(101), uint64(8001)).Return(nil)
		clusterRepo.EXPECT().Remove(gomock.Any(), uint64(1)).Return(err)
		g.Expect(svc.HandleEvent(ctx, event)).To(Equal(err))
	}
	{
		err := bizerr.New(bizerr.ErrCodeUnknown, "failed to get Spending Limit settings")
		clusterRepo.EXPECT().Remove(gomock.Any(), uint64(1)).Return(nil)
		billingFacade.EXPECT().GetSpendLimit(gomock.Any(), uint64(101), uint64(1)).Return(nil, err)
		g.Expect(svc.HandleEvent(ctx, event)).To(Succeed())
	}
	{
		err := bizerr.New(bizerr.ErrCodeUnknown, "failed to delete Spending Limit")
		clusterRepo.EXPECT().Remove(gomock.Any(), uint64(1)).Return(nil)
		billingFacade.EXPECT().GetSpendLimit(gomock.Any(), uint64(101), uint64(1)).Return(setting, nil)
		billingFacade.EXPECT().DeleteSpendLimit(gomock.Any(), uint64(101), uint64(8001)).Return(err)
		g.Expect(svc.HandleEvent(ctx, event)).To(Succeed())
	}
	clusterRepo.EXPECT().Remove(gomock.Any(), uint64(1)).Return(nil)
	billingFacade.EXPECT().GetSpendLimit(gomock.Any(), uint64(101), uint64(1)).Return(setting, nil)
	billingFacade.EXPECT().DeleteSpendLimit(gomock.Any(), uint64(101), uint64(8001)).Return(nil)
	g.Expect(svc.HandleEvent(ctx, event)).To(Succeed())
	{
		err := bizerr.New(bizerr.ErrCodeUnknown, "failed to save cluster tidb pool event")
		event.EventType = core_event.ClusterEventTypeCreated
		clusterTidbPool.EXPECT().Save(gomock.Any(), gomock.Any()).Return(err)
		g.Expect(svc.HandleEvent(ctx, event)).To(Equal(err))
	}
	event.EventType = core_event.ClusterEventTypeCreated
	clusterTidbPool.EXPECT().Save(gomock.Any(), gomock.Any()).Return(nil)
	g.Expect(svc.HandleEvent(ctx, event)).To(Succeed())
}
