package clusterproxy_test

import (
	"context"
	"testing"

	"github.com/golang/mock/gomock"
	"github.com/stretchr/testify/assert"
	regionalpb "github.com/tidbcloud/infra-provider/api/tidbcloud/regional-server/v1"
	"github.com/tidbcloud/ticdc-service/pkg/clusterproxy"
	"github.com/tidbcloud/ticdc-service/pkg/clusterproxy/client"
	"github.com/tidbcloud/ticdc-service/pkg/config"
	"github.com/tidbcloud/ticdc-service/pkg/regionalservice/mocks"
	"google.golang.org/grpc/codes"
	"google.golang.org/grpc/status"
	apierrors "k8s.io/apimachinery/pkg/api/errors"
	"k8s.io/apimachinery/pkg/runtime/schema"
)

func TestGetClusterProxy(t *testing.T) {
	ctrl := gomock.NewController(t)
	defer ctrl.Finish()

	mockRegionalCli := mocks.NewMockClient(ctrl)
	cfg := &config.Config{}
	model := clusterproxy.NewClusterProxyModelImpl(cfg, mockRegionalCli, client.DefaultClientCreator)

	ctx := context.Background()
	clusterIdStr := "12345"
	proxyBaseUrl := "http://proxy.url"

	// Mock the GetCluster method
	mockRegionalCli.EXPECT().GetCluster(ctx, clusterIdStr).Return(&regionalpb.Cluster{
		ProxyBaseUrl: proxyBaseUrl,
	}, nil).Times(1)

	// Test the GetClusterProxy method
	proxy, err := model.GetClusterProxy(ctx, clusterIdStr, clusterproxy.CDCHeavyOperationTimeout)
	assert.NoError(t, err)
	assert.NotNil(t, proxy)
	assert.Equal(t, uint64(12345), proxy.Client().GetClusterID())

	// Test cache
	cachedProxy, err := model.GetClusterProxy(ctx, clusterIdStr, clusterproxy.CDCHeavyOperationTimeout)
	assert.NoError(t, err)
	assert.Equal(t, proxy, cachedProxy)
}

func TestGetClusterProxy_NotFound(t *testing.T) {
	ctrl := gomock.NewController(t)
	defer ctrl.Finish()

	mockRegionalCli := mocks.NewMockClient(ctrl)
	cfg := &config.Config{}
	model := clusterproxy.NewClusterProxyModelImpl(cfg, mockRegionalCli, nil)

	ctx := context.Background()
	clusterIdStr := "12345"

	// Mock the GetCluster method to return not found error
	mockRegionalCli.EXPECT().GetCluster(ctx, clusterIdStr).
		Return(nil, apierrors.NewNotFound(schema.GroupResource{}, clusterIdStr)).Times(1)

	// Test the GetClusterProxy method
	_, err := model.GetClusterProxy(ctx, clusterIdStr, clusterproxy.CDCHeavyOperationTimeout)
	assert.Error(t, err)
	assert.Equal(t, codes.NotFound, status.Code(err))
}

func TestGetClusterProxy_InternalError(t *testing.T) {
	ctrl := gomock.NewController(t)
	defer ctrl.Finish()

	mockRegionalCli := mocks.NewMockClient(ctrl)
	cfg := &config.Config{}
	model := clusterproxy.NewClusterProxyModelImpl(cfg, mockRegionalCli, nil)

	ctx := context.Background()
	clusterIdStr := "12345"

	// Mock the GetCluster method to return internal error
	mockRegionalCli.EXPECT().GetCluster(ctx, clusterIdStr).Return(nil, status.Errorf(codes.Internal, "internal error")).Times(1)

	// Test the GetClusterProxy method
	_, err := model.GetClusterProxy(ctx, clusterIdStr, clusterproxy.CDCHeavyOperationTimeout)
	assert.Error(t, err)
	assert.Equal(t, codes.Internal, status.Code(err))
}
