package server

import (
	"context"
	"errors"
	"testing"

	"github.com/stretchr/testify/assert"
	"github.com/stretchr/testify/mock"
	"github.com/stretchr/testify/require"
	apiv1 "github.com/tidbcloud/cluster-service-ng/api/cluster-service-ng/v1beta"
	"github.com/tidbcloud/cluster-service-ng/domain/entity"
	"github.com/tidbcloud/cluster-service-ng/domain/workflow"
	bractionmocks "github.com/tidbcloud/cluster-service-ng/domain/workflow/action/br/mocks"
	"github.com/tidbcloud/cluster-service-ng/domain/workflow/dag"
	"github.com/tidbcloud/cluster-service-ng/pkg/runtime/actions"
	"github.com/tidbcloud/cluster-service-ng/pkg/runtime/executor"
	executormocks "github.com/tidbcloud/cluster-service-ng/pkg/runtime/executor/mocks"
	"github.com/tidbcloud/cluster-service-ng/pkg/storage/mysql/schema"
	"github.com/tidbcloud/cluster-service-ng/pkg/storage/repo"
	repomnocks "github.com/tidbcloud/cluster-service-ng/pkg/storage/repo/mocks"
)

func TestListSharedPools(t *testing.T) {
	tests := []struct {
		name        string
		setupMocks  func(*repomnocks.SharedPoolRepo, *executormocks.RemoteExecutor, *bractionmocks.ScaleManager)
		expectError bool
		validate    func(*testing.T, []*entity.SharedPool, error)
	}{
		{
			name: "successful list with no creating pools",
			setupMocks: func(sharedPoolRepo *repomnocks.SharedPoolRepo, dagExecutor *executormocks.RemoteExecutor, scaleManager *bractionmocks.ScaleManager) {
				existingPools := []*entity.SharedPool{
					{
						SharedPool: apiv1.SharedPool{
							Id:    "pool-1",
							Phase: apiv1.SharedPool_AVAILABLE,
						},
					},
					{
						SharedPool: apiv1.SharedPool{
							Id:    "pool-2",
							Phase: apiv1.SharedPool_PAUSED,
						},
					},
				}
				sharedPoolRepo.On("List", mock.Anything, &repo.SharedPoolFilter{
					Ids:            nil,
					DataplaneNames: nil,
					Deleted:        false,
				}).Return(existingPools, nil)
				dagExecutor.On("QueryRunnings", mock.Anything, mock.Anything, mock.Anything).Return(executor.NewExecTaskIdStatus(), nil)
				scaleManager.On("AnyFullfillingDecision", mock.Anything, mock.Anything).Return(false, nil)
			},
			expectError: false,
			validate: func(t *testing.T, result []*entity.SharedPool, err error) {
				t.Helper()
				require.NoError(t, err)
				require.Len(t, result, 2)

				ids := make([]string, len(result))
				for i, pool := range result {
					ids[i] = pool.GetId()
				}
				assert.Contains(t, ids, "pool-1")
				assert.Contains(t, ids, "pool-2")
			},
		},
		{
			name: "successful list with creating pools from DAG",
			setupMocks: func(sharedPoolRepo *repomnocks.SharedPoolRepo, dagExecutor *executormocks.RemoteExecutor, scaleManager *bractionmocks.ScaleManager) {
				existingPools := []*entity.SharedPool{
					{
						SharedPool: apiv1.SharedPool{
							Id:    "pool-1",
							Phase: apiv1.SharedPool_AVAILABLE,
						},
					},
				}
				sharedPoolRepo.On("List", mock.Anything, &repo.SharedPoolFilter{
					Ids:            nil,
					DataplaneNames: nil,
					Deleted:        false,
				}).Return(existingPools, nil)

				// Mock creating pool in DAG
				runningDags := executor.NewExecTaskIdStatus()
				mockExecTask := &executor.ExecutorTask{
					RootName: dag.PlanCreateSharedPool,
					ExecId:   "creating-dag-id",
					Args: actions.ActionArgs{
						workflow.SharedPoolIdKey:         actions.ActionArgString("creating-pool"),
						workflow.SharedPoolKey:           actions.ActionArgString(`{"id":"creating-pool","phase":"CREATING"}`),
						workflow.SharedPoolDeployTypeKey: actions.ActionArgString(schema.SharedPoolDeployTypeSharedTiProxy),
					},
				}
				runningDags["creating-dag-id"] = &executor.ExecTaskStatusEx{
					ExecTaskStatus: executor.ExecTaskStatus{
						ExecTask: mockExecTask,
					},
					State: executor.ExecTaskStateTypeRunningOK,
				}

				// Simple approach: Mock all DAG plans individually
				// For create-sharedpool plan, return the running DAG only for first call (without filter)
				// For all other calls, return empty results
				dagExecutor.On("QueryRunnings", mock.Anything, "create-sharedpool", mock.AnythingOfType("executor.MatchFilter")).Return(runningDags, nil).Once()
				dagExecutor.On("QueryRunnings", mock.Anything, "create-sharedpool", mock.AnythingOfType("executor.MatchFilter")).Return(executor.NewExecTaskIdStatus(), nil)
				dagExecutor.On("QueryRunnings", mock.Anything, "delete-sharedpool", mock.AnythingOfType("executor.MatchFilter")).Return(executor.NewExecTaskIdStatus(), nil)
				dagExecutor.On("QueryRunnings", mock.Anything, "update-component", mock.AnythingOfType("executor.MatchFilter")).Return(executor.NewExecTaskIdStatus(), nil)
				dagExecutor.On("QueryRunnings", mock.Anything, "apply-component", mock.AnythingOfType("executor.MatchFilter")).Return(executor.NewExecTaskIdStatus(), nil)
				dagExecutor.On("QueryRunnings", mock.Anything, "create-component", mock.AnythingOfType("executor.MatchFilter")).Return(executor.NewExecTaskIdStatus(), nil)
				dagExecutor.On("QueryRunnings", mock.Anything, dag.PlanDeleteTiKVGroup, mock.AnythingOfType("executor.MatchFilter")).Return(executor.NewExecTaskIdStatus(), nil)
				dagExecutor.On("QueryRunnings", mock.Anything, dag.PlanSetSharedPoolPDDeploymentModeToMonolithic, mock.AnythingOfType("executor.MatchFilter")).Return(executor.NewExecTaskIdStatus(), nil)
				dagExecutor.On("QueryRunnings", mock.Anything, dag.PlanSetSharedPoolPDDeploymentModeToMicroservice, mock.AnythingOfType("executor.MatchFilter")).Return(executor.NewExecTaskIdStatus(), nil)
				dagExecutor.On("QueryRunnings", mock.Anything, "create-tidbcluster", mock.AnythingOfType("executor.MatchFilter")).Return(executor.NewExecTaskIdStatus(), nil)
				dagExecutor.On("QueryRunnings", mock.Anything, "update-tidbcluster", mock.AnythingOfType("executor.MatchFilter")).Return(executor.NewExecTaskIdStatus(), nil)
				dagExecutor.On("QueryRunnings", mock.Anything, "delete-tidbcluster", mock.AnythingOfType("executor.MatchFilter")).Return(executor.NewExecTaskIdStatus(), nil)
				dagExecutor.On("QueryRunnings", mock.Anything, "create-tidbgroup", mock.AnythingOfType("executor.MatchFilter")).Return(executor.NewExecTaskIdStatus(), nil)
				dagExecutor.On("QueryRunnings", mock.Anything, "update-tidbgroup", mock.AnythingOfType("executor.MatchFilter")).Return(executor.NewExecTaskIdStatus(), nil)
				dagExecutor.On("QueryRunnings", mock.Anything, "delete-tidbgroup", mock.AnythingOfType("executor.MatchFilter")).Return(executor.NewExecTaskIdStatus(), nil)
				dagExecutor.On("QueryRunnings", mock.Anything, dag.PlanEnableCoprocessorWorker, mock.AnythingOfType("executor.MatchFilter")).Return(executor.NewExecTaskIdStatus(), nil)
				dagExecutor.On("QueryRunnings", mock.Anything, dag.PlanDisableCoprocessorWorker, mock.AnythingOfType("executor.MatchFilter")).Return(executor.NewExecTaskIdStatus(), nil)
				scaleManager.On("AnyFullfillingDecision", mock.Anything, mock.Anything).Return(false, nil)
			},
			expectError: false,
			validate: func(t *testing.T, result []*entity.SharedPool, err error) {
				t.Helper()
				require.NoError(t, err)
				require.Len(t, result, 2)

				var creatingPool *entity.SharedPool
				var existingPool *entity.SharedPool
				for _, pool := range result {
					if pool.GetId() == "creating-pool" {
						creatingPool = pool
					} else if pool.GetId() == "pool-1" {
						existingPool = pool
					}
				}

				require.NotNil(t, creatingPool)
				require.NotNil(t, existingPool)
				assert.Equal(t, apiv1.SharedPool_CREATING, creatingPool.GetPhase())
				assert.True(t, entity.IsEssentialV2(creatingPool))
				assert.Equal(t, apiv1.SharedPool_AVAILABLE, existingPool.GetPhase())
			},
		},
		{
			name: "creating pool already exists in db (skip duplicate)",
			setupMocks: func(sharedPoolRepo *repomnocks.SharedPoolRepo, dagExecutor *executormocks.RemoteExecutor, scaleManager *bractionmocks.ScaleManager) {
				existingPools := []*entity.SharedPool{
					{
						SharedPool: apiv1.SharedPool{
							Id:    "pool-1",
							Phase: apiv1.SharedPool_CREATING,
						},
					},
				}
				sharedPoolRepo.On("List", mock.Anything, &repo.SharedPoolFilter{
					Ids:            nil,
					DataplaneNames: nil,
					Deleted:        false,
				}).Return(existingPools, nil)

				// Mock creating pool in DAG with same ID as existing pool
				runningDags := executor.NewExecTaskIdStatus()
				mockExecTask := &executor.ExecutorTask{
					RootName: dag.PlanCreateSharedPool,
					ExecId:   "creating-dag-id",
					Args: actions.ActionArgs{
						workflow.SharedPoolIdKey: actions.ActionArgString("pool-1"), // Same as existing pool
						workflow.SharedPoolKey:   actions.ActionArgString(`{"id":"pool-1","phase":"CREATING"}`),
					},
				}
				runningDags["creating-dag-id"] = &executor.ExecTaskStatusEx{
					ExecTaskStatus: executor.ExecTaskStatus{
						ExecTask: mockExecTask,
					},
					State: executor.ExecTaskStateTypeRunningOK,
				}
				dagExecutor.On("QueryRunnings", mock.Anything, mock.Anything, mock.Anything).Return(runningDags, nil)
				scaleManager.On("AnyFullfillingDecision", mock.Anything, mock.Anything).Return(false, nil)
			},
			expectError: false,
			validate: func(t *testing.T, result []*entity.SharedPool, err error) {
				t.Helper()
				require.NoError(t, err)
				require.Len(t, result, 1) // Should not duplicate
				assert.Equal(t, "pool-1", result[0].GetId())
			},
		},
		{
			name: "repository error",
			setupMocks: func(sharedPoolRepo *repomnocks.SharedPoolRepo, dagExecutor *executormocks.RemoteExecutor, scaleManager *bractionmocks.ScaleManager) {
				sharedPoolRepo.On("List", mock.Anything, &repo.SharedPoolFilter{
					Ids:            nil,
					DataplaneNames: nil,
					Deleted:        false,
				}).Return(nil, errors.New("database error"))
			},
			expectError: true,
		},
		{
			name: "dag executor error",
			setupMocks: func(sharedPoolRepo *repomnocks.SharedPoolRepo, dagExecutor *executormocks.RemoteExecutor, scaleManager *bractionmocks.ScaleManager) {
				existingPools := []*entity.SharedPool{
					{
						SharedPool: apiv1.SharedPool{
							Id:    "pool-1",
							Phase: apiv1.SharedPool_AVAILABLE,
						},
					},
				}
				sharedPoolRepo.On("List", mock.Anything, &repo.SharedPoolFilter{
					Ids:            nil,
					DataplaneNames: nil,
					Deleted:        false,
				}).Return(existingPools, nil)
				dagExecutor.On("QueryRunnings", mock.Anything, mock.Anything, mock.Anything).Return(nil, errors.New("executor error"))
			},
			expectError: true,
		},
		{
			name: "empty list from repository",
			setupMocks: func(sharedPoolRepo *repomnocks.SharedPoolRepo, dagExecutor *executormocks.RemoteExecutor, scaleManager *bractionmocks.ScaleManager) {
				sharedPoolRepo.On("List", mock.Anything, &repo.SharedPoolFilter{
					Ids:            nil,
					DataplaneNames: nil,
					Deleted:        false,
				}).Return([]*entity.SharedPool{}, nil)
				dagExecutor.On("QueryRunnings", mock.Anything, mock.Anything, mock.Anything).Return(executor.NewExecTaskIdStatus(), nil)
			},
			expectError: false,
			validate: func(t *testing.T, result []*entity.SharedPool, err error) {
				t.Helper()
				require.NoError(t, err)
				require.Empty(t, result)
			},
		},
		{
			name: "invalid JSON in creating pool DAG",
			setupMocks: func(sharedPoolRepo *repomnocks.SharedPoolRepo, dagExecutor *executormocks.RemoteExecutor, scaleManager *bractionmocks.ScaleManager) {
				existingPools := []*entity.SharedPool{}
				sharedPoolRepo.On("List", mock.Anything, &repo.SharedPoolFilter{
					Ids:            nil,
					DataplaneNames: nil,
					Deleted:        false,
				}).Return(existingPools, nil)

				// Mock creating pool in DAG with invalid JSON
				runningDags := executor.NewExecTaskIdStatus()
				mockExecTask := &executor.ExecutorTask{
					RootName: dag.PlanCreateSharedPool,
					ExecId:   "creating-dag-id",
					Args: actions.ActionArgs{
						workflow.SharedPoolIdKey: actions.ActionArgString("creating-pool"),
						workflow.SharedPoolKey:   actions.ActionArgString(`{invalid json`),
					},
				}
				runningDags["creating-dag-id"] = &executor.ExecTaskStatusEx{
					ExecTaskStatus: executor.ExecTaskStatus{
						ExecTask: mockExecTask,
					},
					State: executor.ExecTaskStateTypeRunningOK,
				}
				dagExecutor.On("QueryRunnings", mock.Anything, mock.Anything, mock.Anything).Return(runningDags, nil)
			},
			expectError: true,
		},
	}

	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {
			// Create mocks
			sharedPoolRepo := repomnocks.NewSharedPoolRepo(t)
			dagExecutor := executormocks.NewRemoteExecutor(t)
			scaleManager := bractionmocks.NewScaleManager(t)

			// Setup mocks
			tt.setupMocks(sharedPoolRepo, dagExecutor, scaleManager)

			// Create server implementation
			server := &serverImpl{
				sharedPoolRepo: sharedPoolRepo,
				dagExecutor:    dagExecutor,
				scaleManager:   scaleManager,
			}

			// Execute test
			result, err := server.ListSharedPools(context.Background(), nil, nil)

			if tt.expectError {
				require.Error(t, err)
				assert.Nil(t, result)
				return
			}

			if tt.validate != nil {
				tt.validate(t, result, err)
			} else {
				require.NoError(t, err)
				require.NotNil(t, result)
			}
		})
	}
}

