package server

import (
	"context"
	"fmt"
	"net/netip"

	apiv1 "github.com/tidbcloud/cluster-service-ng/api/cluster-service-ng/v1beta"
	"github.com/tidbcloud/cluster-service-ng/config"
	"github.com/tidbcloud/cluster-service-ng/domain/entity"
	"github.com/tidbcloud/cluster-service-ng/domain/server/br"
	braction "github.com/tidbcloud/cluster-service-ng/domain/workflow/action/br"
	"github.com/tidbcloud/cluster-service-ng/pkg/clusterconfig"
	"github.com/tidbcloud/cluster-service-ng/pkg/clustergateway"
	"github.com/tidbcloud/cluster-service-ng/pkg/dataplane"
	"github.com/tidbcloud/cluster-service-ng/pkg/dataplanemgr"
	"github.com/tidbcloud/cluster-service-ng/pkg/runtime/executor"
	"github.com/tidbcloud/cluster-service-ng/pkg/runtime/executorext"
	"github.com/tidbcloud/cluster-service-ng/pkg/storage/repo"
	"github.com/tidbcloud/cluster-service-ng/pkg/storage/repoext"
	templateversion "github.com/tidbcloud/cluster-service-ng/pkg/template/version"
	"github.com/tidbcloud/pkgv2/db"
	"google.golang.org/protobuf/types/known/wrapperspb"
)

type meteringWriter interface {
	Write(ctx context.Context, data any) error
}

type BootstrapComponentCapacity struct {
	NodeSpec  *entity.NodeSpec
	NodeCount uint32
}

type SharedPoolBootstrapCapacity struct {
	TiKV           *BootstrapComponentCapacity
	TiFlashCompute *BootstrapComponentCapacity
}

type CreateSharedPoolOptions struct {
	BootstrapCapacity            *SharedPoolBootstrapCapacity
	EnforceO11yNetworkNonOverlap bool
}

