package cluster

import (
	"github.com/tidbcloud/eks-provider/controllers/cluster/task"
	akstask "github.com/tidbcloud/eks-provider/controllers/cluster/task/aks"
	commontask "github.com/tidbcloud/eks-provider/controllers/cluster/task/common"
	ekstask "github.com/tidbcloud/eks-provider/controllers/cluster/task/eks"
	eksextragroup "github.com/tidbcloud/eks-provider/controllers/cluster/task/eks/extragroup"
	eksextragroupnodegroup "github.com/tidbcloud/eks-provider/controllers/cluster/task/eks/extragroup/nodegroup"
	gketask "github.com/tidbcloud/eks-provider/controllers/cluster/task/gke"
	"github.com/tidbcloud/infra-provider/pkg/consts"
	"github.com/tidbcloud/infra-provider/pkg/deploy"
)

func GetClusterTasks(r *ClusterReconciler, c *task.Context) []deploy.Task {
	switch c.Config.Provider {
	case consts.ProviderTypeEKS:
		return GetEKSClusterTasks(r, c)
	case consts.ProviderTypeGKE:
		return GetGKEClusterTasks(r, c)
	case consts.ProviderTypeAKS:
		return GetAKSClusterTasks(r, c)
	}

	return nil
}

func GetEKSClusterTasks(r *ClusterReconciler, c *task.Context) (tasks []deploy.Task) {
	tasks = []deploy.Task{
		// This task will always return done
		commontask.NewKubernetesInfoSaver(c),
		commontask.NewPriorityClass(c),

		// TODO: this task should run after guardian task
		// But now it blocks kms key creation in guardian task
		ekstask.NewProviderConfig(c),

		ekstask.NewGuardian(c, r.AWSCli),
		commontask.NewDNS(c),

		// these tasks only used in new separate cluster-controller
		ekstask.NewNodeRole(c),
		ekstask.NewBatchOpsRole(c),

		commontask.NewNamespace(c),
		commontask.NewStorageClass(c),
		ekstask.NewServiceSG(c, r.AWSCli),
		commontask.NewAuditLog(c),
		getTidbClusterTask(c),
		commontask.NewClusterProxyRegionalEndpoint(c),
		commontask.NewClusterAgent(c),
		// extra group will update the tidbcluster status attached to tidb cluster
		getTiDBGroupTask(c),
		commontask.NewScaleStatusTrack(c),
		commontask.NewWorkflow(c),
		// placeholder nodegroup task is a temporary hack to workaround
		// aws-auth configmap issues
		ekstask.NewPlaceholderNodegroup(c),
		ekstask.NewSelfManagedNodegroup(c, r.AWSCli),
		ekstask.NewNodegroup(c),
		eksextragroupnodegroup.NewSelfManagedNodegroup(c, r.AWSCli),
		commontask.NewPCAIssuer(c),
		commontask.NewComponentsSelfSignedIssuer(c),
		commontask.NewCert(c),
		commontask.NewSecret(c),
		commontask.NewTiDBGroupSecret(c),
		commontask.NewTiDBInitializer(c),
		commontask.NewPV(c),
		commontask.NewTiDBGroupPVCleaner(c),
		ekstask.NewService(c),
		ekstask.NewFullService(c, r.AWSCli),
		commontask.NewTiDBGroupCert(c),
		commontask.NewTiDBGroupService(c, r.AWSCli),
		eksextragroup.NewPrivateLink(c, r.AWSCli),
	}

	if ekstask.IsPrivateLinkRequired(*c.Cluster) {
		tasks = append(tasks, ekstask.NewPrivateLink(c, r.AWSCli))
	}

	tasks = append(tasks, commontask.NewO11yCluster(c))

	return tasks
}

