package vo

import (
	"context"
	"testing"

	dmapi "github.com/tidbcloud/pkgv2/clusterproxy/serverless/dm"
	v1beta1 "github.com/tidbcloud/serverless-service/idl/pbgen/proto/v1beta1"
	tidbmgmtservicev1 "github.com/tidbcloud/tidb-management-service/api/spec/tidb_mgmt_service/v1"
)

func TestConvertV1beta1ShardModeToDMShardMode(t *testing.T) {
	tests := []struct {
		name      string
		shardMode *v1beta1.TaskShardMode
		want      *dmapi.TaskShardMode
		wantErr   bool
	}{
		{name: "omitted", shardMode: nil, want: nil, wantErr: false},
		{
			name:      "pessimistic",
			shardMode: enumPtr(v1beta1.TaskShardMode_PESSIMISTIC),
			want:      dmapi.TASKSHARDMODE_PESSIMISTIC.Ptr(),
			wantErr:   false,
		},
		{
			name:      "optimistic",
			shardMode: enumPtr(v1beta1.TaskShardMode_OPTIMISTIC),
			want:      dmapi.TASKSHARDMODE_OPTIMISTIC.Ptr(),
			wantErr:   false,
		},
		{
			name:      "unspecified",
			shardMode: enumPtr(v1beta1.TaskShardMode_SHARD_MODE_UNSPECIFIED),
			want:      nil,
			wantErr:   true,
		},
	}

	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {
			got, err := ConvertV1beta1ShardModeToDMShardMode(tt.shardMode)
			if tt.wantErr && err == nil {
				t.Fatal("expected error, got nil")
			}
			if !tt.wantErr && err != nil {
				t.Fatalf("expected no error, got %v", err)
			}
			switch {
			case got == nil && tt.want == nil:
			case got == nil || tt.want == nil:
				t.Fatalf("unexpected nil mismatch: got=%v want=%v", got, tt.want)
			case *got != *tt.want:
				t.Fatalf("unexpected shard mode: got=%s want=%s", *got, *tt.want)
			}
		})
	}
}

func TestCreateV1beta1TaskReqToDMTaskPersistsShardMode(t *testing.T) {
	req := validReq()
	req.ShardMode = enumPtr(v1beta1.TaskShardMode_OPTIMISTIC)

	task, err := CreateV1beta1TaskReqToDMTask(context.Background(), req, validCluster())
	if err != nil {
		t.Fatalf("expected no error, got %v", err)
	}
	if task.ShardMode == nil {
		t.Fatal("expected shard mode to be persisted")
	}
	if *task.ShardMode != dmapi.TASKSHARDMODE_OPTIMISTIC {
		t.Fatalf("unexpected shard mode: got=%s", *task.ShardMode)
	}
}

func validReq() *v1beta1.CreateMigrationReq {
	return &v1beta1.CreateMigrationReq{
		ClusterId:   "101",
		DisplayName: "dm-task",
		Mode:        v1beta1.TaskMode_ALL,
		Sources: []*v1beta1.Source{
			{
				SourceType: v1beta1.Source_MYSQL,
				ConnProfile: &v1beta1.ConnProfile{
					ConnType: v1beta1.ConnType_PUBLIC,
					Endpoint: &v1beta1.ConnProfile_Host{Host: "127.0.0.1"},
					Port:     3306,
					User:     "root",
					Password: "secret",
				},
			},
		},
		Target: &v1beta1.Target{
			User:     "tidb",
			Password: "encrypted",
		},
	}
}

func validCluster() *tidbmgmtservicev1.Cluster {
	return &tidbmgmtservicev1.Cluster{
		ClusterId:      101,
		ProjectId:      102,
		OrganizationId: 103,
		CloudProvider:  "aws",
		Region:         "us-east-1",
	}
}

func enumPtr[T any](v T) *T {
	return &v
}