type Service interface {
	// cluster
	CreateSharedPool(ctx context.Context, sharedPool *entity.SharedPool, requestUint *entity.RequestUnit, initConfig *entity.InitSharedPoolConfig, options ...*CreateSharedPoolOptions) (*entity.SharedPool, error)
	ListNodeSpecs(ctx context.Context, tenantID string, componentType entity.ComponentType) (*entity.ListNodeSpecsResponse, error)
	GetSharedPoolProvisionConfiguration(ctx context.Context) (*entity.SharedPoolProvisionConfiguration, error)
	EvaluateSharedPoolNetworkCapacity(ctx context.Context, req *entity.EvaluateSharedPoolNetworkCapacityRequest) (*entity.EvaluateSharedPoolNetworkCapacityResponse, error)
	GetSharedPool(ctx context.Context, sharedPoolId string) (*entity.SharedPool, error)
	ValidateSharedPoolPause(ctx context.Context, sharedPoolID string) (*entity.ValidateSharedPoolPauseResponse, error)
	PauseSharedPool(ctx context.Context, sharedPoolID, operationID string) (*entity.SharedPool, error)
	ResumeSharedPool(ctx context.Context, sharedPoolID, operationID string) (*entity.SharedPool, error)
	GetPauseResumeOperation(ctx context.Context, sharedPoolID, operationID string) (*entity.PauseResumeOperation, error)
	ListSharedPools(ctx context.Context, sharedPoolIds, dataplaneNames []string) ([]*entity.SharedPool, error)
	DeleteSharedPool(ctx context.Context, sharedPoolId string, pruneDataplane bool) (*entity.SharedPool, error)
	ScaleSharedPool(ctx context.Context, sharedPoolId string, scaleComponent *entity.Component, force bool) (*entity.SharedPool, error)
	GetSharedPoolScaleConstraints(ctx context.Context, sharedPoolId string) (*entity.GetSharedPoolScaleConstraintsResponse, error)
	SetSharedPoolPDDeploymentMode(ctx context.Context, sharedPoolId string, targetMode entity.PDDeploymentMode) (*entity.SharedPool, error)
	SetSharedPoolTiKVRemoteWorkers(ctx context.Context, sharedPoolId string, targetWorkers []entity.ComponentType) (*entity.SharedPool, error)
	UpdateSharedPoolVcpusLimit(ctx context.Context, sharedPoolId string, vcpusLimit uint64) (*entity.SharedPool, error)
	UpdateSharedPoolCloudResourceTags(ctx context.Context, sharedPoolId string, cloudResourceTags map[string]string, removeCloudResourceTagKeys []string) (*entity.SharedPool, error)
	GetSharedPoolVcpusUsage(ctx context.Context, sharedPoolId string) (*apiv1.GetSharedPoolVcpusUsageResponse, error)

	// TiKV group
	CreateTiKVGroup(ctx context.Context, sharedPoolId, tikvGroupId string, nodeQuota *entity.NodeQuota, storages []*entity.Storage, labels map[string]string, exclusive, force bool) (*entity.Component, error)
	DeleteTiKVGroup(ctx context.Context, sharedPoolId, tikvGroupId string) error
	CreatePlacementPolicy(ctx context.Context, sharedPoolId, clusterId, tikvGroupId string) (*entity.PlacementPolicy, error)
	ListPlacementPolicies(ctx context.Context, sharedPoolId, tikvGroupId string) ([]*entity.PlacementPolicy, error)
	GetPlacementPolicy(ctx context.Context, sharedPoolId, placementPolicyId string) (*entity.PlacementPolicy, error)
	UpdatePlacementPolicy(ctx context.Context, sharedPoolId, placementPolicyId, tikvGroupId string) (*entity.PlacementPolicy, error)
	DeletePlacementPolicy(ctx context.Context, sharedPoolId, placementPolicyId string) error

	ApplySharedPool(ctx context.Context, sharedPoolId string, applyComponent *entity.TargetComponent, force bool) error
	SetSharedPoolComponentQuota(ctx context.Context, sharedPoolId string, targetComponent *entity.Component) (*entity.Component, error)
	SetSharedPoolComponentLabels(ctx context.Context, sharedPoolId string, targetComponent *entity.Component) (*entity.Component, error)
	SetSharedPoolComponentNodeVersion(ctx context.Context, sharedPoolId string, compId string, compType apiv1.ComponentType, nodeVersion string) (*entity.Component, error)
	SetSharedPoolComponentConfigOrVersion(ctx context.Context, sharedPoolId string, targetComponents []*entity.TargetComponent, scope entity.SetVersionConfigScope, mode entity.SetVersionConfigMode, force bool) error
	SetBrComponentConfigOrVersion(ctx context.Context, sharedPoolId string, targetComponents []*entity.TargetComponent, scope entity.SetVersionConfigScope) error
	SetDMComponentConfigOrVersion(ctx context.Context, sharedPoolId string, targetComponents []*entity.TargetComponent, scope entity.SetVersionConfigScope, force bool) error

	// dm cluster
	CreateDMCluster(ctx context.Context, dmCluster *entity.DMCluster) (*entity.DMCluster, error)
	GetDMCluster(ctx context.Context, sharedPoolId, dmClusterId string) (*entity.DMCluster, error)
	ListDMClusters(ctx context.Context, sharedPoolId string) ([]*entity.DMCluster, error)
	ScaleDMCluster(ctx context.Context, sharedPoolId, dmClusterId string, masterNodeQuota, workerNodeQuota *entity.NodeQuota, force bool) (*entity.DMCluster, error)
	DeleteDMCluster(ctx context.Context, sharedPoolId, dmClusterId string) error

	// export
	ListExports(ctx context.Context, clusterId string) ([]*entity.Export, error)
	GetExport(ctx context.Context, clusterId, exportId string) (*entity.Export, error)
	CreateExport(ctx context.Context, export *entity.Export) (*entity.Export, error)
	CancelExport(ctx context.Context, clusterId, exportId string) (*entity.Export, error)

	// tidb cluster
	CreateTiDBCluster(ctx context.Context, tidbCluster *entity.TiDBCluster) (*entity.TiDBCluster, error)
	GetTiDBCluster(ctx context.Context, tidbClusterId string) (*entity.TiDBCluster, error)
	ListTiDBClusters(ctx context.Context, sharedPoolId, tenantId string) ([]*entity.TiDBCluster, error)
	UpdateTiDBCluster(ctx context.Context, tidbCluster *entity.TiDBCluster, force bool) (*entity.TiDBCluster, error)
	ForceUpdateGatewayIdentity(ctx context.Context, tidbClusterId, gatewayIdentity string) error
	DeleteTiDBCluster(ctx context.Context, tidbClusterId string) (*entity.TiDBCluster, error)
	GetTiDBClusterTiProxyNodeQuota(ctx context.Context, tidbClusterId string) (*entity.NodeQuota, error)
	SetTiProxyExternalDNS(ctx context.Context, req *entity.SetTiProxyExternalDNSRequest) error
	// cassandra-proxy
	SetCassandraProxy(ctx context.Context, req *apiv1.SetCassandraProxyRequest) (*apiv1.SetCassandraProxyResponse, error)
	GetCassandraProxy(ctx context.Context, req *apiv1.GetCassandraProxyRequest) (*apiv1.GetCassandraProxyResponse, error)

	// Role
	GetProviderRole(ctx context.Context, tidbClusterId string) (*entity.ProviderRole, error)
	GetImportRoleConfig(ctx context.Context, tidbClusterId string) (*entity.ImportRoleConfig, error)

	// Plan Replayer
	ListPlanReplayerFiles(ctx context.Context, req *apiv1.ListPlanReplayerFilesRequest) (*apiv1.ListPlanReplayerFilesResponse, error)
	GeneratePlanReplayerFileDownloadURL(ctx context.Context, req *apiv1.GeneratePlanReplayerFileDownloadURLRequest) (*apiv1.GeneratePlanReplayerFileDownloadURLResponse, error)

	// Auditlog
	SetAuditLogSetting(ctx context.Context, tidbClusterId string, auditLogSetting *entity.AuditLogSetting) (*entity.AuditLogSetting, error)

	// tidb group
	CreateTiDBGroup(ctx context.Context, tidbGroup *entity.TiDBGroup) (*entity.TiDBGroup, error)
	GetTiDBGroup(ctx context.Context, tidbClusterId string, tidbGroupId string) (*entity.TiDBGroup, error)
	ListTiDBGroups(ctx context.Context, tidbClusterId string) ([]*entity.TiDBGroup, error)
	UpdateTiDBGroup(ctx context.Context, tidbGroup *entity.TiDBGroup, force bool) (*entity.TiDBGroup, error)
	ApplyTiDBGroup(ctx context.Context, tidbClusterId, tidbGroupId string, force bool) error
	DeleteTiDBGroup(ctx context.Context, tidbClusterId, tidbGroupId string) (*entity.TiDBGroup, error)

	// privatelink service
	CreatePrivateLinkService(ctx context.Context, tidbClusterId string, privateLinkService *entity.PrivateLinkService) (*entity.PrivateLinkService, error)
	GetPrivateLinkService(ctx context.Context, tidbClusterId, tidbGroupId, privateLinkServiceId string) (*entity.PrivateLinkService, error)
	UpdatePrivateLinkService(ctx context.Context, tidbClusterId, tidbGroupId, privateLinkServiceId string, privateLinkConnections []*entity.PrivateLinkConnection) (*entity.PrivateLinkService, error)
	DeletePrivateLinkService(ctx context.Context, tidbClusterId, tidbGroupId, privateLinkServiceId string) error

	// BR
	ListLightweightBackups(ctx context.Context, req *ListLightweightBackupsInput) (*ListLightweightBackupsOutput, error)
	CreateLightweightRestore(ctx context.Context, req *br.CreateLightweightRestoreInput) error
	GetLightweightRestore(ctx context.Context, req *br.GetLightweightRestoreInput) (*br.GetLightweightRestoreOutput, error)
	GetLightweightRestorePostActions(ctx context.Context, req *br.GetLightweightRestorePostActionsInput) (*br.GetLightweightRestorePostActionsOutput, error)
	DeleteLightweightRestore(ctx context.Context, req *br.DeleteLightweightRestoreInput) error
	CreateTiKVCapacityReservation(ctx context.Context, req *CreateTiKVCapacityReservationInput) (*entity.TiKVCapacityReservation, error)
	GetTiKVCapacityReservation(ctx context.Context, req *GetTiKVCapacityReservationInput) (*entity.TiKVCapacityReservation, error)
	DeleteTiKVCapacityReservation(ctx context.Context, req *DeleteTiKVCapacityReservationInput) error
	CreateClassicRestore(ctx context.Context, req *CreateClassicRestoreInput) error
	GetClassicRestore(ctx context.Context, req *GetClassicRestoreInput) (*GetClassicRestoreOutput, error)
	DeleteClassicRestore(ctx context.Context, req *DeleteClassicRestoreInput) error
	CreateManualBackup(ctx context.Context, req *CreateManualBackupInput) error
	GetManualBackup(ctx context.Context, req *GetManualBackupInput) (*GetManualBackupOutput, error)
	DeleteManualBackup(ctx context.Context, req *DeleteManualBackupInput) error
	CreateManualBackupRestore(ctx context.Context, req *CreateManualBackupRestoreInput) error
	GetManualBackupRestore(ctx context.Context, req *GetManualBackupRestoreInput) (*GetManualBackupRestoreOutput, error)
	GetManualBackupRestorePostActions(ctx context.Context, req *GetManualBackupRestorePostActionsInput) (*GetManualBackupRestorePostActionsOutput, error)
	DeleteManualBackupRestore(ctx context.Context, req *DeleteManualBackupRestoreInput) error
	TestClassicBackupAccess(ctx context.Context, req *TestClassicBackupAccessInput) (*TestClassicBackupAccessOutput, error)
	UpdateBackupGcSetting(ctx context.Context, req *UpdateBackupGcSettingInput) (*UpdateBackupGcSettingOutput, error)
	GetBackupGcSetting(ctx context.Context, req *GetBackupGcSettingInput) (*GetBackupGcSettingOutput, error)
	UpdateAutoBackupMetering(ctx context.Context, req *apiv1.UpdateAutoBackupMeteringRequest) error
	ReportAutoBackupMetering(ctx context.Context, req *apiv1.ReportAutoBackupMeteringRequest) error

	// RuConfig
	GetRuConfig(ctx context.Context, id string, scope entity.RuConfigScope) (*entity.RuConfig, error)
	SetRuConfig(ctx context.Context, id string, scope entity.RuConfigScope, ruConfig *entity.RuConfig) (*entity.RuConfig, error)

	// AutoscalePolicy
	GetResolvedAutoscalePolicyBundle(ctx context.Context, sharedPoolID string, componentType entity.ComponentType) (*entity.ResolvedAutoscalePolicyBundle, error)
	ApplyMaterializedAutoscalePolicies(ctx context.Context, subjectType entity.AutoscalePolicySubjectType, subjectID string, policies []*entity.AutoscalePolicy) ([]*entity.AutoscalePolicy, error)
	EvaluateAutoscalePolicy(
		ctx context.Context,
		sharedPoolID string,
		componentType entity.ComponentType,
		direction entity.AutoscalePolicyDirection,
		capability entity.AutoscalePolicyCapability,
		trigger entity.AutoscalePolicyTrigger,
	) (*entity.EvaluateAutoscalePolicyResponse, error)
	ListAutoscalePolicies(ctx context.Context, subjectType entity.AutoscalePolicySubjectType, subjectID string, componentType entity.ComponentType) (*entity.ListAutoscalePoliciesResponse, error)
	UpsertAutoscaleRuntimeGuard(ctx context.Context, guard *entity.AutoscaleRuntimeGuard) (*entity.AutoscaleRuntimeGuard, error)
	DeleteAutoscaleRuntimeGuard(
		ctx context.Context,
		scopeType entity.AutoscaleRuntimeGuardScopeType,
		scopeID string,
		guardType entity.AutoscaleRuntimeGuardType,
		componentType entity.ComponentType,
	) error
	ListAutoscaleRuntimeGuards(ctx context.Context, filter repo.AutoscaleRuntimeGuardFilter) (*entity.ListAutoscaleRuntimeGuardsResponse, error)

	// Policy-shaped RPCs (PR-A: feat/apply-autoscale-policy-rpc).
	// See docs/design/tenant-aware-autoscale-policy-redesign.md
	// §POST (Replace) / PATCH / Fanout.
	//
	// Write RPCs translate AutoscalePolicySpec → ru_configs.FeatureFlags
	// and apply the patch to the appropriate row(s). The 3-state
	// apply_to_all_shared_pools propagation directive fans out at the
	// TENANT scope. PATCH = MERGE per-key; POST = REPLACE wholesale.
	//
	// No DELETE / CLEAR RPC and no way to remove a single override:
	// PATCH treats field=nil as PRESERVE (not clear) — the autoscale
	// flag in the merged result is whatever the existing row has, NOT
	// a cleared override. To remove an override, callers POST the
	// desired final state. (The `autoscale_policies` table is dormant
	// for SHARED_POOL/CLUSTER under storage-point exclusivity; the
	// applyPolicyPatchToTargets write-path writes `ru_configs.FeatureFlags`
	// at SHARED_POOL scope only, never to the legacy table.) The
	// documented wipe-everything path is the
	// (not-yet-implemented) ClearAutoscalePolicyBundle RPC, tracked in
	// design doc §Open questions.
	CreateOrReplaceAutoscalePolicy(ctx context.Context, scope apiv1.AutoscalePolicyScope, subjectID string, specs []*entity.AutoscalePolicySpec, applyToAllSharedPools *wrapperspb.BoolValue, requestID string) (*entity.AutoscalePolicyResponse, error)
	PatchAutoscalePolicy(ctx context.Context, scope apiv1.AutoscalePolicyScope, subjectID string, specs []*entity.AutoscalePolicySpec, applyToAllSharedPools *wrapperspb.BoolValue, requestID string) (*entity.AutoscalePolicyResponse, error)
	GetAutoscalePolicy(ctx context.Context, scope apiv1.AutoscalePolicyScope, subjectID string) (*entity.AutoscalePolicySpecBundle, error)
	GetEffectiveAutoscalePolicy(ctx context.Context, scope apiv1.AutoscalePolicyScope, subjectID string) (*entity.AutoscalePolicySpecBundle, error)
	ListAutoscalePolicy(ctx context.Context, filter repo.AutoscalePolicyBundleFilter, pageSize uint32, pageToken string) ([]*entity.AutoscalePolicySpecBundle, string, error)
	PreviewAutoscalePolicy(ctx context.Context, scope apiv1.AutoscalePolicyScope, subjectID string, specs []*entity.AutoscalePolicySpec, operation apiv1.PreviewOperationType, applyToAllSharedPools *wrapperspb.BoolValue) ([]*entity.AutoscalePolicyPreviewTarget, error)
	SyncAutoscalePolicy(ctx context.Context, scope apiv1.AutoscalePolicyScope, subjectID string, mode apiv1.SyncAutoscalePolicyMode, keys []*entity.AutoscalePolicySpecKey, applyToAllSharedPools *wrapperspb.BoolValue, requestID string) (*entity.AutoscalePolicyResponse, error)

	// ScaleOperation
	GetScaleOperation(ctx context.Context, sharedPoolID, scaleOperationID string) (*entity.ScaleOperation, error)
	CancelScaleOperation(ctx context.Context, sharedPoolID, scaleOperationID, reason string) (*entity.ScaleOperation, error)

	// NodeInstanceGroup
	CreateNodeInstanceGroup(ctx context.Context, group *entity.NodeInstanceGroup) (*entity.NodeInstanceGroup, error)
	ListNodeInstanceGroups(ctx context.Context, nodeSpec string) ([]*entity.NodeInstanceGroup, error)
	DeprecateNodeInstanceGroup(ctx context.Context, nodeSpec, primaryInstance string) (*entity.NodeInstanceGroup, error)
	SetNodeInstanceGroupStatus(ctx context.Context, nodeSpec, primaryInstance string, nodeGroupStatus apiv1.NodeInstanceGroup_Status) (*entity.NodeInstanceGroup, error)
	SetDataplaneNodeInstanceGroupStatus(ctx context.Context, dataplaneName, nodeSpec, primaryInstance string, status apiv1.DataplaneNodeInstanceGroup_Status) (*entity.DataplaneNodeInstanceGroup, error)
	ListDataplaneNodeInstanceGroups(ctx context.Context, dataplaneName string) ([]*entity.DataplaneNodeInstanceGroup, error)
	SetNodeInstanceGroupInstanceTypeStatus(ctx context.Context, nodeSpec, primaryInstance, instanceType string, status apiv1.InstanceTypeStatus) (*entity.NodeInstanceGroup, error)
	DeleteNodeInstanceGroup(ctx context.Context, nodeSpec, primaryInstance string) (*entity.NodeInstanceGroup, error)
	UpdateNodeInstanceGroup(ctx context.Context, nodeSpec, primaryInstance string, fallbackInstances []*apiv1.NodeInstanceGroup_FallbackInstance) (*entity.NodeInstanceGroup, error)

	// helper API used by e2e
	CheckPods(ctx context.Context, sharedPoolId string, clusterId string, componentType entity.ComponentType, form string) (*entity.CheckPodsResponse, error)
	// HPA
	// TODO(shenjun): need a get HPASpec API
	GetHPASpec(ctx context.Context, sharedPoolId string) ([]entity.ComponentHPASpec, error)
	SetHPASpec(ctx context.Context, sharedPoolId string, groupId string, componentType entity.ComponentType, spec *entity.HorizontalPodAutoscalerSpec) error
	SetHPAScaleBehavior(ctx context.Context, sharedPoolId string, groupId string, componentType entity.ComponentType, scaleUpEnabled *bool, scaleDownEnabled *bool) error
	// Scale Out Config
	SetScaleOutConfig(ctx context.Context, sharedPoolId string, groupId string, componentType entity.ComponentType, config *entity.ScaleOutConfig) error
	// SEM Config
	ApplySemConfig(ctx context.Context, sharedPoolId string) error

	// template versioning
	GetComponentTemplate(ctx context.Context, componentType entity.ComponentType, version string) (*apiv1.GetComponentTemplateResponse, error)
	ListComponentTemplateVersions(ctx context.Context, componentType entity.ComponentType) (*apiv1.ListComponentTemplateVersionsResponse, error)
	SetComponentTemplateVersionStatus(ctx context.Context, componentType entity.ComponentType, version string, status entity.TemplateVersionStatus) (*entity.TemplateVersionInfo, error)
	ListComponentTemplates(ctx context.Context) (*apiv1.ListComponentTemplatesResponse, error)
	// template versioning by template_name (for templates without ComponentType mapping)
	GetTemplate(ctx context.Context, templateName, version string) (*apiv1.GetTemplateResponse, error)
	ListTemplateVersions(ctx context.Context, templateName string) (*apiv1.ListTemplateVersionsResponse, error)
	SetTemplateVersionStatus(ctx context.Context, templateName, version string, status entity.TemplateVersionStatus) (*entity.TemplateVersionInfo, error)
	ListTemplates(ctx context.Context) (*apiv1.ListTemplatesResponse, error)
}

