package appbox

import (
	"github.com/tidbcloud/infra-provider/regional-server/pkg/consts"
	"github.com/tidbcloud/infra-provider/regional-server/pkg/controllers/appbox/task"
	acktask "github.com/tidbcloud/infra-provider/regional-server/pkg/controllers/appbox/task/ack"
	akstask "github.com/tidbcloud/infra-provider/regional-server/pkg/controllers/appbox/task/aks"
	"github.com/tidbcloud/infra-provider/regional-server/pkg/controllers/appbox/task/common"
	ekstask "github.com/tidbcloud/infra-provider/regional-server/pkg/controllers/appbox/task/eks"
	"github.com/tidbcloud/infra-provider/regional-server/pkg/deploy"
)

func GetAPPBoxTasks(r *APPBoxReconciler, c *task.Context) (tasks []deploy.Task) {
	switch c.Config.Provider {
	case consts.ProviderTypeEKS:
		return GetEKSAPPBoxTasks(r, c)
	case consts.ProviderTypeACK:
		return GetACKAPPBoxTasks(r, c)
	case consts.ProviderTypeAKS:
		return GetAKSAPPBoxTasks(r, c)
	}
	return nil
}

func GetEKSAPPBoxTasks(r *APPBoxReconciler, c *task.Context) (tasks []deploy.Task) {
	tasks = []deploy.Task{
		common.NewGuardian(c),
		ekstask.NewEKS(c, r.AWSCli, r.Manager),
		ekstask.NewAccessEntryTask(c),
		ekstask.NewNodeRole(c),
		ekstask.NewNodegroup(c, r.AWSCli),
		common.NewPriorityClass(c),
		common.NewLocalVolumeProvisioner(c),
		ekstask.NewStorageClass(c),
		// worker nodepools are managed by the dataplane controller
		// ekstask.NewOIDC(c), // We don't use IRSA at the moment
		// infra components
		ekstask.NewAddons(c),
		common.NewNamespace(c),
		ekstask.NewClusterAutoscaler(c),
		common.NewNodeExporter(c),
		common.NewNodeLocalDNS(c),
		common.NewKubeStateMetrics(c),
		common.NewMetricsServer(c),
		common.NewEventExporter(c),
		common.NewGoldpinger(c),
		common.NewNodePinger(c),
		common.NewDataplaneExporter(c),
		common.NewKubeletVolumeStatsExporter(c),
		common.NewCertManager(c),
		common.NewPCAIssuer(c), // PCAIssuer relies on cert-manager to succeed
		common.NewSelfSignedCAClusterIssuer(c),
		ekstask.NewAWSLBController(c), // AWS LB Controller relies on cert-manager crds.
		ekstask.NewExternalDNS(c),
		// dedicated components
		common.NewTiDBOperatorV2(c),
		common.NewClusterGateway(c),
		ekstask.NewApiGatewayService(c, r.AWSCli),
		common.NewClusterRole(c),
		common.NewClusterProxy(c),
		common.NewServiceProxy(c),
		ekstask.NewSLIReporter(c),
		common.NewNGAutoScaler(c),
		common.NewCapacityPlanner(c),
		// data platform components
		common.NewDataflowAgent(c),
		// o11y components
		common.NewO11y(c, ekstask.NewO11yProvider()),
	}

	if c.IsBYOC() {
		tasks = append(tasks,
			ekstask.NewClusterGatewayService(c, r.AWSCli),
			ekstask.NewClusterGatewayEndpoint(c),
			ekstask.NewK8sAPIServerIngress(c, r.Manager),
		)
	}

	return tasks
}

