package ops_svc

import (
	"testing"

	"github.com/stretchr/testify/assert"
	"github.com/stretchr/testify/require"
	rpc "github.com/tidbcloud/serverless-service/idl/pbgen/proto/rpc"
	"github.com/tidbcloud/serverless-service/internal/domain/constant"
)

func TestValidatePoolTransition(t *testing.T) {
	tests := []struct {
		name        string
		currentPool string
		targetPool  string
		expectError bool
	}{
		{"tidb-pool to self", constant.TidbPoolNameFree, constant.TidbPoolNameFree, false},
		{
			"tidb-pool to canary-tidb-pool",
			constant.TidbPoolNameFree,
			constant.CanaryPoolPrefix + constant.TidbPoolNameFree,
			false,
		},
		{"tidb-pool to vip-tidb-pool", constant.TidbPoolNameFree, constant.TidbPoolNameVip, false},
		{
			"tidb-pool to canary-vip-tidb-pool",
			constant.TidbPoolNameFree,
			constant.CanaryPoolPrefix + constant.TidbPoolNameVip,
			false,
		},

		{"vip-tidb-pool to self", constant.TidbPoolNameVip, constant.TidbPoolNameVip, false},
		{
			"vip-tidb-pool to canary-vip-tidb-pool",
			constant.TidbPoolNameVip,
			constant.CanaryPoolPrefix + constant.TidbPoolNameVip,
			false,
		},
		{"vip-tidb-pool to super-vip-tidb-pool", constant.TidbPoolNameVip, constant.TidbPoolNameSuper, false},
		{
			"vip-tidb-pool to canary-super-vip-tidb-pool",
			constant.TidbPoolNameVip,
			constant.CanaryPoolPrefix + constant.TidbPoolNameSuper,
			false,
		},

		{"super-vip-tidb-pool to self", constant.TidbPoolNameSuper, constant.TidbPoolNameSuper, false},
		{
			"super-vip-tidb-pool to canary-super-vip-tidb-pool",
			constant.TidbPoolNameSuper,
			constant.CanaryPoolPrefix + constant.TidbPoolNameSuper,
			false,
		},

		{
			"canary-tidb-pool to self",
			constant.CanaryPoolPrefix + constant.TidbPoolNameFree,
			constant.CanaryPoolPrefix + constant.TidbPoolNameFree,
			false,
		},
		{
			"canary-tidb-pool to canary-vip-tidb-pool",
			constant.CanaryPoolPrefix + constant.TidbPoolNameFree,
			constant.CanaryPoolPrefix + constant.TidbPoolNameVip,
			false,
		},
		{
			"canary-tidb-pool to tidb-pool",
			constant.CanaryPoolPrefix + constant.TidbPoolNameFree,
			constant.TidbPoolNameFree,
			false,
		},
		{
			"canary-tidb-pool to vip-tidb-pool",
			constant.CanaryPoolPrefix + constant.TidbPoolNameFree,
			constant.TidbPoolNameVip,
			false,
		},

		{
			"canary-vip-tidb-pool to self",
			constant.CanaryPoolPrefix + constant.TidbPoolNameVip,
			constant.CanaryPoolPrefix + constant.TidbPoolNameVip,
			false,
		},
		{
			"canary-vip-tidb-pool to canary-super-vip-tidb-pool",
			constant.CanaryPoolPrefix + constant.TidbPoolNameVip,
			constant.CanaryPoolPrefix + constant.TidbPoolNameSuper,
			false,
		},
		{
			"canary-vip-tidb-pool to vip-tidb-pool",
			constant.CanaryPoolPrefix + constant.TidbPoolNameVip,
			constant.TidbPoolNameVip,
			false,
		},

		{
			"canary-super-vip-tidb-pool to self",
			constant.CanaryPoolPrefix + constant.TidbPoolNameSuper,
			constant.CanaryPoolPrefix + constant.TidbPoolNameSuper,
			false,
		},
		{
			"canary-super-vip-tidb-pool to super-vip-tidb-pool",
			constant.CanaryPoolPrefix + constant.TidbPoolNameSuper,
			constant.TidbPoolNameSuper,
			false,
		},

		{"tidb-pool to super-vip-tidb-pool directly", constant.TidbPoolNameFree, constant.TidbPoolNameSuper, true},
	}

	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {
			err := validatePoolTransition(supportedTiDBPoolTransitions, tt.currentPool, tt.targetPool)
			if tt.expectError {
				require.Error(t, err)
			} else {
				assert.NoError(t, err)
			}
		})
	}
}

func TestParseTiDBPool(t *testing.T) {
	tests := []struct {
		name      string
		poolEnum  int32
		expected  string
		expectErr bool
	}{
		{"TIDB_POOL_DEFAULT", int32(rpc.TiDBPool_TIDB_POOL_DEFAULT), constant.TidbPoolNameFree, false},
		{"TIDB_POOL_VIP", int32(rpc.TiDBPool_TIDB_POOL_VIP), constant.TidbPoolNameVip, false},
		{"TIDB_POOL_SUPER_VIP", int32(rpc.TiDBPool_TIDB_POOL_SUPER_VIP), constant.TidbPoolNameSuper, false},
		{"INVALID_POOL", int32(999), "", true},
	}

	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {
			result, err := parseTiDBPool(rpc.TiDBPool(tt.poolEnum))
			if tt.expectErr {
				require.Error(t, err)
			} else {
				require.NoError(t, err)
				assert.Equal(t, tt.expected, result)
			}
		})
	}
}
