package main

import (
	"fmt"
	"net/http"
	"sync"
	"time"

	_ "net/http/pprof"

	"github.com/gin-gonic/gin"
	"github.com/godoes/ginprom"
	"github.com/penglongli/gin-metrics/ginmetrics"
	"github.com/prometheus/client_golang/prometheus/promhttp"
	swaggerFiles "github.com/swaggo/files"
	ginSwagger "github.com/swaggo/gin-swagger"

	"be.ems/src"
	"be.ems/src/framework/config"
	"be.ems/src/framework/logger"
	"be.ems/src/framework/utils/machine"
	"be.ems/src/framework/utils/parse"
	_ "be.ems/swagger_docs"
)

var wg sync.WaitGroup               // 等待服务
var maxRetries = 10                 // 最大重试次数
var retryInterval = 5 * time.Second // 重试间隔时间

// @title						OMC Swagger API
// @version					1.0.8
// @description				OMC Service Interface Information - Internal Use Only
//
// @tag.name					chart
// @tag.description			chart interface
//
// @tag.name					common
// @tag.description			common interface
// @tag.name					common/authorization
// @tag.description			common authorization Interface
// @tag.name					common/file
// @tag.description			common file Interface
//
// @tag.name					monitor
// @tag.description			monitor interface
// @tag.name					monitor/cache
// @tag.description			monitor cache interface
// @tag.name					monitor/online
// @tag.description			monitor system user online interface
//
// @tag.name					ne_data
// @tag.description			network data interface
// @tag.name					ne_data/alarm
// @tag.description			network data alarm interface
// @tag.name					ne_data/kpi
// @tag.description			network data kpi interface
// @tag.name					ne_data/amf
// @tag.description			network data amf interface
// @tag.name					ne_data/ims
// @tag.description			network data ims interface
// @tag.name					ne_data/mme
// @tag.description			network data mme interface
// @tag.name					ne_data/sgwc
// @tag.description			network data sgwc interface
// @tag.name					ne_data/smf
// @tag.description			network data smf interface
// @tag.name					ne_data/smsc
// @tag.description			network data smsc interface
// @tag.name					ne_data/udm/auth
// @tag.description			network data udm authentication interface
// @tag.name					ne_data/udm/sub
// @tag.description			network data udm subscriber interface
// @tag.name					ne_data/udm/voip
// @tag.description			network data udm voip interface
// @tag.name					ne_data/udm/volte-ims
// @tag.description			network data udm volte interface
// @tag.name					ne_data/upf
// @tag.description			network data upf interface
//
// @tag.name					ne
// @tag.description			network element interface
// @tag.name					ne/action
// @tag.description			network element operating interface
// @tag.name					ne/info
// @tag.description			network element information interface
// @tag.name					ne/host
// @tag.description			network element host interface
// @tag.name					ne/license
// @tag.description			network element license interface
// @tag.name					ne/software
// @tag.description			network element software interface
// @tag.name					ne/version
// @tag.description			network element version interface
// @tag.name					ne/config
// @tag.description			network element config interface
//
// @tag.name					system
// @tag.description			system interface
// @tag.name					system/config
// @tag.description			system config interface
// @tag.name					system/dept
// @tag.description			system dept interface
// @tag.name					system/dict/data
// @tag.description			system dict data interface
// @tag.name					system/dict/type
// @tag.description			system dict type interface
// @tag.name					system/log/login
// @tag.description			system log login interface
// @tag.name					system/log/operate
// @tag.description			system log operate interface
// @tag.name					system/menu
// @tag.description			system menu interface
// @tag.name					system/post
// @tag.description			system post interface
// @tag.name					system/role
// @tag.description			system role interface
// @tag.name					system/user
// @tag.description			system user interface
// @tag.name					system/user/profile
// @tag.description			system user profile interface
//
// @tag.name					tool
// @tag.description			tool interface
// @tag.name					tool/ping
// @tag.description			tool ping interface
// @tag.name					tool/iperf
// @tag.description			tool iperf interface
//
// @tag.name					trace
// @tag.description			trace interface
// @tag.name					trace/tcpdump
// @tag.description			trace tcpdump interface
//
// @tag.name					ws
// @tag.description			ws interface
//
// @host						127.0.0.1:33040
// @BasePath					/
// @schemes					http https
//
// @securityDefinitions.apikey	TokenAuth
// @in							header
// @name						Authorization
// @description				Get the key through the common/authorization System Login, fill in content "Bearer <access_token>"
func main() {
	src.ConfigurationInit()

	app := src.AppEngine()
	src.DefeatConfig(app)

	loadGlobalPre(app)

	src.ModulesRoute(app)

	loadServerRoute(app)

	loadServerWeb()

	// 首次安装启动记录
	machine.Launch()
	wg.Wait()
}

