package main

import (
	"context"
	"flag"
	"os"

	"github.com/gin-contrib/pprof"
	"github.com/gin-gonic/gin"
	"github.com/tidbcloud/cluster-service-ng/pkg/autoscale/app"
	k8s "github.com/tidbcloud/cluster-service-ng/pkg/k8s"
	metricsprov "github.com/tidbcloud/cluster-service-ng/pkg/metricsprovider"
	"k8s.io/client-go/dynamic"
	"k8s.io/client-go/scale"
	"k8s.io/component-base/logs"
	"k8s.io/klog/v2"
	resourceclient "k8s.io/metrics/pkg/client/clientset/versioned/typed/metrics/v1beta1"
	basecmd "sigs.k8s.io/custom-metrics-apiserver/pkg/cmd"
	"sigs.k8s.io/custom-metrics-apiserver/pkg/provider"
)

type Adapter struct {
	basecmd.AdapterBase
	DisableScaleIn int64
}

func (a *Adapter) makeProviderOrDie() provider.MetricsProvider {
	restCfg, err := a.ClientConfig()
	if err != nil {
		klog.Fatalf("unable to build client config: %v", err)
	}
	kubeClient, err := k8s.NewClient(context.Background(), restCfg)
	if err != nil {
		klog.Fatalf("unable to build kube client: %v", err)
	}
	mapper := k8s.RESTMapper()

	resourceMetricsClient := resourceclient.NewForConfigOrDie(restCfg)
	scaleClient, err := scale.NewForConfig(
		restCfg,
		mapper,
		dynamic.LegacyAPIPathResolverFunc,
		&k8s.StaticScaleKindResolver{},
	)
	if err != nil {
		klog.Fatalf("unable to build scale client: %v", err)
	}
	return metricsprov.NewCMProvider(
		kubeClient,
		mapper,
		a.DisableScaleIn,
		resourceMetricsClient,
		scaleClient,
	)
}

// TODO(shenjun): standardize the log stack.
func main() {
	logs.InitLogs()
	defer logs.FlushLogs()

	// initialize the flags, with one custom flag for the message
	adapter := &Adapter{}
	adapter.Flags().Int64Var(&adapter.DisableScaleIn, "disable-scale-in", 0, "disable scale in")
	// make sure you get the klog flags
	logs.AddGoFlags(flag.CommandLine)
	adapter.Flags().AddGoFlagSet(flag.CommandLine)
	_ = adapter.Flags().Parse(os.Args)

	mp := adapter.makeProviderOrDie()
	adapter.WithCustomMetrics(mp)
	adapter.WithExternalMetrics(mp)

	go func() {
		cfg, err := app.LoadConfigFromFile(app.DefaultConfigPath)
		if err != nil {
			klog.ErrorS(err, "failed to load autoscale config")
			return
		}
		if len(cfg.ClusterScalers) == 0 {
			klog.InfoS("no cluster scalers configured, skipping autoscale")
			return
		}
		if err := app.Run(cfg); err != nil {
			klog.ErrorS(err, "autoscale error")
		}
	}()

	go func() {
		router := gin.Default()
		pprof.Register(router)
		if err := router.Run(":6060"); err != nil {
			klog.Fatalf("unable to run pprof server: %v", err)
		}
	}()
	if err := adapter.Run(context.Background()); err != nil {
		klog.Fatalf("unable to run custom metrics adapter: %v", err)
	}
}
