package dm_svc

import (
	"context"
	"testing"

	dmapi "github.com/tidbcloud/pkgv2/clusterproxy/serverless/dm"
	"github.com/tidbcloud/serverless-service/internal/domain/constant"
	"github.com/tidbcloud/serverless-service/internal/domain/entity"
	"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"
	"k8s.io/utils/pointer"
)

func TestOnTaskCreatingOnlySetsShardModeWhenConfigured(t *testing.T) {
	tests := []struct {
		name      string
		shardMode *dmapi.TaskShardMode
		wantNil   bool
		want      dmapi.TaskShardMode
	}{
		{name: "omitted", shardMode: nil, wantNil: true},
		{name: "configured", shardMode: dmapi.TASKSHARDMODE_OPTIMISTIC.Ptr(), want: dmapi.TASKSHARDMODE_OPTIMISTIC},
	}

	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {
			ctrl := gomock.NewController(t)
			defer ctrl.Finish()

			provider := mock_facade.NewMockClusterProxyProviderFacade(ctrl)
			encryptor := mock_facade.NewMockEncryptorFacade(ctrl)
			proxy := mock_facade.NewMockServerlessClusterProxyFacade(ctrl)
			dmTaskRepo := mock_repo.NewMockDMTaskRepo(ctrl)

			provider.EXPECT().
				GetServerlessHTTPProxy(
					gomock.Any(),
					"http://cluster-proxy/proxy/namespace/test/cluster/test",
					gomock.Eq(pointer.String(constant.ServerlessNamespace)),
					gomock.Eq(pointer.String(constant.DMServiceName)),
				).
				Return(proxy, nil)
			encryptor.EXPECT().DecryptBase64("encrypted").Return("plain-password", nil)

			proxy.EXPECT().
				CreateServerlessDMTask(gomock.Any(), gomock.Any()).
				DoAndReturn(func(_ context.Context, req *dmapi.CreateTaskRequest) (*dmapi.OperateTaskResponse, error) {
					switch {
					case tt.wantNil && req.Task.ShardMode != nil:
						t.Fatalf("expected shard mode to be omitted, got %v", *req.Task.ShardMode)
					case !tt.wantNil && req.Task.ShardMode == nil:
						t.Fatal("expected shard mode to be set")
					case !tt.wantNil && *req.Task.ShardMode != tt.want:
						t.Fatalf("unexpected shard mode: got %v want %v", *req.Task.ShardMode, tt.want)
					}
					return &dmapi.OperateTaskResponse{}, nil
				})
			proxy.EXPECT().
				StartServerlessDMTask(gomock.Any(), "task-1", gomock.Any()).
				Return(nil)
			dmTaskRepo.EXPECT().
				UpdateTask(gomock.Any(), "task-1", []constant.DMTaskStage{constant.DMTaskStageTaskCreating}, gomock.Any()).
				Return(nil)

			worker := &DMTaskWorker{
				dmTaskRepo:                 dmTaskRepo,
				clusterProxyProviderFacade: provider,
				encryptorFacade:            encryptor,
			}

			err := worker.OnTaskCreating(context.Background(), &entity.DMTask{
				ID:                      "task-1",
				Name:                    "task-1",
				Stage:                   constant.DMTaskStageTaskCreating,
				TenantID:                "tenant-1",
				Region:                  "us-east-1",
				CloudProvider:           "aws",
				Mode:                    constant.DMTaskModeAll,
				TargetUser:              "tidb",
				TargetEncryptedPassword: "encrypted",
				ShardMode:               tt.shardMode,
				DMSources: []entity.DMSource{
					{
						ID:       "src-1",
						DMTaskID: "task-1",
					},
				},
			}, &dmTaskRuntime{clusterProxyURL: "http://cluster-proxy/proxy/namespace/test/cluster/test"})
			if err != nil {
				t.Fatalf("expected no error, got %v", err)
			}
		})
	}
}
