package action

import (
	"testing"

	"github.com/stretchr/testify/mock"
	"github.com/stretchr/testify/require"
	apiv1 "github.com/tidbcloud/cluster-service-ng/api/cluster-service-ng/v1beta"
	dplanemgrv1 "github.com/tidbcloud/cluster-service-ng/api/dataplane-manager/v1"
	"github.com/tidbcloud/cluster-service-ng/domain/entity"
	"github.com/tidbcloud/cluster-service-ng/domain/workflow"
	dataplanemgrmocks "github.com/tidbcloud/cluster-service-ng/pkg/dataplanemgr/mocks"
	"github.com/tidbcloud/cluster-service-ng/pkg/nodegroup"
	"github.com/tidbcloud/cluster-service-ng/pkg/runtime/actions"
	repomnocks "github.com/tidbcloud/cluster-service-ng/pkg/storage/repo/mocks"
	"google.golang.org/protobuf/types/known/emptypb"
)

func TestDeleteNodeInstanceGroupActionSkipsFallbackWithSameInstanceTypeAsPrimaryGroup(t *testing.T) {
	stateRepo := repomnocks.NewDataplaneNodeInstanceGroupStateRepo(t)
	lockRepo := repomnocks.NewDataplaneNodeInstanceGroupLockRepo(t)
	dataplaneClient := dataplanemgrmocks.NewClient(t)
	dataplaneClient.On("GetDataPlaneServiceClient").Return(dataplaneClient)

	lock := &entity.DataplaneNodeInstanceGroupLock{}
	lock.FencingToken = 1
	lockRepo.On("TryAcquire", mock.Anything, "dataplane-abc", "8C16G", "m5.2xlarge", mock.AnythingOfType("string"), DefaultLockLeaseDuration).Return(lock, nil)
	lockRepo.On("Release", mock.Anything, "dataplane-abc", "8C16G", "m5.2xlarge", mock.AnythingOfType("string")).Return(nil)
	dataplaneClient.On("ListNodePools", mock.Anything, &dplanemgrv1.ListNodePoolsRequest{DataPlaneId: "dataplane-abc"}).Return(&dplanemgrv1.ListNodePoolsResponse{
		NodePools: []*dplanemgrv1.NodePool{
			{
				Name:         "primary-m5-2xlarge",
				InstanceType: "m5.2xlarge",
				Labels: map[string]string{
					nodegroup.LabelNodeSpec:  "8C16G",
					nodegroup.LabelManagedBy: nodegroup.ManagedByInstanceTypeManager,
					nodegroup.LabelPriority:  "1000",
				},
			},
			{
				Name:         "fallback-other-primary-m5-2xlarge",
				InstanceType: "m5.2xlarge",
				Labels: map[string]string{
					nodegroup.LabelNodeSpec:  "8C16G",
					nodegroup.LabelManagedBy: nodegroup.ManagedByInstanceTypeManager,
					nodegroup.LabelPriority:  "100",
				},
			},
		},
	}, nil)
	dataplaneClient.On("DeleteNodePool", mock.Anything, &dplanemgrv1.DeleteNodePoolRequest{
		DataPlaneId: "dataplane-abc",
		NodePoolId:  "primary-m5-2xlarge",
	}).Return(&emptypb.Empty{}, nil).Once()
	stateRepo.On("LoadByDataplaneAndSpec", mock.Anything, "dataplane-abc", "8C16G", "m5.2xlarge").Return(nil, nil)

	action := NewDeleteNodeInstanceGroupAction(stateRepo, lockRepo, dataplaneClient)
	err := action.Invoke(actions.ActionArgs{
		workflow.DataplaneIdKey: actions.ActionArgString("dataplane-abc"),
		workflow.NodeInstanceGroupKey: actions.ActionArgString(mustMarshalNodeInstanceGroup(&entity.NodeInstanceGroup{
			NodeSpec:            &apiv1.NodeSpec{Cpu: 8, MemoryGi: 16},
			PrimaryInstanceType: "m5.2xlarge",
			FallbackInstances: []*apiv1.NodeInstanceGroup_FallbackInstance{
				{InstanceType: "m5.2xlarge", NodeSpec: &apiv1.NodeSpec{Cpu: 8, MemoryGi: 16}, Priority: 100},
			},
		})),
	})

	require.NoError(t, err)
	dataplaneClient.AssertNumberOfCalls(t, "DeleteNodePool", 1)
}
