package del

import (
	"context"
	"testing"

	"github.com/stretchr/testify/assert"
	"github.com/stretchr/testify/mock"
	"github.com/stretchr/testify/require"
	biz_changefeed_mock "github.com/tidbcloud/dataflow-service/app/models/biz_changefeed/mock"
	"github.com/tidbcloud/dataflow-service/app/repo"
	"github.com/tidbcloud/dataflow-service/app/repo/entity"
	repo_mock "github.com/tidbcloud/dataflow-service/app/repo/mock"
	"github.com/tidbcloud/dataflow-service/app/workflow/action/biz_changefeed"
	"github.com/tidbcloud/pkgv2/bizerr"
	"github.com/tidbcloud/pkgv2/db"
	"go.uber.org/zap"
)

func TestActionFinalStep(t *testing.T) {
	mockBizChangefeedRepo := repo_mock.NewBizChangefeedRepo(t)
	testDB, err := repo.GetFakeDB()
	require.NoError(t, err)
	mockTrans := db.NewProvider(testDB)
	mockBizChangefeedHooker := biz_changefeed_mock.NewBizChangefeedHooker(t)
	action := &ActionFinalStep{
		transProvider:       mockTrans,
		bizChangefeedRepo:   mockBizChangefeedRepo,
		bizChangefeedHooker: mockBizChangefeedHooker,
	}
	params := &biz_changefeed.CommonParams{
		BizChangefeedID: 111,
	}
	logger := zap.NewNop()

	t.Run("load entity error", func(t *testing.T) {
		mockErr := bizerr.New(bizerr.ErrCodeRecordNotFound, "not found")
		call := mockBizChangefeedRepo.
			On("Load", mock.Anything, params.BizChangefeedID).
			Return(nil, mockErr)
		defer call.Unset()
		err := action.Run(context.Background(), logger, params)
		assert.Error(t, err)
		assert.Contains(t, err.Error(), "load biz_changefeed entity")
	})

	mockEnt := &entity.BizChangefeed{}
	mockEnt.ID = 1111
	loadCall := mockBizChangefeedRepo.
		On("Load", mock.Anything, params.BizChangefeedID).
		Return(mockEnt, nil)
	defer loadCall.Unset()
	t.Run("update entity error", func(t *testing.T) {
		mockErr := bizerr.New(bizerr.ErrCodeDB, "network error")
		call := mockBizChangefeedRepo.
			On("Update", mock.Anything, mock.Anything).
			Return(mockErr)
		defer call.Unset()
		err := action.Run(context.Background(), logger, params)
		assert.Error(t, err)
		assert.Contains(t, err.Error(), "update biz_changefeed status")
	})

	updateCall := mockBizChangefeedRepo.
		On("Update", mock.Anything, mock.Anything).
		Return(nil)
	defer updateCall.Unset()
	t.Run("delete entity error", func(t *testing.T) {
		mockErr := bizerr.New(bizerr.ErrCodeDB, "network error")
		call := mockBizChangefeedRepo.
			On("Delete", mock.Anything, mockEnt.ID.Uint64()).
			Return(mockErr)
		defer call.Unset()
		err := action.Run(context.Background(), logger, params)
		assert.Error(t, err)
		assert.Contains(t, err.Error(), "delete biz_changefeed")
	})

	deleteCall := mockBizChangefeedRepo.
		On("Delete", mock.Anything, mockEnt.ID.Uint64()).
		Return(nil)
	hookCall := mockBizChangefeedHooker.On(
		"HandleBizChangefeedEvent", mock.Anything, entity.DeleteChangefeed, uint64(0), mockEnt).Return()
	defer hookCall.Unset()
	defer deleteCall.Unset()
	t.Run("delete entity successfully", func(t *testing.T) {
		mockEnt.OperationStatus = entity.BizChangefeedOperationStatusDeleting
		err := action.Run(context.Background(), logger, params)
		assert.NoError(t, err)
		assert.Equal(t, entity.BizChangefeedOperationStatusDeleted, mockEnt.OperationStatus)
	})
}