// loadGlobalPre 全局预加载
func loadGlobalPre(app *gin.Engine) {
	// Swagger 接口文档
	if config.Env() == "local" {
		app.GET("/swagger/*any", ginSwagger.WrapHandler(swaggerFiles.Handler))
	}

	// Prometheus metrics
	metricsEnabled := config.Get("metrics")
	if parse.Boolean(metricsEnabled) {
		// Grafana Monitor 1
		m := ginmetrics.GetMonitor()
		m.UseWithoutExposingEndpoint(app)
		// Grafana Monitor 2
		app.Use(ginprom.PromMiddleware(nil))
		app.GET("/metrics", ginprom.PromHandler(promhttp.Handler()))
	}
	// 启用 pprof HTTP服务
	pprofAddr := fmt.Sprint(config.Get("pprofAddr"))
	if pprofAddr != "" && pprofAddr != "<nil>" {
		wg.Add(1)
		go func(addr string) {
			defer wg.Done()
			for i := range maxRetries {
				if err := http.ListenAndServe(addr, nil); err != nil {
					logger.Errorf("pprof run err:%v", err)
					time.Sleep(retryInterval) // 重试间隔时间
					logger.Warnf("trying to restart HTTP server on %s (Attempt %d)", addr, i)
				}
			}
		}(pprofAddr)
	}
}

// loadServerRoute 多个HTTP服务启动-API服务
func loadServerRoute(app *gin.Engine) {
	routeArr := config.Get("routeServer")
	if routeArr == nil {
		logger.Errorf("routeServer config not found")
		return
	}
	for _, v := range routeArr.([]any) {
		item := v.(map[string]any)
		addr := fmt.Sprint(item["addr"])
		if addr == "" || addr == "<nil>" {
			continue
		}
		schema := fmt.Sprint(item["schema"])
		if schema == "https" && schema != "<nil>" {
			certFile := fmt.Sprint(item["certfile"])
			keyFile := fmt.Sprint(item["keyfile"])
			if certFile == "" || certFile == "<nil>" || keyFile == "" || keyFile == "<nil>" {
				continue
			}
			// 启动HTTPS服务
			wg.Add(1)
			go func(addr string, certFile string, keyFile string) {
				defer wg.Done()
				for i := range maxRetries {
					if err := app.RunTLS(addr, certFile, keyFile); err != nil {
						logger.Errorf("routeServer run tls err:%v", err)
						time.Sleep(retryInterval) // 重试间隔时间
						logger.Warnf("trying to restart HTTPS server on %s (Attempt %d)", addr, i)
					}
				}
			}(addr, certFile, keyFile)
		} else {
			// 启动HTTP服务
			wg.Add(1)
			go func(addr string) {
				defer wg.Done()
				for i := range maxRetries {
					if err := app.Run(addr); err != nil {
						logger.Errorf("routeServer run err:%v", err)
						time.Sleep(retryInterval) // 重试间隔时间
						logger.Warnf("trying to restart HTTP server on %s (Attempt %d)", addr, i)
					}
				}
			}(addr)
		}
	}
}

// loadServerWeb 多个HTTP服务启动-前端静态资源
func loadServerWeb() {
	webEnabled := parse.Boolean(config.Get("webServer.enabled"))
	if !webEnabled {
		logger.Warnf("webServer config not found")
		return
	}
	rootDir := fmt.Sprint(config.Get("webServer.rootDir"))
	if rootDir == "" || rootDir == "<nil>" {
		logger.Warnf("webServer rootDir config not found")
		return
	}

	var web *gin.Engine = gin.New()
	gin.SetMode(gin.ReleaseMode)
	gin.DisableConsoleColor()
	web.Use(gin.Recovery())
	web.StaticFS("/", http.Dir(rootDir))
	// 多个HTTP服务启动
	listenArr := config.Get("webServer.listen")
	if listenArr == nil {
		logger.Errorf("webServer listen config not found")
		return
	}
	for _, v := range listenArr.([]any) {
		listen := v.(map[string]any)
		addr := fmt.Sprint(listen["addr"])
		if addr == "" || addr == "<nil>" {
			continue
		}
		schema := fmt.Sprint(listen["schema"])
		if schema == "https" && schema != "<nil>" {
			certFile := fmt.Sprint(listen["certfile"])
			keyFile := fmt.Sprint(listen["keyfile"])
			if certFile == "" || certFile == "<nil>" || keyFile == "" || keyFile == "<nil>" {
				continue
			}
			// 启动HTTPS服务
			wg.Add(1)
			go func(addr string, certFile string, keyFile string) {
				defer wg.Done()
				for i := range maxRetries {
					if err := web.RunTLS(addr, certFile, keyFile); err != nil {
						logger.Errorf("webServer run tls err:%v", err)
						time.Sleep(retryInterval) // 重试间隔时间
						logger.Warnf("trying to restart HTTPS server on %s (Attempt %d)", addr, i)
					}
				}
			}(addr, certFile, keyFile)
		} else {
			if addr == "" || addr == "<nil>" {
				continue
			}
			// 启动HTTP服务
			wg.Add(1)
			go func(addr string) {
				defer wg.Done()
				for i := range maxRetries {
					if err := web.Run(addr); err != nil {
						logger.Errorf("webServer run err:%v", err)
						time.Sleep(retryInterval) // 重试间隔时间
						logger.Warnf("trying to restart HTTP server on %s (Attempt %d)", addr, i)
					}
				}
			}(addr)
		}
	}
}