func TestListSharedPools_MergesCassandraProxyStateFromRepo(t *testing.T) {
	sharedPoolRepo := repomnocks.NewSharedPoolRepo(t)
	dagExecutor := executormocks.NewRemoteExecutor(t)
	scaleManager := bractionmocks.NewScaleManager(t)
	cassandraProxyStateRepo := repomnocks.NewCassandraProxyStateRepo(t)

	sharedPool := &entity.SharedPool{
		SharedPool: apiv1.SharedPool{
			Id:    "pool-1",
			Phase: apiv1.SharedPool_AVAILABLE,
			ComponentGroups: []*apiv1.Component{
				{
					Id:            "existing-cluster",
					ComponentType: apiv1.ComponentType_CASSANDRA_PROXY,
					Phase:         apiv1.Component_CREATING,
					Labels: map[string]string{
						cassandraProxyHostIdLabelKey:   "old-host",
						cassandraProxyNodeSpecLabelKey: "old-spec",
					},
				},
			},
		},
	}
	sharedPoolRepo.On("List", mock.Anything, &repo.SharedPoolFilter{Deleted: false}).Return([]*entity.SharedPool{sharedPool}, nil)
	dagExecutor.On("QueryRunnings", mock.Anything, mock.Anything, mock.Anything).Return(executor.NewExecTaskIdStatus(), nil)
	scaleManager.On("AnyFullfillingDecision", mock.Anything, "pool-1").Return(false, nil)
	cassandraProxyStateRepo.On("ListBySharedPoolID", mock.Anything, "pool-1").Return([]*entity.CassandraProxyState{
		{
			ClusterID:    "existing-cluster",
			SharedPoolID: "pool-1",
			HostID:       "stable-host-id",
			NodeSpec:     "8C16G",
			Phase:        entity.ComponentPhaseToCassandraProxyPhase(apiv1.Component_AVAILABLE),
			NodeQuotaEntity: &apiv1.NodeQuota{
				NodeSpec:  &apiv1.NodeSpec{Cpu: 8, MemoryGi: 16, AvailableMemoryMi: 14000},
				NodeCount: 2,
			},
		},
		{
			ClusterID:    "state-only-cluster",
			SharedPoolID: "pool-1",
			HostID:       "state-only-host-id",
			NodeSpec:     "16C32G",
			Phase:        entity.ComponentPhaseToCassandraProxyPhase(apiv1.Component_UNAVAILABLE),
			NodeQuotaEntity: &apiv1.NodeQuota{
				NodeSpec:  &apiv1.NodeSpec{Cpu: 16, MemoryGi: 32, AvailableMemoryMi: 28000},
				NodeCount: 3,
			},
		},
	}, nil)

	server := &serverImpl{
		sharedPoolRepo:          sharedPoolRepo,
		dagExecutor:             dagExecutor,
		scaleManager:            scaleManager,
		cassandraProxyStateRepo: cassandraProxyStateRepo,
	}

	result, err := server.ListSharedPools(context.Background(), nil, nil)
	require.NoError(t, err)
	require.Len(t, result, 1)
	components := result[0].GetComponentGroups()
	require.Len(t, components, 2)

	componentsByID := map[string]*apiv1.Component{}
	for _, component := range components {
		componentsByID[component.GetId()] = component
	}
	existing := componentsByID["existing-cluster"]
	require.NotNil(t, existing)
	assert.Equal(t, apiv1.Component_AVAILABLE, existing.GetPhase())
	assert.Equal(t, "stable-host-id", existing.GetLabels()[cassandraProxyHostIdLabelKey])
	assert.Equal(t, "8C16G", existing.GetLabels()[cassandraProxyNodeSpecLabelKey])
	assert.Equal(t, uint32(2), existing.GetNodeQuota().GetNodeCount())

	stateOnly := componentsByID["state-only-cluster"]
	require.NotNil(t, stateOnly)
	assert.Equal(t, apiv1.ComponentType_CASSANDRA_PROXY, stateOnly.GetComponentType())
	assert.Equal(t, apiv1.Component_UNAVAILABLE, stateOnly.GetPhase())
	assert.Equal(t, "state-only-host-id", stateOnly.GetLabels()[cassandraProxyHostIdLabelKey])
	assert.Equal(t, "16C32G", stateOnly.GetLabels()[cassandraProxyNodeSpecLabelKey])
	assert.Equal(t, uint32(3), stateOnly.GetNodeQuota().GetNodeCount())
}

