package util

import (
	"context"
	"testing"
	"time"

	"github.com/golang/mock/gomock"
	"github.com/pingcap/dbaas/central/config"
	"github.com/pingcap/dbaas/central/db/entity"
	"github.com/pingcap/dbaas/central/infra-api/mock_infraapi"
	. "github.com/smartystreets/goconvey/convey"
	"github.com/stretchr/testify/assert"
	"github.com/tidbcloud/idl/pbgen/proto/central"
	cloudv1 "github.com/tidbcloud/infra-api/api/v1"
	"github.com/tidbcloud/pkgv2/clusterproxy"
	"github.com/tidbcloud/pkgv2/clusterproxy/mock_clusterproxy"
	mock_encrypt "github.com/tidbcloud/pkgv2/secret/encrypt/mock_encryptor"
	apierrors "k8s.io/apimachinery/pkg/api/errors"
	"k8s.io/apimachinery/pkg/runtime/schema"
)

func TestValidateCidr(t *testing.T) {
	trafficFilter1 := &central.TrafficFilterList{
		Cidrs: []*central.TrafficFilter{
			{
				Cidr:        "0.0.0.0/0",
				Description: "xxxttt",
			},
			{
				Cidr:        "0.0.0.0/0",
				Description: "xxxttt",
			},
		},
	}
	trafficFilter2 := &central.TrafficFilterList{
		Cidrs: []*central.TrafficFilter{
			{
				Cidr:        "0.0.0.0/0",
				Description: "xxxttt",
			},
			{
				Cidr:        "0.0.0.1/0",
				Description: "xxxttt",
			},
		},
	}

	// Cidr duplicate, update failed
	err := ValidateCidr(trafficFilter1)
	assert.NotNil(t, err)

	// Cidr invalid, update failed
	err = ValidateCidr(trafficFilter2)
	assert.NotNil(t, err)
}

func TestExecuteSqlCommon(t *testing.T) {
	Convey("TestExecuteSqlCommon", t, func() {
		var (
			err error
		)
		ctrl := gomock.NewController(t)
		defer ctrl.Finish()
		ctx := context.Background()
		mockInfraCli := mock_infraapi.NewMockInfraFacade(ctrl)
		mockEncryptorCli := mock_encrypt.NewMockEncryptor(ctrl)
		mockClusterproxy := mock_clusterproxy.NewMockClusterProxy(ctrl)
		mockGetProxy := func(clusterID uint64, status cloudv1.ClusterStatus, timeout int) (clusterproxy.ClusterProxy, error) {
			return mockClusterproxy, nil
		}
		cluster := &entity.Cluster{
			Updatable: entity.Updatable{
				Base: entity.Base{
					ID:        entity.ID(1),
					CreatedAt: time.Now().Add(-24 * time.Hour),
				},
			},
		}

		Convey("not found should be nil", func() {
			mockInfraCli.EXPECT().GetCluster(ctx, gomock.Any(), gomock.Any()).Return(nil, apierrors.NewNotFound(schema.GroupResource{Group: "cloudv1", Resource: "cluster"}, "test"))
			err = ExecuteSqlCommon(
				ctx,
				cluster,
				"",
				mockInfraCli,
				mockEncryptorCli,
				mockGetProxy,
				config.DefaultClusterProxyTimeout,
			)
			So(err, ShouldBeNil)
		})

		Convey("set success err should be nil", func() {
			mockInfraCli.EXPECT().GetCluster(ctx, gomock.Any(), gomock.Any()).Return(
				&cloudv1.Cluster{Status: cloudv1.ClusterStatus{DB: &cloudv1.DBStatus{Version: "5.3"}}},
				nil,
			)
			mockClusterproxy.EXPECT().ExecuteSQL(ctx, gomock.Any(), gomock.Any()).Return(nil)
			err = ExecuteSqlCommon(
				ctx,
				cluster,
				"",
				mockInfraCli,
				mockEncryptorCli,
				mockGetProxy,
				config.DefaultClusterProxyTimeout,
			)
			So(err, ShouldBeNil)
		})
	})
}
