package region

import (
	"context"
	"testing"

	"github.com/stretchr/testify/require"
	"go.uber.org/mock/gomock"
	"google.golang.org/grpc"
	"google.golang.org/protobuf/proto"

	globalcommonv1 "github.com/tidbcloud/tidb-management-service/api/spec/global/common/v1"
	globalngv1 "github.com/tidbcloud/tidb-management-service/api/spec/global/nextgen/v1"
	openapingv1beta2 "github.com/tidbcloud/tidb-management-service/api/spec/tidb_cloud_open_api/nextgen/v1beta2"
	"github.com/tidbcloud/tidb-management-service/tidb-mgmt-service/domain/adapter/nextgenglobal/mock_nextgenglobal"
	"github.com/tidbcloud/tidb-management-service/utilities/grpc/metadata"
)

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

	ctrl := gomock.NewController(t)
	nextgenCli := mock_nextgenglobal.NewMockNextGenGlobal(ctrl)
	server := NewServer(nextgenCli, nil, nil)
	ctx := metadata.AppendToIncomingMeta(t.Context(), &metadata.RequestMeta{
		OrgID:             1001,
		UserID:            "user-1",
		DefaultProjectID:  2001,
		ValidProjectList:  []uint64{2001},
		IsCheckPermission: proto.Bool(true),
	})

	nextgenCli.EXPECT().ListNodeSpecs(gomock.Any(), gomock.Any()).DoAndReturn(
		func(_ context.Context, req *globalngv1.ListNodeSpecsRequest, _ ...grpc.CallOption) (*globalngv1.ListNodeSpecsResponse, error) {
			require.Equal(t, uint64(1001), req.GetOrganizationId())
			require.Equal(t, globalcommonv1.CloudProvider_AWS, req.GetCloudProviderId())
			require.Equal(t, globalcommonv1.Region_AWS_US_WEST_2, req.GetRegionId())
			require.Equal(t, globalngv1.NodeSpecComponentType_NODE_SPEC_COMPONENT_TYPE_TIFLASH, req.GetComponentType())
			require.Equal(t, int32(5), req.GetPageSize())
			require.Equal(t, "token", req.GetPageToken())
			return &globalngv1.ListNodeSpecsResponse{
				NodeSpecs: []*globalngv1.ResourcePoolNodeSpec{{
					NodeSpecKey:   "16c64g",
					DisplayName:   "16 vCPU, 64 GiB",
					ComponentType: globalngv1.NodeSpecComponentType_NODE_SPEC_COMPONENT_TYPE_TIFLASH,
					Cpu:           16,
					MemoryGi:      64,
					IsDefault:     true,
					Storages: []*globalngv1.NodeSpecStorage{{
						Name:          "data",
						DefaultSizeGi: 500,
						MinSizeGi:     100,
						MaxSizeGi:     1000,
						Resizable:     proto.Bool(true),
					}},
				}},
				NodeCountOptions: &globalngv1.NodeCountOptions{
					DefaultNodeCount: 1,
					MinNodeCount:     1,
					MaxNodeCount:     1,
					Rule: &globalngv1.NodeCountRule{
						Type:  globalngv1.NodeCountRuleType_NODE_COUNT_RULE_TYPE_FIXED,
						Value: 1,
					},
				},
				TotalSize:     1,
				NextPageToken: "next",
			}, nil
		},
	)

	response, err := server.ListNodeSpecs(ctx, &openapingv1beta2.ListNodeSpecsRequest{
		RegionId:       "aws-us-west-2",
		OrganizationId: "1001",
		ComponentType:  openapingv1beta2.NodeSpecComponentType_NODE_SPEC_COMPONENT_TYPE_TIFLASH,
		PageSize:       5,
		PageToken:      "token",
	})
	require.NoError(t, err)
	require.Len(t, response.GetNodeSpecs(), 1)
	require.Equal(t, "16c64g", response.GetNodeSpecs()[0].GetNodeSpecKey())
	require.True(t, response.GetNodeSpecs()[0].GetStorages()[0].GetResizable())
	require.Equal(t, int64(1), response.GetNodeCountOptions().GetDefaultNodeCount())
	require.Equal(t, int32(1), response.GetTotalSize())
	require.Equal(t, "next", response.GetNextPageToken())
}

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

	ctrl := gomock.NewController(t)
	server := NewServer(mock_nextgenglobal.NewMockNextGenGlobal(ctrl), nil, nil)
	ctx := metadata.AppendToIncomingMeta(t.Context(), &metadata.RequestMeta{
		OrgID:             1001,
		UserID:            "user-1",
		DefaultProjectID:  2001,
		ValidProjectList:  []uint64{2001},
		IsCheckPermission: proto.Bool(true),
	})

	_, err := server.ListNodeSpecs(ctx, &openapingv1beta2.ListNodeSpecsRequest{
		RegionId:       "aws-us-west-2",
		OrganizationId: "1002",
		ComponentType:  openapingv1beta2.NodeSpecComponentType_NODE_SPEC_COMPONENT_TYPE_TIKV,
	})
	require.Error(t, err)
}
