package main

import (
	"github.com/crossplane-contrib/provider-aws/apis/autoscaling/v1beta1"
	"github.com/crossplane-contrib/provider-aws/apis/eks/manualv1alpha1"
	"github.com/pingcap/log"
	"github.com/samber/lo"
	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
	"k8s.io/apimachinery/pkg/labels"
	"k8s.io/client-go/tools/clientcmd"
	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/log/zap"
	metricsserver "sigs.k8s.io/controller-runtime/pkg/metrics/server"

	cloudv1 "github.com/tidbcloud/infra-api/api/v1"
	"github.com/tidbcloud/infra-provider/pkg/scheme"
)

func newK8sControllerManager(provider, kubeconfigPath string) (ctrl.Manager, error) {
	restCfg, err := clientcmd.BuildConfigFromFlags("", kubeconfigPath)
	if err != nil {
		return nil, err
	}

	// same encoder as other loggers
	encoder, err := log.NewTextEncoder(&log.Config{Level: "info"})
	if err != nil {
		return nil, err
	}
	opts := zap.Options{
		Encoder: encoder,
	}
	ctrl.SetLogger(zap.New(zap.UseFlagOptions(&opts)))

	selector := lo.Must1(metav1.LabelSelectorAsSelector(&metav1.LabelSelector{
		MatchLabels: map[string]string{
			cloudv1.LabelServiceType: cloudv1.ServiceTypeDedicated,
		},
	}))
	return ctrl.NewManager(restCfg, ctrl.Options{
		Scheme: scheme.Scheme,
		Metrics: metricsserver.Options{
			BindAddress: "0", // disable now, enable it when we need it
		},
		// Only load objects to local cache if it matches the label selector.
		Cache: cache.Options{
			ByObject: buildCacheConfig(provider, selector),
		},
		LeaderElection: false,
	})
}

func buildCacheConfig(provider string, selector labels.Selector) map[client.Object]cache.ByObject {
	m := map[client.Object]cache.ByObject{
		&cloudv1.Cluster{}: {
			Label: selector,
		},
		&cloudv1.Workflow{}:     {}, // cache all workflow
		&cloudv1.ConfigChange{}: {}, // cache all configchange
	}

	// For GetInfraInformation API
	if provider == cloudv1.ProviderAWS {
		m[&v1beta1.AutoScalingGroup{}] = cache.ByObject{}
		m[&manualv1alpha1.NodeGroup{}] = cache.ByObject{}
	}

	return m
}