func TestListSharedPoolsWithDataplaneNames(t *testing.T) {
	tests := []struct {
		name           string
		sharedPoolIds  []string
		dataplaneNames []string
		setupMocks     func(*repomnocks.SharedPoolRepo, *executormocks.RemoteExecutor, *bractionmocks.ScaleManager)
		expectError    bool
		validate       func(*testing.T, []*entity.SharedPool, error)
	}{
		{
			name:           "filter by dataplane_names only",
			sharedPoolIds:  nil,
			dataplaneNames: []string{"dataplane-1"},
			setupMocks: func(sharedPoolRepo *repomnocks.SharedPoolRepo, dagExecutor *executormocks.RemoteExecutor, scaleManager *bractionmocks.ScaleManager) {
				existingPools := []*entity.SharedPool{
					{
						SharedPool: apiv1.SharedPool{
							Id:            "pool-1",
							DataplaneName: "dataplane-1",
							Phase:         apiv1.SharedPool_AVAILABLE,
						},
					},
				}
				sharedPoolRepo.On("List", mock.Anything, &repo.SharedPoolFilter{
					Ids:            nil,
					DataplaneNames: []string{"dataplane-1"},
					Deleted:        false,
				}).Return(existingPools, nil)
				dagExecutor.On("QueryRunnings", mock.Anything, mock.Anything, mock.Anything).Return(executor.NewExecTaskIdStatus(), nil)
				scaleManager.On("AnyFullfillingDecision", mock.Anything, mock.Anything).Return(false, nil)
			},
			expectError: false,
			validate: func(t *testing.T, result []*entity.SharedPool, err error) {
				t.Helper()
				require.NoError(t, err)
				require.Len(t, result, 1)
				assert.Equal(t, "pool-1", result[0].GetId())
				assert.Equal(t, "dataplane-1", result[0].GetDataplaneName())
			},
		},
		{
			name:           "filter by ids and dataplane_names (AND logic)",
			sharedPoolIds:  []string{"pool-1", "pool-2"},
			dataplaneNames: []string{"dataplane-1"},
			setupMocks: func(sharedPoolRepo *repomnocks.SharedPoolRepo, dagExecutor *executormocks.RemoteExecutor, scaleManager *bractionmocks.ScaleManager) {
				existingPools := []*entity.SharedPool{
					{
						SharedPool: apiv1.SharedPool{
							Id:            "pool-1",
							DataplaneName: "dataplane-1",
							Phase:         apiv1.SharedPool_AVAILABLE,
						},
					},
				}
				sharedPoolRepo.On("List", mock.Anything, &repo.SharedPoolFilter{
					Ids:            []string{"pool-1", "pool-2"},
					DataplaneNames: []string{"dataplane-1"},
					Deleted:        false,
				}).Return(existingPools, nil)
				dagExecutor.On("QueryRunnings", mock.Anything, mock.Anything, mock.Anything).Return(executor.NewExecTaskIdStatus(), nil)
				scaleManager.On("AnyFullfillingDecision", mock.Anything, mock.Anything).Return(false, nil)
			},
			expectError: false,
			validate: func(t *testing.T, result []*entity.SharedPool, err error) {
				t.Helper()
				require.NoError(t, err)
				require.Len(t, result, 1)
				assert.Equal(t, "pool-1", result[0].GetId())
			},
		},
		{
			name:           "filter by multiple dataplane_names",
			sharedPoolIds:  nil,
			dataplaneNames: []string{"dataplane-1", "dataplane-2"},
			setupMocks: func(sharedPoolRepo *repomnocks.SharedPoolRepo, dagExecutor *executormocks.RemoteExecutor, scaleManager *bractionmocks.ScaleManager) {
				existingPools := []*entity.SharedPool{
					{
						SharedPool: apiv1.SharedPool{
							Id:            "pool-1",
							DataplaneName: "dataplane-1",
							Phase:         apiv1.SharedPool_AVAILABLE,
						},
					},
					{
						SharedPool: apiv1.SharedPool{
							Id:            "pool-2",
							DataplaneName: "dataplane-2",
							Phase:         apiv1.SharedPool_AVAILABLE,
						},
					},
				}
				sharedPoolRepo.On("List", mock.Anything, &repo.SharedPoolFilter{
					Ids:            nil,
					DataplaneNames: []string{"dataplane-1", "dataplane-2"},
					Deleted:        false,
				}).Return(existingPools, nil)
				dagExecutor.On("QueryRunnings", mock.Anything, mock.Anything, mock.Anything).Return(executor.NewExecTaskIdStatus(), nil)
				scaleManager.On("AnyFullfillingDecision", mock.Anything, mock.Anything).Return(false, nil)
			},
			expectError: false,
			validate: func(t *testing.T, result []*entity.SharedPool, err error) {
				t.Helper()
				require.NoError(t, err)
				require.Len(t, result, 2)
			},
		},
		{
			name:           "filter by ids only (uses List method)",
			sharedPoolIds:  []string{"pool-1"},
			dataplaneNames: nil,
			setupMocks: func(sharedPoolRepo *repomnocks.SharedPoolRepo, dagExecutor *executormocks.RemoteExecutor, scaleManager *bractionmocks.ScaleManager) {
				existingPools := []*entity.SharedPool{
					{
						SharedPool: apiv1.SharedPool{
							Id:    "pool-1",
							Phase: apiv1.SharedPool_AVAILABLE,
						},
					},
				}
				sharedPoolRepo.On("List", mock.Anything, &repo.SharedPoolFilter{
					Ids:            []string{"pool-1"},
					DataplaneNames: nil,
					Deleted:        false,
				}).Return(existingPools, nil)
				dagExecutor.On("QueryRunnings", mock.Anything, mock.Anything, mock.Anything).Return(executor.NewExecTaskIdStatus(), nil)
				scaleManager.On("AnyFullfillingDecision", mock.Anything, mock.Anything).Return(false, nil)
			},
			expectError: false,
			validate: func(t *testing.T, result []*entity.SharedPool, err error) {
				t.Helper()
				require.NoError(t, err)
				require.Len(t, result, 1)
				assert.Equal(t, "pool-1", result[0].GetId())
			},
		},
		{
			name:           "empty filters returns all (uses List method)",
			sharedPoolIds:  nil,
			dataplaneNames: nil,
			setupMocks: func(sharedPoolRepo *repomnocks.SharedPoolRepo, dagExecutor *executormocks.RemoteExecutor, scaleManager *bractionmocks.ScaleManager) {
				existingPools := []*entity.SharedPool{
					{
						SharedPool: apiv1.SharedPool{
							Id:    "pool-1",
							Phase: apiv1.SharedPool_AVAILABLE,
						},
					},
					{
						SharedPool: apiv1.SharedPool{
							Id:    "pool-2",
							Phase: apiv1.SharedPool_AVAILABLE,
						},
					},
				}
				sharedPoolRepo.On("List", mock.Anything, &repo.SharedPoolFilter{
					Ids:            nil,
					DataplaneNames: nil,
					Deleted:        false,
				}).Return(existingPools, nil)
				dagExecutor.On("QueryRunnings", mock.Anything, mock.Anything, mock.Anything).Return(executor.NewExecTaskIdStatus(), nil)
				scaleManager.On("AnyFullfillingDecision", mock.Anything, mock.Anything).Return(false, nil)
			},
			expectError: false,
			validate: func(t *testing.T, result []*entity.SharedPool, err error) {
				t.Helper()
				require.NoError(t, err)
				require.Len(t, result, 2)
			},
		},
		{
			name:           "no matching dataplane_names returns empty",
			sharedPoolIds:  nil,
			dataplaneNames: []string{"non-existent-dataplane"},
			setupMocks: func(sharedPoolRepo *repomnocks.SharedPoolRepo, dagExecutor *executormocks.RemoteExecutor, scaleManager *bractionmocks.ScaleManager) {
				sharedPoolRepo.On("List", mock.Anything, &repo.SharedPoolFilter{
					Ids:            nil,
					DataplaneNames: []string{"non-existent-dataplane"},
					Deleted:        false,
				}).Return([]*entity.SharedPool{}, nil)
				dagExecutor.On("QueryRunnings", mock.Anything, mock.Anything, mock.Anything).Return(executor.NewExecTaskIdStatus(), nil)
			},
			expectError: false,
			validate: func(t *testing.T, result []*entity.SharedPool, err error) {
				t.Helper()
				require.NoError(t, err)
				require.Empty(t, result)
			},
		},
	}

	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {
			// Create mocks
			sharedPoolRepo := repomnocks.NewSharedPoolRepo(t)
			dagExecutor := executormocks.NewRemoteExecutor(t)
			scaleManager := bractionmocks.NewScaleManager(t)

			// Setup mocks
			tt.setupMocks(sharedPoolRepo, dagExecutor, scaleManager)

			// Create server implementation
			server := &serverImpl{
				sharedPoolRepo: sharedPoolRepo,
				dagExecutor:    dagExecutor,
				scaleManager:   scaleManager,
			}

			// Execute test
			result, err := server.ListSharedPools(context.Background(), tt.sharedPoolIds, tt.dataplaneNames)

			if tt.expectError {
				require.Error(t, err)
				assert.Nil(t, result)
				return
			}

			if tt.validate != nil {
				tt.validate(t, result, err)
			} else {
				require.NoError(t, err)
				require.NotNil(t, result)
			}
		})
	}
}
