package main

import (
	"context"
	"encoding/json"
	"flag"
	"fmt"
	"math/rand"
	"net"
	"net/http"
	_ "net/http/pprof"
	"os"
	"os/exec"
	"os/signal"
	"runtime"
	"syscall"
	"time"
	"virjar.com/majora-go/client"
	"virjar.com/majora-go/global"
	"virjar.com/majora-go/initialize"
	"virjar.com/majora-go/log"
	"virjar.com/majora-go/safe"
)

var (
	configure string
	daemon    bool
)

var (
	Version string
	Date    string
)

var (
	cmd *exec.Cmd
)

func init() {
	rand.Seed(time.Now().UnixNano())
	flag.StringVar(&configure, "conf", "", "./majora -c path/to/your/majora.ini")
	flag.BoolVar(&daemon, "daemon", false, "daemon")

	flag.Parse()
}

func initial() {
	if global.Config.PprofPort > 0 {
		safe.SageGo(func() {
			addr := fmt.Sprintf("127.0.0.1:%d", global.Config.PprofPort)
			log.Run().Infof("enable pprof: %s", addr)
			log.Run().Error(http.ListenAndServe(addr, nil))
		})
	}

	if len(global.Config.DNSServer) > 0 {
		net.DefaultResolver = &net.Resolver{
			PreferGo: true,
			Dial: func(ctx context.Context, network, address string) (net.Conn, error) {
				return net.Dial("udp", global.Config.DNSServer)
			},
		}
	}

	if daemon {
		var args []string
		for _, arg := range os.Args[1:] {
			if arg != "-daemon" {
				args = append(args, arg)
			}
		}
		cmd = exec.Command(os.Args[0], args...)
		cmd.Env = os.Environ()
		if err := cmd.Start(); err != nil {
			panic(err)
		}
		log.Run().Infof("%s [pid-%d] running...\n", os.Args[0], cmd.Process.Pid)
		os.Exit(0)
	}
}

func cli() {
	defer func() {
		if err := recover(); err != nil {
			log.Error().Errorf("cli panic %+v", err)
		}
	}()
	log.Run().Infof("cpu count %d proc %d", runtime.NumCPU(), runtime.NumCPU()*2)
	log.Run().Infof("current Version %s, build at %s", Version, Date)
	log.Run().Infof("hostInfo os:%s, arch:%s", runtime.GOOS, runtime.GOARCH)
	cfgInfo, _ := json.Marshal(global.Config)
	log.Run().Infof("config info:%s", string(cfgInfo))
	client.NewClientWithConf(global.Config).StartUp()
}

//main start
func main() {
	if len(os.Args) > 1 && os.Args[1] == "version" {
		fmt.Println(Version)
		os.Exit(0)
	}

	initialize.MustInitConfig(configure, global.Config)
	initialize.InitLogger()
	initial()
	cli()

	signalChan := make(chan os.Signal, 1)
	signal.Notify(signalChan, os.Interrupt, syscall.SIGHUP, syscall.SIGINT, syscall.SIGTERM, syscall.SIGQUIT)
	select {
	case <-signalChan:
		time.Sleep(time.Second * 3)
		log.Run().Warn("main process exit...")
	}
}
