package main

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

	_ "net/http/pprof"

	"github.com/chenjiandongx/ginprom"
	"github.com/gin-gonic/gin"
	"github.com/prometheus/client_golang/prometheus/promhttp"
	swaggerFiles "github.com/swaggo/files"
	ginSwagger "github.com/swaggo/gin-swagger"

	"be.ems/features"
	"be.ems/features/dbrest"
	"be.ems/features/event"
	"be.ems/features/fm"
	"be.ems/features/lm"
	"be.ems/features/mml"
	"be.ems/features/pm"
	featuresCfg "be.ems/lib/config"
	"be.ems/lib/dborm"
	"be.ems/lib/global"
	"be.ems/lib/log"
	"be.ems/lib/routes"
	"be.ems/src"
	"be.ems/src/framework/config"
	"be.ems/src/framework/logger"
	"be.ems/src/framework/middleware"
	"be.ems/src/framework/utils/parse"
	_ "be.ems/swagger2docs"
)

var wg sync.WaitGroup

// @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					network_data
// @tag.description			network data interface
// @tag.name					network_data/kpi
// @tag.description			network data kpi interface
// @tag.name					network_data/amf
// @tag.description			network data amf interface
// @tag.name					network_data/ims
// @tag.description			network data ims interface
// @tag.name					network_data/mme
// @tag.description			network data mme interface
// @tag.name					network_data/sgwc
// @tag.description			network data sgwc interface
// @tag.name					network_data/smf
// @tag.description			network data smf interface
// @tag.name					network_data/smsc
// @tag.description			network data smsc interface
// @tag.name					network_data/udm/auth
// @tag.description			network data udm authentication interface
// @tag.name					network_data/udm/sub
// @tag.description			network data udm subscriber interface
// @tag.name					network_data/upf
// @tag.description			network data upf interface
//
// @tag.name					network_element
// @tag.description			network element interface
// @tag.name					network_element/action
// @tag.description			network element operating interface
// @tag.name					network_element/info
// @tag.description			network element information interface
// @tag.name					network_element/host
// @tag.description			network element host interface
// @tag.name					network_element/license
// @tag.description			network element license interface
// @tag.name					network_element/software
// @tag.description			network element software interface
// @tag.name					network_element/version
// @tag.description			network element version interface
// @tag.name					network_element/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()

	loadFeatures(app)

	loadDev(app)

	loadServer(app)

	loadWebServer()

	wg.Wait()
}

// loadFeatures mux路由模块
func loadFeatures(app *gin.Engine) {
	conf := featuresCfg.GetYamlConfig()

	log.InitLogger(conf.Logger.File, conf.Logger.Duration, conf.Logger.Count, "omc:restagent", featuresCfg.GetLogLevel())
	fmt.Printf("OMC restagent version: %s\n", global.Version)
	log.Infof("========================= OMC restagent startup =========================")
	log.Infof("OMC restagent version: %s %s %s", global.Version, global.BuildTime, global.GoVer)

	err := dborm.InitDbClient(conf.Database.Type, conf.Database.User, conf.Database.Password,
		conf.Database.Host, conf.Database.Port, conf.Database.Name, conf.Database.ConnParam)
	if err != nil {
		fmt.Println("dborm.initDbClient err:", err)
		os.Exit(4)
	}
	err = dborm.InitGormConnect(conf.Database.Type, conf.Database.User, conf.Database.Password,
		conf.Database.Host, conf.Database.Port, conf.Database.Name, conf.Database.ConnParam, true)
	if err != nil {
		fmt.Println("dborm.InitGormConnect err:", err)
		os.Exit(4)
	}
	err = fm.InitDbClient(conf.Database.Type, conf.Database.User, conf.Database.Password,
		conf.Database.Host, conf.Database.Port, conf.Database.Name, conf.Database.ConnParam)
	if err != nil {
		fmt.Println("dborm.initDbClient err:", err)
		os.Exit(4)
	}
	err = pm.InitDbClient(conf.Database.Type, conf.Database.User, conf.Database.Password,
		conf.Database.Host, conf.Database.Port, conf.Database.Name, conf.Database.ConnParam)
	if err != nil {
		fmt.Println("dborm.initDbClient err:", err)
		os.Exit(4)
	}
	err = dbrest.InitDbClient(conf.Database.Type, conf.Database.User, conf.Database.Password,
		conf.Database.Host, conf.Database.Port, conf.Database.Name, conf.Database.ConnParam)
	if err != nil {
		fmt.Println("dbrest.initDbClient err:", err)
		os.Exit(4)
	}
	err = lm.InitDbClient(conf.Database.Type, conf.Database.User, conf.Database.Password,
		conf.Database.Host, conf.Database.Port, conf.Database.Name, conf.Database.ConnParam)
	if err != nil {
		fmt.Println("lm.initDbClient err:", err)
		os.Exit(4)
	}

	mml.InitMML()

	// 将 mux.Router 注册到 gin.Engine

	// 默认路由组
	defaultUriGroup := app.Group(featuresCfg.DefaultUriPrefix)
	defaultUriGroup.Use(middleware.PreAuthorize(nil))
	defaultUriGroup.Any("/*any", gin.WrapH(routes.NewRouter()))
	// 可配置前缀路由组
	uriGroup := app.Group(featuresCfg.UriPrefix)
	uriGroup.Any("/*any", gin.WrapH(routes.NewRouter()))
	// AMF上报的UE事件, 无前缀，暂时特殊处理
	app.POST(event.UriUEEventAMF, event.PostUEEventFromAMF)

	// register feature service gin.Engine
	features.InitServiceEngine(app)
}