type serverImpl struct {
	cloudProvider string
	region        string
	// dependencies
	sharedPoolRepo            repo.SharedPoolRepo
	pauseResumeOperationRepo  repo.PauseResumeOperationRepo
	dataplaneRepo             repo.DataplaneRepo
	cassandraProxyStateRepo   repo.CassandraProxyStateRepo
	nodeGroupRepo             repo.NodeInstanceGroupRepo
	nodeGroupStateRepo        repo.DataplaneNodeInstanceGroupStateRepo
	dataplaneNodeGroupRepo    repo.DataplaneNodeInstanceGroupRepo
	tidbGroupRepo             repo.TiDBGroupRepo
	tidbClusterRepo           repo.TiDBClusterRepo
	dmClusterRepo             repo.DMClusterRepo
	exportRepo                repo.ExportRepo
	lockRepo                  repo.LockRepo
	ruConfigRepo              repo.RuConfigRepo
	autoscalePolicyBundleRepo repo.AutoscalePolicyBundleRepo
	autoscaleRuntimeGuardRepo repo.AutoscaleRuntimeGuardRepo
	transactioner             db.Transactioner
	lwRestoreRepo             repo.LightweightRestoreRepo
	classicRestoreRepo        repo.ClassicRestoreRepo
	manualBackupRepo          repo.ManualBackupRepo
	manualBackupRestoreRepo   repo.ManualBackupRestoreRepo
	scaleTikvDecisionRepo     repo.ScaleTikvDecisionRepo
	backupGcSettingRepo       repo.BackupGcSettingRepo
	templateVersionSvc        *templateversion.Service
	dataplaneManager          dataplane.Manager
	dataplaneClient           dataplanemgr.Client
	clustergatewayCli         clustergateway.Client
	clusterConfigClient       clusterconfig.Client
	dagExecutor               executor.RemoteExecutor
	imageConfig               *config.ImageConfig
	bizCfg                    *config.BizConfig
	o11yClusterPrefix         netip.Prefix
	o11yClusterCIDRConfigured bool
	storageSizePolicy         config.StorageSizePolicy
	scaleOperationRepo        repo.ScaleOperationRepo
	scaleOperationCfg         *config.ScaleOperationConfig
	// this metering config is set into kernel component's config, so use the dataplane metering config
	meteringConfig     *config.MeteringConfig
	meteringWriter     meteringWriter
	meteringDataWriter meteringWriter

	// wrappers
	keyspaceFetcher   repoext.KeyspaceFetcher
	dagInstanceFinder executorext.DagInstanceFinder
	scaleManager      braction.ScaleManager
}

