package app

import (
	"context"
	"testing"

	"github.com/stretchr/testify/require"
	apiv1 "github.com/tidbcloud/cluster-service-ng/api/cluster-service-ng/v1beta"
	"github.com/tidbcloud/cluster-service-ng/config"
	"google.golang.org/grpc/codes"
	"google.golang.org/grpc/status"
)

func TestSelectAutoscalePolicyGrpcServer(t *testing.T) {
	active := &appImpl{}

	selected := selectAutoscalePolicyGrpcServer(config.AutoscalePolicyConfig{}, active)
	require.IsType(t, &autoscalePolicyQuarantineServer{}, selected)

	selected = selectAutoscalePolicyGrpcServer(config.AutoscalePolicyConfig{
		Mode: config.AutoscalePolicyModeEnforce,
	}, active)
	require.IsType(t, &autoscalePolicyQuarantineServer{}, selected)

	selected = selectAutoscalePolicyGrpcServer(config.AutoscalePolicyConfig{
		Mode:            config.AutoscalePolicyModeEnforce,
		AllowAllTenants: true,
	}, active)
	require.Same(t, active, selected)
}

func TestAutoscalePolicyQuarantineServer(t *testing.T) {
	t.Parallel()

	ctx := context.Background()
	server := &autoscalePolicyQuarantineServer{}
	tests := []struct {
		name string
		call func() error
	}{
		{"GetResolvedAutoscalePolicyBundle", func() error {
			_, err := server.GetResolvedAutoscalePolicyBundle(ctx, &apiv1.GetResolvedAutoscalePolicyBundleRequest{})
			return err
		}},
		{"ApplyMaterializedAutoscalePolicies", func() error {
			_, err := server.ApplyMaterializedAutoscalePolicies(ctx, &apiv1.ApplyMaterializedAutoscalePoliciesRequest{})
			return err
		}},
		{"EvaluateAutoscalePolicy", func() error {
			_, err := server.EvaluateAutoscalePolicy(ctx, &apiv1.EvaluateAutoscalePolicyRequest{})
			return err
		}},
		{"ListAutoscalePolicies", func() error {
			_, err := server.ListAutoscalePolicies(ctx, &apiv1.ListAutoscalePoliciesRequest{})
			return err
		}},
		{"UpsertAutoscaleRuntimeGuard", func() error {
			_, err := server.UpsertAutoscaleRuntimeGuard(ctx, &apiv1.UpsertAutoscaleRuntimeGuardRequest{})
			return err
		}},
		{"DeleteAutoscaleRuntimeGuard", func() error {
			_, err := server.DeleteAutoscaleRuntimeGuard(ctx, &apiv1.DeleteAutoscaleRuntimeGuardRequest{})
			return err
		}},
		{"ListAutoscaleRuntimeGuards", func() error {
			_, err := server.ListAutoscaleRuntimeGuards(ctx, &apiv1.ListAutoscaleRuntimeGuardsRequest{})
			return err
		}},
		{"CreateOrReplaceAutoscalePolicy", func() error {
			_, err := server.CreateOrReplaceAutoscalePolicy(ctx, &apiv1.CreateOrReplaceAutoscalePolicyRequest{})
			return err
		}},
		{"PatchAutoscalePolicy", func() error {
			_, err := server.PatchAutoscalePolicy(ctx, &apiv1.PatchAutoscalePolicyRequest{})
			return err
		}},
		{"GetAutoscalePolicy", func() error {
			_, err := server.GetAutoscalePolicy(ctx, &apiv1.GetAutoscalePolicyRequest{})
			return err
		}},
		{"GetEffectiveAutoscalePolicy", func() error {
			_, err := server.GetEffectiveAutoscalePolicy(ctx, &apiv1.GetEffectiveAutoscalePolicyRequest{})
			return err
		}},
		{"ListAutoscalePolicy", func() error {
			_, err := server.ListAutoscalePolicy(ctx, &apiv1.ListAutoscalePolicyRequest{})
			return err
		}},
		{"PreviewAutoscalePolicy", func() error {
			_, err := server.PreviewAutoscalePolicy(ctx, &apiv1.PreviewAutoscalePolicyRequest{})
			return err
		}},
		{"SyncAutoscalePolicy", func() error {
			_, err := server.SyncAutoscalePolicy(ctx, &apiv1.SyncAutoscalePolicyRequest{})
			return err
		}},
	}
	require.Len(t, tests, len(apiv1.AutoscalePolicyService_ServiceDesc.Methods),
		"every AutoscalePolicy RPC must be explicitly quarantined and tested")

	for _, test := range tests {
		t.Run(test.name, func(t *testing.T) {
			err := test.call()
			require.Equal(t, codes.FailedPrecondition, status.Code(err))
			require.Equal(t, autoscalePolicyQuarantineMessage, status.Convert(err).Message())
		})
	}
}
