package api

import (
	"cold-delivery/app/admin/model"
	"cold-delivery/app/jobs"
	"cold-delivery/common/file_store"
	global2 "cold-delivery/common/global"
	"cold-delivery/common/middleware"
	"cold-delivery/common/middleware/handler"
	"cold-delivery/common/nats"
	"cold-delivery/common/storage"
	"context"
	"fmt"
	"log"
	"net/http"
	"os"
	"os/signal"
	"time"

	"github.com/gin-gonic/gin"
	"github.com/spf13/cobra"
	"gogs.baozhida.cn/zoie/OAuth-core/api"
	"gogs.baozhida.cn/zoie/OAuth-core/config/source/file"
	"gogs.baozhida.cn/zoie/OAuth-core/pkg"
	"gogs.baozhida.cn/zoie/OAuth-core/runtime"
	"gogs.baozhida.cn/zoie/OAuth-core/sdk"
	"gogs.baozhida.cn/zoie/OAuth-core/sdk/config"

	"cold-delivery/app/admin/router"
	ext "cold-delivery/conf"
	database "cold-delivery/db"
)

var (
	configYml string
	StartCmd  = &cobra.Command{
		Use:          "server",
		Short:        "Start API server",
		Example:      "cold-delivery server -c conf/settings.yml",
		SilenceUsage: true,
		PreRun: func(cmd *cobra.Command, args []string) {
			setup()
		},
		RunE: func(cmd *cobra.Command, args []string) error {
			return run()
		},
	}
)

var AppRouters = make([]func(), 0)

func init() {
	StartCmd.PersistentFlags().StringVarP(&configYml, "config", "c", "config/settings.yml", "Start server with provided configuration file")

	//注册路由
	AppRouters = append(AppRouters, router.InitRouter)
}

func setup() {
	// 注入配置扩展项
	config.ExtendConfig = &ext.ExtConfig
	//1. 读取配置
	config.Setup(
		file.NewSource(file.WithPath(configYml)),
		database.Setup,
		storage.Setup,
		file_store.QiniuSetup,
		nats.Setup,
	)
	database.AutoMigrateDB()
	database.AutoSeedMenus() // 初始化菜单数据
	//注册监听函数
	queue := sdk.Runtime.GetMemoryQueue("")
	queue.Register(global2.LoginLog, model.SaveLoginLog)
	queue.Register(global2.OperateLog, model.SaveOperaLog)
	//queue.Register(global2.ApiCheck, model.SaveSysApi)
	go queue.Run()

	usageStr := `starting api server...`
	log.Println(usageStr)
}

func run() error {
	if config.ApplicationConfig.Mode == pkg.ModeProd.String() {
		gin.SetMode(gin.ReleaseMode)
	}
	initRouter()

	for _, f := range AppRouters {
		f()
	}

	srv := &http.Server{
		Addr:    fmt.Sprintf("%s:%d", config.ApplicationConfig.Host, config.ApplicationConfig.Port),
		Handler: sdk.Runtime.GetEngine(),
	}

	// fixme 新加的服务在这里配置
	//go func() {
	//	otherSvc.InitJob()
	//	otherSvc.Setup(sdk.Runtime.GetDb())
	//
	//}()

	// fixme 定时任务，需要时再配置
	go func() {
		jobs.InitJob()
		jobs.Setup(sdk.Runtime.GetDb())
	}()

	go func() {
		// 服务连接
		if config.SslConfig.Enable {
			if err := srv.ListenAndServeTLS(config.SslConfig.Pem, config.SslConfig.KeyStr); err != nil && err != http.ErrServerClosed {
				log.Fatal("listen: ", err)
			}
		} else {
			if err := srv.ListenAndServe(); err != nil && err != http.ErrServerClosed {
				log.Fatal("listen: ", err)
			}
		}
	}()

	//go func() {
	//	InitService()
	//}()

	tip()
	fmt.Println(pkg.Green("Server run at:"))
	fmt.Printf("-  Local:   http://localhost:%d/ \r\n", config.ApplicationConfig.Port)
	fmt.Printf("-  Network: http://%s:%d/ \r\n", pkg.GetLocalHost(), config.ApplicationConfig.Port)
	fmt.Println(pkg.Green("Swagger run at:"))
	fmt.Printf("-  Local:   http://localhost:%d/swagger/index.html \r\n", config.ApplicationConfig.Port)
	fmt.Printf("-  Network: http://%s:%d/swagger/index.html \r\n", pkg.GetLocalHost(), config.ApplicationConfig.Port)
	fmt.Printf("%s Enter Control + C Shutdown Server \r\n", pkg.GetCurrentTimeStr())
	// 等待中断信号以优雅地关闭服务器（设置 5 秒的超时时间）
	quit := make(chan os.Signal)
	signal.Notify(quit, os.Interrupt)
	<-quit

	ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
	defer cancel()

	fmt.Printf("%s Shutdown Server ... \r\n", pkg.GetCurrentTimeStr())

	if err := srv.Shutdown(ctx); err != nil {
		log.Fatal("Server Shutdown:", err)
	}
	log.Println("Server exiting")

	return nil
}

var Router runtime.Router

func tip() {
	usageStr := `欢迎使用 ` + pkg.Green(`OAuth `+global2.Version) + ` 可以使用 ` + pkg.Red(`-h`) + ` 查看命令`
	fmt.Printf("%s \n\n", usageStr)
}

func initRouter() {
	var r *gin.Engine
	h := sdk.Runtime.GetEngine()
	if h == nil {
		h = gin.New()
		sdk.Runtime.SetEngine(h)
	}
	switch h.(type) {
	case *gin.Engine:
		r = h.(*gin.Engine)
	default:
		log.Fatal("not support other engine")
		os.Exit(-1)
	}
	if config.SslConfig.Enable {
		r.Use(handler.TlsHandler())
	}
	r.Use(middleware.Sentinel()).
		Use(middleware.RequestId(pkg.TrafficKey)).
		Use(api.SetRequestLogger)

	middleware.InitMiddleware(r)

}