func NewServer(
	cloudProvider,
	region string,
	transactioner db.Transactioner,
	sharedPoolRepo repo.SharedPoolRepo,
	pauseResumeOperationRepo repo.PauseResumeOperationRepo,
	dataplaneRepo repo.DataplaneRepo,
	cassandraProxyStateRepo repo.CassandraProxyStateRepo,
	nodeGroupRepo repo.NodeInstanceGroupRepo,
	nodeGroupStateRepo repo.DataplaneNodeInstanceGroupStateRepo,
	dataplaneNodeGroupRepo repo.DataplaneNodeInstanceGroupRepo,
	tidbClusterRepo repo.TiDBClusterRepo,
	tidbGroupRepo repo.TiDBGroupRepo,
	dmClusterRepo repo.DMClusterRepo,
	exportRepo repo.ExportRepo,
	lockRepo repo.LockRepo,
	ruConfigRepo repo.RuConfigRepo,
	autoscalePolicyBundleRepo repo.AutoscalePolicyBundleRepo,
	autoscaleRuntimeGuardRepo repo.AutoscaleRuntimeGuardRepo,
	scaleOperationRepo repo.ScaleOperationRepo,
	lwRestoreRepo repo.LightweightRestoreRepo,
	classicRestoreRepo repo.ClassicRestoreRepo,
	manualBackupRepo repo.ManualBackupRepo,
	manualBackupRestoreRepo repo.ManualBackupRestoreRepo,
	scaleTikvDecisionRepo repo.ScaleTikvDecisionRepo,
	backupGcSettingRepo repo.BackupGcSettingRepo,
	templateVersionSvc *templateversion.Service,
	dataPlaneManager dataplane.Manager,
	dataplaneClient dataplanemgr.Client,
	clustergatewayCli clustergateway.Client,
	clusterConfigClient clusterconfig.Client,
	dagExecutor executor.RemoteExecutor,
	imageConfig *config.ImageConfig,
	bizCfg *config.BizConfig,
	rcuCfg *config.RuConfig,
	scaleOperationCfg *config.ScaleOperationConfig,
	meteringConfig *config.MeteringConfig,
	meteringWriter meteringWriter,
	meteringDataWriter meteringWriter,
) (Service, error) {
	var o11yClusterCIDR string
	if bizCfg != nil {
		o11yClusterCIDR = bizCfg.O11yClusterCIDR
	}
	o11yClusterPrefix, o11yClusterCIDRConfigured, err := config.ParseO11yClusterCIDR(o11yClusterCIDR)
	if err != nil {
		return nil, fmt.Errorf("invalid o11y cluster cidr: %w", err)
	}
	storageSizePolicy := config.DefaultStorageSizePolicy()
	if bizCfg != nil && bizCfg.StorageSizePolicy != (config.StorageSizePolicy{}) {
		storageSizePolicy = bizCfg.StorageSizePolicy
	}
	if err := storageSizePolicy.Validate(); err != nil {
		return nil, fmt.Errorf("invalid storage size policy: %w", err)
	}

	return &serverImpl{
		cloudProvider:             cloudProvider,
		region:                    region,
		transactioner:             transactioner,
		sharedPoolRepo:            sharedPoolRepo,
		pauseResumeOperationRepo:  pauseResumeOperationRepo,
		dataplaneRepo:             dataplaneRepo,
		cassandraProxyStateRepo:   cassandraProxyStateRepo,
		nodeGroupRepo:             nodeGroupRepo,
		nodeGroupStateRepo:        nodeGroupStateRepo,
		dataplaneNodeGroupRepo:    dataplaneNodeGroupRepo,
		tidbGroupRepo:             tidbGroupRepo,
		tidbClusterRepo:           tidbClusterRepo,
		dmClusterRepo:             dmClusterRepo,
		exportRepo:                exportRepo,
		lockRepo:                  lockRepo,
		ruConfigRepo:              ruConfigRepo,
		autoscalePolicyBundleRepo: autoscalePolicyBundleRepo,
		autoscaleRuntimeGuardRepo: autoscaleRuntimeGuardRepo,
		lwRestoreRepo:             lwRestoreRepo,
		classicRestoreRepo:        classicRestoreRepo,
		manualBackupRepo:          manualBackupRepo,
		manualBackupRestoreRepo:   manualBackupRestoreRepo,
		scaleTikvDecisionRepo:     scaleTikvDecisionRepo,
		backupGcSettingRepo:       backupGcSettingRepo,
		templateVersionSvc:        templateVersionSvc,
		dataplaneManager:          dataPlaneManager,
		dataplaneClient:           dataplaneClient,
		clusterConfigClient:       clusterConfigClient,
		clustergatewayCli:         clustergatewayCli,
		dagExecutor:               dagExecutor,
		imageConfig:               imageConfig,
		bizCfg:                    bizCfg,
		o11yClusterPrefix:         o11yClusterPrefix,
		o11yClusterCIDRConfigured: o11yClusterCIDRConfigured,
		storageSizePolicy:         storageSizePolicy,
		scaleOperationRepo:        scaleOperationRepo,
		scaleOperationCfg:         scaleOperationCfg,
		meteringConfig:            meteringConfig,
		meteringWriter:            meteringWriter,
		meteringDataWriter:        meteringDataWriter,
		// wrappers
		keyspaceFetcher:   repoext.NewKeyspaceFetcher(tidbGroupRepo),
		dagInstanceFinder: executorext.NewDagInstanceFinder(dagExecutor),
		scaleManager:      braction.NewScaleManager(sharedPoolRepo, scaleTikvDecisionRepo, clustergatewayCli, dataPlaneManager, transactioner, bizCfg),
	}, nil
}
