package httpapi

import (
	"context"
	"errors"
	"fmt"
	"log"
	"net/http"
	"time"

	"github.com/gin-contrib/cors"
	"github.com/gin-gonic/gin"
	"github.com/prometheus/client_golang/prometheus/promhttp"
	"github.com/tidbcloud/metering/pkg/common/config"
	"github.com/tidbcloud/metering/pkg/common/constants"
)

func StartService(ctx context.Context, serviceconfig config.ServiceConfig) {

	if serviceconfig.IsProd() {
		gin.SetMode(gin.ReleaseMode)
	} else {
		gin.SetMode(gin.DebugMode)
	}

	g := gin.New()
	g.Use(cors.New(corsConfig()))
	route(g, serviceconfig.EnablePprof)

	port := serviceconfig.Port
	addr := fmt.Sprintf(":%d", port)

	srv := &http.Server{
		Addr:              addr,
		Handler:           g,
		ReadHeaderTimeout: constants.GinReadHeaderTimeout,
		IdleTimeout:       constants.GinIdleTimeout,
	}

	// initial metrics server
	go metricsServer(serviceconfig.MetricsPort)

	// Initializing the server in a goroutine so that
	// it won't block the graceful shutdown handling below
	go func() {
		if err := srv.ListenAndServe(); err != nil && errors.Is(err, http.ErrServerClosed) {
			log.Printf("listen: %s\n", err)
		}
	}()
	<-ctx.Done()
	timeoutCtx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
	defer cancel()
	if err := srv.Shutdown(timeoutCtx); err != nil {
		log.Fatal("Server forced to shutdown:", err)
	}
	log.Printf("Wait %s for all graceful shutdown\n", constants.GracefulShutDownWait.String())
	t := time.NewTimer(constants.GracefulShutDownWait)
	<-t.C
	log.Println("Server exiting")

}

// metricsServer
// @Description: boot metricsServer
// @Parameter metricsPort
func metricsServer(metricsPort int) {
	mux := http.NewServeMux()
	h := promhttp.Handler()
	mux.Handle("/metrics", h)
	log.Printf("metrics listen address [:%d]", metricsPort)
	addr := fmt.Sprintf(":%d", metricsPort)
	srv := &http.Server{
		Addr:              addr,
		Handler:           mux,
		ReadHeaderTimeout: constants.GinReadHeaderTimeout,
	}
	err := srv.ListenAndServe()
	if err != nil {
		log.Fatal("metrics listen and serve error: " + err.Error())
	}
}

// corsConfig
// @Description: build cors config
// @return cors.Config
func corsConfig() cors.Config {
	config := cors.DefaultConfig()
	config.AllowHeaders = []string{"*"}
	config.AllowCredentials = true
	config.AllowOriginFunc = func(origin string) bool {
		return true
	}
	return config
}
