package v1beta1

import (
	"testing"

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

func TestValidateWildcardPattern(t *testing.T) {
	tests := []struct {
		name    string
		pattern string
		wantErr bool
	}{
		{name: "empty", pattern: "", wantErr: false},
		{name: "only_star", pattern: "*", wantErr: false},
		{name: "literal", pattern: "db1", wantErr: false},
		{name: "star_at_end", pattern: "db*", wantErr: false},
		{name: "question_mark", pattern: "db?", wantErr: false},
		{name: "char_class", pattern: "db[abc]", wantErr: false},
		{name: "char_class_with_question_and_star", pattern: "db[ab]?*", wantErr: false},
		{name: "nested_star_in_class", pattern: "db[*]", wantErr: true},
		{name: "multiple_stars", pattern: "db*a*", wantErr: true},
		{name: "star_not_at_end", pattern: "*db", wantErr: true},
		{name: "star_in_middle", pattern: "d*b", wantErr: true},
		{name: "unclosed_class", pattern: "db[ab", wantErr: true},
		{name: "unmatched_closing", pattern: "dbab]", wantErr: true},
		{name: "empty_class", pattern: "db[]", wantErr: true},
		{name: "nested_class", pattern: "db[[a]]", wantErr: true},
	}

	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {
			err := validateWildcardPattern(tt.pattern)
			if tt.wantErr && err == nil {
				t.Fatalf("expected error for pattern %q, got nil", tt.pattern)
			}
			if !tt.wantErr && err != nil {
				t.Fatalf("expected no error for pattern %q, got %v", tt.pattern, err)
			}
		})
	}
}

func TestValidateNoWildcard(t *testing.T) {
	tests := []struct {
		name    string
		value   string
		wantErr bool
	}{
		{name: "empty", value: "", wantErr: false},
		{name: "literal", value: "db1", wantErr: false},
		{name: "underscored", value: "db_01", wantErr: false},
		{name: "star", value: "db*", wantErr: true},
		{name: "question", value: "db?", wantErr: true},
		{name: "open_bracket", value: "db[ab]", wantErr: true},
		{name: "close_bracket", value: "db]", wantErr: true},
	}

	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {
			err := validateNoWildcard(tt.value, "field")
			if tt.wantErr && err == nil {
				t.Fatalf("expected error for value %q, got nil", tt.value)
			}
			if !tt.wantErr && err != nil {
				t.Fatalf("expected no error for value %q, got %v", tt.value, err)
			}
		})
	}
}

func TestValidateCreateTaskReqShardMode(t *testing.T) {
	tests := []struct {
		name      string
		shardMode *v1beta1pb.TaskShardMode
		wantErr   bool
	}{
		{name: "omitted", shardMode: nil, wantErr: false},
		{name: "pessimistic", shardMode: enumPtr(v1beta1pb.TaskShardMode_PESSIMISTIC), wantErr: false},
		{name: "optimistic", shardMode: enumPtr(v1beta1pb.TaskShardMode_OPTIMISTIC), wantErr: false},
		{name: "unspecified", shardMode: enumPtr(v1beta1pb.TaskShardMode_SHARD_MODE_UNSPECIFIED), wantErr: true},
	}

	cluster := &tidbmgmtservicev1.Cluster{CloudProvider: "aws"}
	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {
			req := validCreateMigrationReq()
			req.ShardMode = tt.shardMode

			err := validateCreateTaskReq(req, cluster)
			if tt.wantErr && err == nil {
				t.Fatal("expected error, got nil")
			}
			if !tt.wantErr && err != nil {
				t.Fatalf("expected no error, got %v", err)
			}
		})
	}
}

func validCreateMigrationReq() *v1beta1pb.CreateMigrationReq {
	return &v1beta1pb.CreateMigrationReq{
		ClusterId:   "123",
		DisplayName: "migration-test",
		Mode:        v1beta1pb.TaskMode_ALL,
		Sources: []*v1beta1pb.Source{
			{
				SourceType: v1beta1pb.Source_MYSQL,
				ConnProfile: &v1beta1pb.ConnProfile{
					ConnType: v1beta1pb.ConnType_PUBLIC,
					Endpoint: &v1beta1pb.ConnProfile_Host{Host: "127.0.0.1"},
					Port:     3306,
					User:     "root",
					Password: "secret",
				},
			},
		},
		Target: &v1beta1pb.Target{
			User:     "tidb",
			Password: "secret",
		},
	}
}

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