func GetGKEClusterTasks(r *ClusterReconciler, c *task.Context) (tasks []deploy.Task) {
	tasks = []deploy.Task{
		// This task will always return done
		commontask.NewKubernetesInfoSaver(c),
		commontask.NewPriorityClass(c),

		// this task only used in new separate cluster-controller
		gketask.NewProviderConfig(c, r.GCPCli),

		// TODO: combine guardian task
		gketask.NewGuardian(c, r.GCPCli),
		commontask.NewDNS(c),
		// TODO: enable kms after cross cloud auth problem is resolved
		// commontask.NewKMS(c),
		commontask.NewNamespace(c),
		commontask.NewStorageClass(c),
		commontask.NewPCAIssuer(c),
		commontask.NewComponentsSelfSignedIssuer(c),
		commontask.NewCert(c),
		commontask.NewTiDBGroupCert(c),
		commontask.NewSecret(c),
		commontask.NewTiDBGroupSecret(c),
		gketask.NewGCPServiceAccount(c),
		gketask.NewArtifactRegistryPolicy(c, r.GCPCli),
		gketask.NewGCRBucketPolicy(c),
		gketask.NewSharedBucket(c, r.GCPCli),
		gketask.NewSecret(c),
		// TODO: enable it after changing the logic of core-svc
		// commontask.NewMTLS(c),
		commontask.NewAuditLog(c),
		getTidbClusterTask(c),
		commontask.NewClusterProxyRegionalEndpoint(c),
		commontask.NewClusterAgent(c),
		getTiDBGroupTask(c),
		commontask.NewGKEHeterogeneousStatusTrack(c),
		commontask.NewScaleStatusTrack(c),
		commontask.NewWorkflow(c),
		// nodepool task will use the tidbcluster CR, so it should be after the tidbcluster task
		commontask.NewNodePool(c, r.GCPCli),
		commontask.NewGKEComputeClassCleanup(c),
		commontask.NewTiDBInitializer(c),
		commontask.NewPV(c),
		commontask.NewTiDBGroupPVCleaner(c),
		// TODO: combine with the eks one and move to common task pkg
		commontask.NewFullService(c),
		commontask.NewTiDBGroupService(c, nil),
		// After FullService
		gketask.NewPSC(c, r.GCPCli),
		gketask.NewLoadBalancer(c, r.GCPCli),
	}

	tasks = append(tasks, commontask.NewO11yCluster(c))

	return tasks
}

func GetAKSClusterTasks(_ *ClusterReconciler, c *task.Context) (tasks []deploy.Task) {
	tasks = []deploy.Task{
		akstask.NewGuardian(c),
		commontask.NewPriorityClass(c),
		akstask.NewProviderConfig(c),
		akstask.NewProviderConfig2(c),
		commontask.NewDNS(c),
		commontask.NewNamespace(c),
		akstask.NewDiskEncryptionSetTask(c),
		commontask.NewStorageClass(c),
		commontask.NewPCAIssuer(c),
		commontask.NewComponentsSelfSignedIssuer(c),
		commontask.NewCert(c),
		commontask.NewTiDBGroupCert(c),
		commontask.NewSecret(c),
		commontask.NewTiDBGroupSecret(c),
		commontask.NewAuditLog(c),
		getTidbClusterTask(c),
		// Cluster Agent and Regional Cluster Proxy Endpoint
		commontask.NewClusterProxyRegionalEndpoint(c),
		commontask.NewClusterAgent(c),
		getTiDBGroupTask(c),
		commontask.NewScaleStatusTrack(c),
		commontask.NewWorkflow(c),
		akstask.NewNodePool(c),
		commontask.NewTiDBInitializer(c),
		commontask.NewPV(c),
		commontask.NewTiDBGroupPVCleaner(c),
		// TiDB Serivce and DNS Record
		akstask.NewService(c),
		commontask.NewTiDBGroupService(c, nil),
		// NodeReadyCheck task
		commontask.NewNodeReadyCheck(c),
	}
	return tasks
}

func getTidbClusterTask(c *task.Context) deploy.Task {
	if c.Cluster.FeatureEnabled(consts.ClusterFeatureUseTiDBOperatorV2) {
		return commontask.NewTiDBClusterV2(c)
	}
	return commontask.NewTiDBCluster(c)
}

func getTiDBGroupTask(c *task.Context) deploy.Task {
	if c.Cluster.FeatureEnabled(consts.ClusterFeatureUseTiDBOperatorV2) {
		return commontask.NewTiDBGroupV2(c)
	}
	return commontask.NewTiDBGroup(c)
}
