package main

import (
	"fmt"
	"github.com/TeaOSLab/EdgeAdmin/internal/apps"
	"github.com/TeaOSLab/EdgeAdmin/internal/configs"
	teaconst "github.com/TeaOSLab/EdgeAdmin/internal/const"
	"github.com/TeaOSLab/EdgeAdmin/internal/gen"
	"github.com/TeaOSLab/EdgeAdmin/internal/nodes"
	"github.com/TeaOSLab/EdgeAdmin/internal/utils"
	_ "github.com/TeaOSLab/EdgeAdmin/internal/web"
	_ "github.com/iwind/TeaGo/bootstrap"
	"github.com/iwind/TeaGo/maps"
	"github.com/iwind/gosock/pkg/gosock"
	"log"
	"time"
)

func main() {
	var app = apps.NewAppCmd().
		Version(teaconst.Version).
		Product(teaconst.ProductName).
		Usage(teaconst.ProcessName+" [-v|start|stop|restart|service|daemon|reset|recover|demo|upgrade]").
		Usage(teaconst.ProcessName+" [dev|prod]").
		Option("-h", "show this help").
		Option("-v", "show version").
		Option("start", "start the service").
		Option("stop", "stop the service").
		Option("restart", "restart the service").
		Option("service", "register service into systemd").
		Option("daemon", "start the service with daemon").
		Option("reset", "reset configs").
		Option("recover", "enter recovery mode").
		Option("demo", "switch to demo mode").
		Option("dev", "switch to 'dev' mode").
		Option("prod", "switch to 'prod' mode").
		Option("upgrade", "upgrade from official site")

	app.On("daemon", func() {
		nodes.NewAdminNode().Daemon()
	})
	app.On("service", func() {
		err := nodes.NewAdminNode().InstallSystemService()
		if err != nil {
			fmt.Println("[ERROR]install failed: " + err.Error())
			return
		}
		fmt.Println("done")
	})
	app.On("reset", func() {
		err := configs.ResetAPIConfig()
		if err != nil {
			fmt.Println("[ERROR]reset failed: " + err.Error())
			return
		}
		fmt.Println("done")
	})
	app.On("recover", func() {
		sock := gosock.NewTmpSock(teaconst.ProcessName)
		if !sock.IsListening() {
			fmt.Println("[ERROR]the service not started yet, you should start the service first")
			return
		}
		_, err := sock.Send(&gosock.Command{Code: "recover"})
		if err != nil {
			fmt.Println("[ERROR]enter recovery mode failed: " + err.Error())
			return
		}
		fmt.Println("enter recovery mode successfully")
	})
	app.On("demo", func() {
		sock := gosock.NewTmpSock(teaconst.ProcessName)
		if !sock.IsListening() {
			fmt.Println("[ERROR]the service not started yet, you should start the service first")
			return
		}
		reply, err := sock.Send(&gosock.Command{Code: "demo"})
		if err != nil {
			fmt.Println("[ERROR]change demo mode failed: " + err.Error())
			return
		}
		var isDemo = maps.NewMap(reply.Params).GetBool("isDemo")
		if isDemo {
			fmt.Println("change demo mode to: on")
		} else {
			fmt.Println("change demo mode to: off")
		}
	})
	app.On("generate", func() {
		err := gen.Generate()
		if err != nil {
			fmt.Println("generate failed: " + err.Error())
			return
		}
	})
	app.On("dev", func() {
		var env = "dev"
		var sock = gosock.NewTmpSock(teaconst.ProcessName)
		_, err := sock.Send(&gosock.Command{
			Code:   env,
			Params: nil,
		})
		if err != nil {
			fmt.Println("failed to switch to '" + env + "': " + err.Error())
		} else {
			fmt.Println("switch to '" + env + "' ok")
		}
	})
	app.On("prod", func() {
		var env = "prod"
		var sock = gosock.NewTmpSock(teaconst.ProcessName)
		_, err := sock.Send(&gosock.Command{
			Code:   env,
			Params: nil,
		})
		if err != nil {
			fmt.Println("failed to switch to '" + env + "': " + err.Error())
		} else {
			fmt.Println("switch to '" + env + "' ok")
		}
	})
	app.On("upgrade", func() {
		var manager = utils.NewUpgradeManager("admin")
		log.Println("checking latest version ...")
		var ticker = time.NewTicker(1 * time.Second)
		go func() {
			var lastProgress float32 = 0
			var isStarted = false
			for range ticker.C {
				if manager.IsDownloading() {
					if !isStarted {
						log.Println("start downloading v" + manager.NewVersion() + " ...")
						isStarted = true
					}
					var progress = manager.Progress()
					if progress >= 0 {
						if progress == 0 || progress == 1 || progress-lastProgress >= 0.1 {
							lastProgress = progress
							log.Println(fmt.Sprintf("%.2f%%", manager.Progress()*100))
						}
					}
				} else {
					break
				}
			}
		}()
		err := manager.Start()
		if err != nil {
			log.Println("upgrade failed: " + err.Error())
			return
		}
		log.Println("finished!")
		log.Println("restarting ...")
		app.RunRestart()
	})
	app.Run(func() {
		var adminNode = nodes.NewAdminNode()
		adminNode.Run()
	})
}