// loadDev 开发环境调试
func loadDev(app *gin.Engine) {
	// Swagger 接口文档
	if config.Env() == "local" {
		app.GET("/swagger/*any", ginSwagger.WrapHandler(swaggerFiles.Handler))
	}

	//性能分析监控 Prometheus
	pprofEnabled := config.Get("pprof.enabled")
	if pprofEnabled != nil && pprofEnabled.(bool) {
		app.Use(ginprom.PromMiddleware(nil))
		app.GET("/metrics", ginprom.PromHandler(promhttp.Handler()))
		pprofAddr := config.Get("pprof.addr").(string)
		wg.Add(1)
		// 启用pprof HTTP服务
		go func(addr string) {
			defer wg.Done()
			fmt.Println(http.ListenAndServe(addr, nil))
		}(pprofAddr)
	}
}

// loadServer 多个HTTP服务启动
func loadServer(app *gin.Engine) {
	httpArr := config.Get("rest")
	if httpArr == nil {
		logger.Errorf("rest config not found")
		return
	}
	for _, v := range httpArr.([]any) {
		rest := v.(map[string]any)
		port := parse.Number(rest["port"])
		ipv4 := fmt.Sprint(rest["ipv4"])
		ipv6 := fmt.Sprint(rest["ipv6"])
		schema := fmt.Sprint(rest["schema"])
		if schema == "https" && schema != "<nil>" {
			certFile := fmt.Sprint(rest["certfile"])
			keyFile := fmt.Sprint(rest["keyfile"])
			addr := ""
			if ipv4 != "" && ipv4 != "<nil>" {
				addr = fmt.Sprintf("%s:%d", ipv4, port)
			}
			if ipv6 != "" && ipv6 != "<nil>" {
				addr = fmt.Sprintf("[%s]:%d", ipv6, port)
			}
			if addr == "" {
				continue
			}
			// 启动HTTPS服务
			wg.Add(1)
			go func(addr string, certFile string, keyFile string) {
				defer wg.Done()
				err := app.RunTLS(addr, certFile, keyFile)
				logger.Errorf("run tls err:%v", err)
			}(addr, certFile, keyFile)
		} else {
			addr := ""
			if ipv4 != "" && ipv4 != "<nil>" {
				addr = fmt.Sprintf("%s:%d", ipv4, port)
			}
			if ipv6 != "" && ipv6 != "<nil>" {
				addr = fmt.Sprintf("[%s]:%d", ipv6, port)
			}
			if addr == "" {
				continue
			}
			// 启动HTTP服务
			wg.Add(1)
			go func(addr string) {
				defer wg.Done()
				err := app.Run(addr)
				logger.Errorf("run err:%v", err)
			}(addr)
		}
	}
}

// loadWebServer 前端静态资源服务
func loadWebServer() {
	webEnabled := config.Get("webServer.enabled")
	if webEnabled == nil {
		logger.Errorf("webServer config not found")
		return
	}
	if webEnabled.(bool) {
		rootDir := config.Get("webServer.rootDir").(string)
		if rootDir != "" {
			var web *gin.Engine
			gin.SetMode(gin.ReleaseMode)
			web = gin.New()
			web.Use(gin.Recovery())
			gin.DisableConsoleColor()
			web.StaticFS("/", http.Dir(rootDir))
			// 多个HTTP服务启动
			listenArr := config.Get("webServer.listen")
			for _, v := range listenArr.([]any) {
				listen := v.(map[string]any)
				addr := fmt.Sprint(listen["addr"])
				schema := fmt.Sprint(listen["schema"])
				if schema == "https" && schema != "<nil>" {
					certFile := fmt.Sprint(listen["certfile"])
					keyFile := fmt.Sprint(listen["keyfile"])
					if addr == "" || addr == "<nil>" {
						continue
					}
					// 启动HTTPS服务
					wg.Add(1)
					go func(addr string, certFile string, keyFile string) {
						defer wg.Done()
						err := web.RunTLS(addr, certFile, keyFile)
						logger.Errorf("web run tls err:%v", err)
					}(addr, certFile, keyFile)
				} else {
					if addr == "" || addr == "<nil>" {
						continue
					}
					// 启动HTTP服务
					wg.Add(1)
					go func(addr string) {
						defer wg.Done()
						err := web.Run(addr)
						logger.Errorf("web run err:%v", err)
					}(addr)
				}
			}
		}
	}
}
