package main

import (
	"context"
	"net/http"
	"net/http/pprof"
	"os"
	"time"

	"github.com/prometheus/client_golang/prometheus/promhttp"

	"github.com/tidbcloud/sli-reporter/firehose"
	k8s "github.com/tidbcloud/sli-reporter/kubernetes"
	"github.com/tidbcloud/sli-reporter/slprober"

	"k8s.io/apimachinery/pkg/util/wait"

	"github.com/pingcap/log"
	"go.uber.org/zap"
)

const ServiceLevelProbeInterval = 6 * time.Second

var (
	deliveryStreamName          string
	deliveryStreamRoleArn       string
	reporterMode                string
	sendRegistryMetricsInterval = 6 * time.Second
)

func main() {
	getConfigFromEnv()
	if err := k8s.InitConfig(); err != nil {
		log.Fatal("failed to init k8s config", zap.Error(err))
	}
	log.Info("init config successfully")
	reg := slprober.RegisterMetric()
	sender := firehose.NewSender(reporterMode, deliveryStreamName, deliveryStreamRoleArn)

	if reporterMode == "" || reporterMode == "DEDICATED" {
		onStarted := func(ctx context.Context) {
			if k8s.CheckTiDBClusterCRDExists(ctx) {
				k8s.TiDBClusterInformerFactory.Start(ctx.Done())
				// Wait for all started informers' cache were synced.
				for v, synced := range k8s.TiDBClusterInformerFactory.WaitForCacheSync(wait.NeverStop) {
					if !synced {
						log.Fatal("error syncing informer", zap.Any("value", v))
					}
				}
				log.Info("cache of informer factories sync successfully")
			} else {
				log.Warn("TiDBCluster CRD not found, skipping informer startup")
			}

			go wait.NonSlidingUntil(func() { k8s.Prober.Probe() }, ServiceLevelProbeInterval, wait.NeverStop)
			log.Info("Probe started successfully")
		}
		controllerCtx, cancel := context.WithCancel(context.Background())
		defer cancel()
		onStarted(controllerCtx)

		go wait.Forever(func() {
			if err := sender.SendMetricsFromRegistry(reg); err != nil {
				log.Error(err.Error())
			}
		}, sendRegistryMetricsInterval)
	}

	log.Info("Begin server")
	mux := http.NewServeMux()
	setupMetricsHandler(mux)
	setupPprofHandler(mux)
	server := http.Server{
		Addr:         "0.0.0.0:8080",
		Handler:      mux,
		ReadTimeout:  10 * time.Second,
		WriteTimeout: 10 * time.Second,
	}
	err := server.ListenAndServe()
	if err != nil {
		log.Error(err.Error())
	}
}

func getConfigFromEnv() {
	deliveryStreamName = os.Getenv("AWS_DELIVERY_STREAM_NAME")
	deliveryStreamRoleArn = os.Getenv("AWS_DELIVERY_STREAM_ROLE_ARN")
	reporterMode = os.Getenv("SLI_REPORTER_MODE")
}

func setupMetricsHandler(mux *http.ServeMux) {
	mux.Handle("/metrics", promhttp.Handler())
}

func setupPprofHandler(mux *http.ServeMux) {
	mux.HandleFunc("/debug/pprof/", pprof.Index)
	mux.HandleFunc("/debug/pprof/cmdline", pprof.Cmdline)
	mux.HandleFunc("/debug/pprof/profile", pprof.Profile)
	mux.HandleFunc("/debug/pprof/symbol", pprof.Symbol)
	mux.HandleFunc("/debug/pprof/trace", pprof.Trace)
}
