package main

import (
	"context"
	"testing"

	"buf.build/go/protovalidate"
	protovalidate_middleware "github.com/grpc-ecosystem/go-grpc-middleware/v2/interceptors/protovalidate"
	"github.com/stretchr/testify/require"
	"google.golang.org/grpc"
	"google.golang.org/grpc/codes"
	"google.golang.org/grpc/status"

	apiv1 "github.com/tidbcloud/infra-provider/api/tidbcloud/cluster-server/v1"
	apicommon "github.com/tidbcloud/infra-provider/api/tidbcloud/common"
)

const testProtoValidateClusterID = "cluster-1"

func TestProtoValidateUnaryInterceptorRejectsInvalidExistingRPCs(t *testing.T) {
	interceptor := newTestProtoValidateUnaryInterceptor(t)

	handlerCalled := false
	resp, err := interceptor(
		context.Background(),
		&apiv1.SetVersionAndConfigurationsRequest{
			ClusterId:      testProtoValidateClusterID,
			Strategy:       apiv1.SetVersionAndConfigurationsRequest_Strategy(99),
			IdempotencyKey: "invalid-idempotency-key",
		},
		&grpc.UnaryServerInfo{FullMethod: apiv1.ClusterService_SetVersionAndConfigurations_FullMethodName},
		func(ctx context.Context, req any) (any, error) {
			handlerCalled = true
			return "existing rpc handler response", nil
		},
	)

	require.Error(t, err)
	require.Equal(t, codes.InvalidArgument, status.Code(err))
	require.False(t, handlerCalled)
	require.Nil(t, resp)
}

func TestProtoValidateUnaryInterceptorRejectsInvalidHeterogeneousRPCs(t *testing.T) {
	interceptor := newTestProtoValidateUnaryInterceptor(t)

	handlerCalled := false
	resp, err := interceptor(
		context.Background(),
		&apiv1.CreateGKEHeterogeneousDeployRequest{
			ClusterId:     testProtoValidateClusterID,
			ComponentType: apicommon.ComponentType_TIKV,
		},
		&grpc.UnaryServerInfo{FullMethod: apiv1.ClusterService_CreateGKEHeterogeneousDeploy_FullMethodName},
		func(ctx context.Context, req any) (any, error) {
			handlerCalled = true
			return &apiv1.GKEHeterogeneousDeploy{}, nil
		},
	)

	require.Error(t, err)
	require.Equal(t, codes.InvalidArgument, status.Code(err))
	require.False(t, handlerCalled)
	require.Nil(t, resp)
}

func TestProtoValidateUnaryInterceptorAllowsValidHeterogeneousRPCs(t *testing.T) {
	interceptor := newTestProtoValidateUnaryInterceptor(t)

	handlerCalled := false
	resp, err := interceptor(
		context.Background(),
		&apiv1.CreateGKEHeterogeneousDeployRequest{
			ClusterId:     testProtoValidateClusterID,
			ComponentType: apicommon.ComponentType_TIKV,
			InstanceTypes: []string{"n2-standard-32"},
			NodePoolNames: []string{"tikv-0", "tikv-extra"},
		},
		&grpc.UnaryServerInfo{FullMethod: apiv1.ClusterService_CreateGKEHeterogeneousDeploy_FullMethodName},
		func(ctx context.Context, req any) (any, error) {
			handlerCalled = true
			return &apiv1.GKEHeterogeneousDeploy{Enabled: true}, nil
		},
	)

	require.NoError(t, err)
	require.True(t, handlerCalled)
	require.Equal(t, &apiv1.GKEHeterogeneousDeploy{Enabled: true}, resp)
}

func newTestProtoValidateUnaryInterceptor(t *testing.T) grpc.UnaryServerInterceptor {
	t.Helper()

	validator, err := protovalidate.New()
	require.NoError(t, err)

	return protovalidate_middleware.UnaryServerInterceptor(validator)
}
