package start

import (
	"dilu/common/codes"
	"dilu/common/config"
	"dilu/common/middleware"
	"dilu/common/utils"
	"fmt"
	"time"

	coreCfg "github.com/baowk/dilu-core/config"

	"github.com/baowk/dilu-core/core"
	"github.com/baowk/dilu-core/core/i18n"

	"github.com/fsnotify/fsnotify"
	"github.com/spf13/cobra"
	"github.com/spf13/viper"
	_ "github.com/spf13/viper/remote"
)

var (
	configYml string
	syncApi   bool
	StartCmd  = &cobra.Command{
		Use:     "start",
		Short:   "Get Application config info",
		Example: "dilu start -c resources/config.dev.yml",
		Run: func(cmd *cobra.Command, args []string) {
			run()
		},
	}
)

func init() {
	StartCmd.PersistentFlags().StringVarP(&configYml, "config", "c", "resources/config.dev.yaml", "Start server with provided configuration file")
	StartCmd.PersistentFlags().BoolVarP(&syncApi, "api", "a", false, "Start server with sync api")
}

func run() {
	if configYml == "" {
		panic("找不到配置文件")
	}
	v := viper.New()
	v.SetConfigFile(configYml)
	//v.SetConfigType("yaml")
	err := v.ReadInConfig()
	if err != nil {
		panic(fmt.Sprintf("Fatal error config file: %v \n", err))
	}

	var cfg coreCfg.AppCfg

	if err = v.Unmarshal(&cfg); err != nil {
		fmt.Println(err)
	}

	if cfg.Server.RemoteEnable {
		rviper := viper.New()
		if cfg.Remote.SecretKeyring == "" {
			err = rviper.AddRemoteProvider(cfg.Remote.Provider, cfg.Remote.Endpoint, cfg.Remote.Path)
		} else {
			err = rviper.AddSecureRemoteProvider(cfg.Remote.Provider, cfg.Remote.Endpoint, cfg.Remote.Path, cfg.Remote.SecretKeyring)
		}
		if err != nil {
			panic(fmt.Sprintf("Fatal error remote config : %v \n", err))
		}
		rviper.SetConfigType(cfg.Remote.GetConfigType())
		err = rviper.ReadRemoteConfig()
		if err != nil {
			panic(fmt.Sprintf("Fatal error remote config : %v \n", err))
		}
		var remoteCfg coreCfg.AppCfg
		rviper.Unmarshal(&remoteCfg)

		mergeCfg(&cfg, &remoteCfg)

		extend := rviper.Sub("extend")
		if extend != nil {
			extend.Unmarshal(config.Ext)
		}
		go func() {
			for {
				time.Sleep(time.Second * 5) // delay after each request
				err := rviper.WatchRemoteConfig()
				if err != nil {
					fmt.Println(err)
					continue
				}
				rviper.Unmarshal(&remoteCfg)

				mergeCfg(&cfg, &remoteCfg)

				extend := rviper.Sub("extend")
				if extend != nil {
					extend.Unmarshal(config.Ext)
				}
			}
		}()
	} else {
		mergeCfg(&cfg, nil)
		v.Sub("extend").Unmarshal(config.Ext)
		v.WatchConfig()
		v.OnConfigChange(func(e fsnotify.Event) {
			fmt.Println("config file changed:", e.String())
			if err = v.Unmarshal(&cfg); err != nil {
				fmt.Println(err)
			}
			mergeCfg(&cfg, nil)
			extend := v.Sub("extend")
			if extend != nil {
				extend.Unmarshal(config.Ext)
			}
		})
	}

	core.Init()

	i18n.Register(&codes.Code{
		EnableI18N: core.Cfg.Server.I18n,
		Lang:       core.Cfg.Server.Lang,
	})

	//初始化gin
	r := core.GetGinEngine()

	middleware.InitMiddleware(r, &core.Cfg)

	//初始化路由
	for _, f := range AppRouters {
		f()
	}

	go func() { //主服务启动后回调
		<-core.Started
		startedInit()
		if syncApi {
			syncApiFn(r)
		}
	}()

	go func() { //服务关闭释放资源
		<-core.ToClose
		toClose()

	}()
	core.Run()

	core.Log.Info("Server exited")
}

func mergeCfg(local, remote *coreCfg.AppCfg) {
	if remote != nil {
		core.Cfg = *local
		core.Cfg = *remote
		core.Cfg.Server.Mode = local.Server.Mode
		core.Cfg.Server.RemoteEnable = local.Server.RemoteEnable
		core.Cfg.Remote = local.Remote
		core.Cfg.Server.Name = local.Server.Name
		core.Cfg.Server.Port = local.Server.Port
		core.Cfg.Server.Host = local.Server.Host
		core.Cfg.Server.Node = local.Server.Node
	} else {
		core.Cfg = *local
	}
}

// 服务启动后要初始化的资源
func startedInit() {
	if core.Cfg.GrpcServer.Enable {
		grpcInit()
	}
	rdInit()
	utils.Setup(core.Cfg.Server.Node)
	core.Log.Debug("服务启动，初始化执行完成")
}

// 服务关闭要释放的资源
func toClose() {
	if core.Cfg.GrpcServer.Enable {
		closeGrpc()
	}
	rdRelease()
	core.Log.Debug("服务关闭需要释放的资源")
}