func GetACKAPPBoxTasks(r *APPBoxReconciler, c *task.Context) (tasks []deploy.Task) {
	tasks = []deploy.Task{
		common.NewGuardian(c),
		acktask.NewACK(c, r.AliyunCli),
		// Set network
		acktask.NewACL(c, r.AliyunCli),
		acktask.NewSecurityGroup(c),
		acktask.NewNodeSecurityGroup(c),
		// Set RAM
		acktask.NewACKWorkerPolicy(c),
		acktask.NewOIDC(c),
		acktask.NewNodeRole(c),
		// Create admin nodepool
		acktask.NewNodePool(c),
		acktask.NewAddons(c),
		// permission task rely on ack-ram-authenticator addon
		// tasks rely on remote client must wait permission task finish
		acktask.NewPermissions(c, r.AliyunCli),
		common.NewPriorityClass(c),
		acktask.NewDaemonSetRequests(c),
		acktask.NewStorageClass(c),
		// worker nodepools are managed by the dataplane/nodepool controllers
		acktask.NewACR(c),
		acktask.NewCSIDriver(c),
		// infra components
		common.NewLocalVolumeProvisioner(c),
		common.NewNamespace(c),
		common.NewNodeExporter(c),
		common.NewKubeStateMetrics(c),
		common.NewEventExporter(c),
		common.NewGoldpinger(c),
		common.NewNodePinger(c),
		common.NewDataplaneExporter(c),
		common.NewCertManager(c),
		acktask.NewPCAIssuer(c),
		common.NewSelfSignedCAClusterIssuer(c),
		// dedicated components
		common.NewTiDBOperatorV2(c),
		common.NewClusterGateway(c),
		acktask.NewApiGatewayService(c, r.AliyunCli),
		common.NewClusterRole(c),
		common.NewClusterProxy(c),
		common.NewServiceProxy(c),
		acktask.NewSLIReporter(c),
		common.NewNGAutoScaler(c),
		common.NewCapacityPlanner(c),
		// data platform components
		common.NewDataflowAgent(c),
		// o11y components
		common.NewO11y(c, acktask.NewO11yProvider()),
	}

	return tasks
}

func GetAKSAPPBoxTasks(r *APPBoxReconciler, c *task.Context) (tasks []deploy.Task) {
	tasks = []deploy.Task{
		common.NewGuardian(c),
		akstask.NewAKSManagedIdentity(c),
		akstask.NewAKS(c, r.AzureCli),
	}
	if c.IsBYOC() {
		tasks = append(tasks,
			akstask.NewAPIServerPrivateLinkService(c, r.AzureCli),
			akstask.NewAPIServerEndpoint(c, r.AzureCli),
			akstask.NewAPIServerDNS(c, r.AzureCli),
		)
	}
	tasks = append(tasks,
		akstask.NewAdminNodePool(c),
		akstask.NewNodeRoleAssignment(c),
		akstask.NewOIDC(c),
		akstask.NewWorkerNodePool(c),
		akstask.NewStorageClass(c),
		common.NewPriorityClass(c),
		common.NewNamespace(c),
		common.NewKubeStateMetrics(c),
		common.NewNodeExporter(c),
		common.NewEventExporter(c),
		common.NewGoldpinger(c),
		common.NewNodePinger(c),
		common.NewDataplaneExporter(c),
		common.NewCertManager(c),
		akstask.NewPCAIssuer(c),
		common.NewSelfSignedCAClusterIssuer(c),
		common.NewTiDBOperatorV2(c),
		common.NewClusterGateway(c),
		akstask.NewApiGatewayService(c),
	)
	if c.IsBYOC() {
		tasks = append(tasks,
			akstask.NewClusterGatewayService(c),
			akstask.NewClusterGatewayEndpoint(c, r.AzureCli),
			akstask.NewClusterGatewayDNS(c),
		)
	}
	tasks = append(tasks,
		common.NewClusterRole(c),
		common.NewClusterProxy(c),
		common.NewServiceProxy(c),
		akstask.NewSLIReporter(c),
		common.NewNGAutoScaler(c),
		common.NewCapacityPlanner(c),
		// data platform components
		common.NewDataflowAgent(c),
		// o11y components
		common.NewO11y(c, akstask.NewO11yProvider()),
		akstask.NewRBAC(c),
	)
	return tasks
}
