package cmd

import (
	"os"

	"github.com/spf13/cobra"
	"github.com/tidbcloud/tiinf/transport/crossregion"
	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
	"k8s.io/apimachinery/pkg/labels"
	ctrl "sigs.k8s.io/controller-runtime"
	"sigs.k8s.io/controller-runtime/pkg/cache"
	"sigs.k8s.io/controller-runtime/pkg/client"
	"sigs.k8s.io/controller-runtime/pkg/predicate"

	"github.com/tidbcloud/eks-provider/controllers/dumpling"
	cloudv1 "github.com/tidbcloud/infra-api/api/v1"
	compatk8s "github.com/tidbcloud/infra-provider/pkg/compat/k8s"
	pkgconfig "github.com/tidbcloud/infra-provider/pkg/config"
)

func buildDumplingCacheConfig(selector labels.Selector) map[client.Object]cache.ByObject {
	return map[client.Object]cache.ByObject{
		&cloudv1.Dumpling{}: {
			Label: selector,
		},
	}
}

func mustRegisterDumplingControllers(rootConfig pkgconfig.RootConfig, mgr ctrl.Manager) {
	p, err := predicate.LabelSelectorPredicate(rootConfig.Predicate)
	if err != nil {
		setupLog.Error(err, "unable to create predicate")
		os.Exit(1)
	}
	var infraCli client.Client
	var infraReader client.Reader
	if pkgconfig.FeatureEnabled(rootConfig.FeatureGates, pkgconfig.EnableDPCompatibilityMode, "", "") {
		infraCli = compatk8s.NewCompatK8sClient(mgr.GetClient(), crossregion.EnvType(rootConfig.DPCompatEnv), rootConfig.DPCompatAssumeRole, rootConfig.DPComaptDataPlaneRoleArn, rootConfig.DPCompatAssumeExternalId, pkgconfig.OverrideConfig{}, rootConfig.ClusterServiceEndpoint)
		infraReader = compatk8s.NewCompatK8sReader(mgr.GetCache(), crossregion.EnvType(rootConfig.DPCompatEnv), rootConfig.DPCompatAssumeRole, rootConfig.DPComaptDataPlaneRoleArn, rootConfig.DPCompatAssumeExternalId, pkgconfig.OverrideConfig{}, rootConfig.ClusterServiceEndpoint)
	} else {
		infraCli = mgr.GetClient()
		infraReader = mgr.GetCache()
	}
	if err = (&dumpling.DumplingReconciler{
		Client:        infraCli,
		Cache:         infraReader,
		Config:        rootConfig,
		EventRecorder: mgr.GetEventRecorderFor("dumpling-controller"),
	}).SetupWithManager(mgr, p); err != nil {
		setupLog.Error(err, "unable to create controller", "controller", "Dumpling")
		os.Exit(1)
	}
}

func runDumplingControllers() {
	setupLog.Info("starting dumpling controllers")
	rootConfig := mustBuildRootConfig()
	// parse cache selector from root config
	selector, err := metav1.LabelSelectorAsSelector(&rootConfig.Predicate)
	if err != nil {
		setupLog.Error(err, "invalid predicates")
		os.Exit(1)
	}
	mgr := mustBuildManager("dumpling", rootConfig.Network.Region, buildDumplingCacheConfig(selector), nil, rootConfig.DryRun.Enabled)
	mustRegisterDumplingControllers(rootConfig, mgr)
	mustRunManager(ctrl.SetupSignalHandler(), mgr)
}

var dumplingCMD = &cobra.Command{
	Use:   "run-dumpling-controller",
	Short: "running dumpling controllers",
	Run: func(cmd *cobra.Command, args []string) {
		runDumplingControllers()
	},
}

func init() {
	rootCmd.AddCommand(dumplingCMD)
}
