package nt

import (
	"encoding/json"
	"fmt"
	"path"
	"strconv"
	"time"

	"../conf"
	"../log"
	mac "../mach"
	"../mq"
	"../rds"
	"../utils"
	"../zkeeper"
	"github.com/go-redis/redis"
	"go.uber.org/zap/zapcore"
)

// 通用数据，初始化过程
const (
	//
	DEF_MIN_GUID       = 100000
	DEF_MAX_NET_BUFFER = 4096 // 网络缓冲区大小
)

var (
	NAME     string                              // 进程名称
	VERSION  string                              // 版本
	BootTime time.Time                           // 启动时间
	InstName string                              // 实例名称
	InstConf *conf.Conf                          // 配置对象
	Mac      *mac.MachMeta     = &mac.MachMeta{} // 硬件信息
	Log      *log.SLogger                        // 日志
	Zk       *zkeeper.ZkClient                   // zookeeper
	Rdb      *redis.Client                       // redis
	Mq       *mq.Mq                              // msg queue
	Wp       *utils.WorkPool
	ZkP      *ZkPaths

	//logger level 映射
	LogLevelMap = map[int]zapcore.Level{
		1: zapcore.DebugLevel,
		2: zapcore.InfoLevel,
		3: zapcore.WarnLevel,
		4: zapcore.ErrorLevel,
		5: zapcore.DPanicLevel,
		6: zapcore.PanicLevel,
		7: zapcore.FatalLevel,
	}
)

// 进程初始化
//@name: 进程名称
//@ver: 版本
//@cf: 配置文件名
//@cb: zookeeper 若有监控的回调函数
func InstInit(name, ver, cf string) error {
	// 初始化基本值
	NAME = name
	VERSION = ver

	// 加载配置
	var err error
	InstConf, err = conf.LoadConf(cf)
	utils.ErrPanic(err)
	// 实例名称
	InstName = NAME + "-" + strconv.FormatUint(InstConf.Id, 10)
	// zk 路径
	ZkP = GetZkPaths(InstConf.Namespace)

	// 连接 zookeeper
	Zk, err = zkeeper.NewZkClient(InstConf.Zoo.Hosts, ZkP.Root, InstConf.Zoo.Username, InstConf.Zoo.Password, 5, OnZkNotify)
	utils.ErrPanic(err)

	// 获取 redis 地址参数
	data, err := Zk.GetNodeData(ZkP.Redis)
	utils.ErrPanic(err)

	Rdb, err = rds.ConnectRedis(data)
	utils.ErrPanic(err)

	// 连接消息队列
	mqs, err := Zk.GetNodeData(ZkP.Mq)
	utils.ErrPanic(err)
	mqconf := &ZkMqConf{}
	err = json.Unmarshal(mqs, mqconf)
	utils.ErrPanic(err)
	Mq, err = mq.NewMq(mqconf.Addrs, mqconf.Username, mqconf.Password, mqconf.ClusterId, InstName)
	utils.ErrPanic(err)

	// 初始化日志
	log_path := strconv.FormatUint(InstConf.Id, 10) + ".log"
	if len(InstConf.LogPath) > 0 {
		b, err := utils.PathExists(InstConf.LogPath)
		if err != nil || !b {
			utils.ErrPanic(utils.ErrNotExists)
		}
		log_path = path.Join(InstConf.LogPath, log_path)
	}
	log_level, ok := LogLevelMap[InstConf.Level]

	if !ok {
		log_level = zapcore.WarnLevel
	}
	console := true
	if InstConf.Mode == "release" {
		console = false
	}
	utils.UnUsed(console) // 当前 supervisor 方式都输出到控制台
	//
	mqsink := NewMqSink(InstName)
	Log = log.NewSLogger(true, log_path, log_level, mqsink)
	log.SetDefaultLogger(Log)
	
	//
	Wp = utils.NewWorkPool(1024)
	return nil
}

// 打印系统信息
func PrintInstInfo(m *mac.MachMeta) {
	mac.GetMachInfo(m)

	fmt.Println("************* System Info *************")
	fmt.Println("Instance Name:", InstName, "-", VERSION)
	fmt.Println("Instance Boot:", BootTime.Format("2006-01-02 15:04:05"))
	fmt.Println("System Boot:", time.Unix(int64(m.BootTime), 0).Format("2006-01-02 15:04:05"))
	fmt.Println("Hostname:", m.Hostname)
	fmt.Println("OS:", m.OS)
	fmt.Println("Arch:", m.Arch)
	fmt.Println("Platform:", m.Platform)
	fmt.Println("Kernel Version:", m.KernelVer)
	fmt.Println("CPU Num:", m.CpuNum)
	fmt.Println("CPU Core Num:", m.CpuCoreNum)
	fmt.Println("CPU Model Name:", m.CpuModelName)
	fmt.Printf("CPU Core CpuPercent:")
	for _, p := range m.CpuPercent {
		fmt.Printf("%3.1f%%  ", p)
	}
	fmt.Print("\n")
	fmt.Printf("Mem Total:%vG\n", m.MemTotal/1024/1024/1024)
	fmt.Printf("Mem Used:%vG\n", m.MemUsed/1024/1024/1024)
	fmt.Printf("Mem Available:%vG\n", m.MemAvailable/1024/1024/1024)
	fmt.Printf("Mem Percent:%v%%\n", m.MemPercent)
}

// @path: 必须为完整路径
func RegisterNodeCallback(path string, cb CallbackPath) error {
	MapPathCb[path] = cb
	return Zk.WatchNode(path)
}

// @path: 必须为完整路径
func RegisterChildrenCallback(path string, cb CallbackPath) error {
	MapPathCb[path] = cb
	return Zk.WatchChildren(path)
}
