package nt

import (
	"../conf"
	pb "../protos"
	"../utils"
	"encoding/json"
	"github.com/coheneye/go-simplejson"
	"github.com/pkg/errors"
	"go.uber.org/zap"
	"sync"
)

/// 加载所有需要加载的数据， 变化自动更新

// 这不是通用的函数， init 模块一定理解业务

var (
	DynConf *allConfT = &allConfT{
		muVip:           sync.Mutex{},
		muLobbies:       sync.Mutex{},

		muGames:         sync.Mutex{},
		muChannels:      sync.Mutex{},

		ClientAddrsConf: &pb.S_Ntf_Config{},
		muClientAddrs:   sync.Mutex{},

		Notices:         make(map[int32]*pb.Notice),
		muNotices:       sync.Mutex{},

		Kv:              make(map[string]interface{}),
		muKv:            sync.Mutex{},

		Wallet:          new(walletConf),
		muWallet:        sync.Mutex{},

		muCheckin7:      sync.Mutex{},
		muGameTasks:     sync.Mutex{},
		cacheIdItem:     make(map[int64][]*pb.GameItemEntry),
	}

	errNoZkData = errors.New("no data in zookeeper")
)

func (self *allConfT) MonitorVip() error {
	_, err := self.ReloadVipConf()
	if nil != err {
		return err
	}

	return Zk.WatchNode(ZkP.Vip)
}

func (self *allConfT) MonitorLobbies() error {
	_, err := self.ReloadLobbiesConf()
	if err != nil {
		return err
	}
	return Zk.WatchChildren(ZkP.Lobbies)
}

func (self *allConfT) MonitorGames() error {
	_, err := self.ReloadGamesConf()
	if err != nil {
		return err
	}
	return Zk.WatchNode(ZkP.Games)
}

func (self *allConfT) MonitorChannels() error {
	_, err := self.ReloadChannelsConf()
	if nil != err {
		return err
	}
	return Zk.WatchNode(ZkP.Channels)
}

func (self *allConfT) MonitorKv() error {
	err := self.ReloadKvConf()
	if err != nil {
		return err
	}
	return Zk.WatchNode(ZkP.Kv)
}

func (self *allConfT) MonitorClientAddrs() error {
	err := self.ReloadClientAddrs()
	if err != nil {
		return err
	}
	return Zk.WatchNode(ZkP.ClientAddrs)
}

func (self *allConfT) MonitorWallet() error {
	err := self.ReloadWalletConf()
	if nil != err {
		return err
	}

	return Zk.WatchNode(ZkP.Wallet)
}

func (self *allConfT) MonitorCheckin7() error {
	err := self.ReloadCheckin7()
	if nil != err {
		return err
	}

	return Zk.WatchNode(ZkP.Checkin7)
}

func (self *allConfT) MonitorGameTasks() error {
	_, err := self.ReloadGameTasksConf()
	if err != nil {
		return err
	}
	return Zk.WatchNode(ZkP.GameTask)
}

func (self *allConfT) MonitorTurntable() error {
	_, err := self.ReloadTurntableConf()
	if err != nil {
		return err
	}
	return Zk.WatchNode(ZkP.Turntable)
}

///TODO: games, channels, clientaddrs 全部转变为此处的加载方式
func (self *allConfT) ReloadVipConf() ([]*pb.VipConfItem, error) {
	//load
	data, err := Zk.GetNodeData(ZkP.Vip)
	if nil != err {
		return nil, err
	}

	var vips []*pb.VipConfItem
	err = json.Unmarshal([]byte(data), &vips)
	if nil != err {
		return nil, err
	}

	self.muVip.Lock()
	self.Vip = vips
	self.muVip.Unlock()

	return vips, nil
}

// 获取所有 大厅 配置信息
// 不传输 zookeeper 地址参数，默认在同一个进程中
// 并且 zookeeper 已连接
func (self *allConfT) ReloadLobbiesConf() (map[string]*conf.Conf, error) {
	children, err := Zk.GetChildren(ZkP.Lobbies)
	if nil != err {
		return nil, err
	}
	// 返回值
	mr := make(map[string]*conf.Conf)

	for _, child := range children {
		child_path := ZkP.Lobbies + "/" + child
		bytes, err := Zk.GetNodeData(child_path)
		if err != nil {
			Log.Warn("zk children error", zap.String("name", child_path), zap.Error(err))
		}
		child_conf_json := &conf.Conf{}
		err = json.Unmarshal(bytes, &child_conf_json)
		if nil != err {
			Log.Warn("zk child json", zap.String("name", child_path), zap.Error(err))
		}
		mr[child] = child_conf_json
	}

	self.muLobbies.Lock()
	self.Lobbies = mr
	self.muLobbies.Unlock()

	return mr, nil
}

//获取所有游戏列表的参数配置
func (self *allConfT) ReloadGamesConf() ([]*pb.GameItemEntry, error) {
	//load
	data, err := Zk.GetNodeData(ZkP.Games)
	if nil != err {
		return nil, err
	}

	type gameItem struct {
		Name          string
		Channel_id    int64
		Game_id       int64
		Is_start      int32
		Is_top        int
		Order         int32
		Icon          string
		Icon_size     int32
		Lately_icon string
		Lately_icon_size int32
		Hot_icon      string
		Hot_icon_size int32
		Limit_coin    int64
		Limit_bet     int64
		Limit_people  int
		Is_game       bool
		Is_show 		int32
		Channel       int64
		Game_param    []string
		View_type	  int32
	}

	type gameItemHeader struct {
		Cmd    string
		Params []gameItem
	}

	var item gameItemHeader
	err = json.Unmarshal([]byte(data), &item)
	if nil != err {
		return nil, err
	}

	var games []*pb.GameItemEntry
	var isGame int32 = 0
	for i := 0; i < len(item.Params); i++ {
		var p = item.Params[i]
		if p.Is_game {
			isGame = 1
		} else {
			isGame = 0
		}
		obj := &pb.GameItemEntry{
			Id:        p.Game_id,
			Order:     p.Order,
			GameMaker: p.Channel,
			GameParam: p.Game_param,
			ParentId:  p.Channel_id,
			Name:      p.Name,
			Enabled:   p.Is_start,
			MinLimit:  p.Limit_coin, //至少50元入场限制
			Orientation: p.View_type,
			IsGame:    isGame,
			Status: 	p.Is_show + 1, // 转换 0 - 1 到  1 - 2
		}
		obj.Icons = append(obj.Icons, &pb.Icon{
			Name: p.Icon,
			Size: p.Icon_size,
		})
		obj.Icons = append(obj.Icons, &pb.Icon{})
		obj.Icons = append(obj.Icons, &pb.Icon{})
		obj.Icons = append(obj.Icons, &pb.Icon{
			Name: p.Hot_icon,
			Size: p.Hot_icon_size,
		})
		obj.Icons = append(obj.Icons, &pb.Icon{
			Name: p.Lately_icon,
			Size: p.Lately_icon_size,
		})
		games = append(games, obj)
	}
	self.muGames.Lock()
	self.cacheIdItem = make(map[int64][]*pb.GameItemEntry)
	self.Games = games
	self.muGames.Unlock()

	return games, nil
}

func (self *allConfT) ReloadChannelsConf() ([]*pb.GameItemEntry, error) {
	pjs, err := Zk.GetNodeData(ZkP.Channels)
	if err != nil {
		return nil, err
	}
	js, err := simplejson.NewJson([]byte(pjs))
	if err != nil {
		return nil, err
	}

	items := js.Get("params")
	arr, err := items.Array()
	if err != nil {
		return nil, err
	}
	sz := len(arr)

	var channels []*pb.GameItemEntry
	var bGame bool
	for i := 0; i < sz; i++ {
		item := &pb.GameItemEntry{}

		item.ParentId = items.GetIndex(i).Get("lobby_id").MustInt64()
		item.Name = items.GetIndex(i).Get("name").MustString()
		item.Id = items.GetIndex(i).Get("channel_id").MustInt64()
		item.Enabled = int32(items.GetIndex(i).Get("is_start").MustInt64())
		item.Order = int32(items.GetIndex(i).Get("order").MustInt64())
		item.Icons = append(item.Icons, &pb.Icon{
			Name: items.GetIndex(i).Get("big_icon").MustString(),
			Size: int32(items.GetIndex(i).Get("big_icon_size").MustInt64()),
		})
		item.Icons = append(item.Icons, &pb.Icon{
			Name: items.GetIndex(i).Get("normal_icon").MustString(),
			Size: 0,
		})
		item.Icons = append(item.Icons, &pb.Icon{
			Name: items.GetIndex(i).Get("click_icon").MustString(),
			Size: 0,
		})
		item.Icons = append(item.Icons, &pb.Icon{
			Name: "",
			Size: 0,
		})
		item.Icons = append(item.Icons, &pb.Icon{})

		bGame = items.GetIndex(i).Get("is_game").MustBool()
		if bGame {
			item.IsGame = 1
		} else {
			item.IsGame = 0
		}
		channels = append(channels, item)
	}
	self.muChannels.Lock()
	self.cacheIdItem = make(map[int64][]*pb.GameItemEntry)
	self.Channels = channels
	self.muChannels.Unlock()

	return channels, nil
}

func (self *allConfT) GetChidlrenItems(parentId int64) []*pb.GameItemEntry {
	self.muGames.Lock()
	defer self.muGames.Unlock()
	self.muChannels.Lock()
	defer self.muChannels.Unlock()

	if res, ok := self.cacheIdItem[parentId]; ok {
		return res
	}

	return self.get_second_items(parentId)
}

func (self *allConfT) get_second_items(parentId int64) []*pb.GameItemEntry {
	var r []*pb.GameItemEntry

	for _, item := range self.Channels {
		if item.ParentId == parentId && item.Enabled != 0 {
			r = append(r, item)
		}
	}

	for _, item := range self.Games {
		if item.ParentId == parentId && item.Enabled != 0 {
			r = append(r, item)
		}
	}

	self.cacheIdItem[parentId] = r
	return r
}

func (self *allConfT) ReloadKvConf() error {
	data, err := Zk.GetNodeData(ZkP.Kv)
	if err != nil {
		return err
	}
	js, err := simplejson.NewJson(data)
	if nil != err {
		return err
	}
	if kv, ok := js.Interface().(map[string]interface{}); ok {
		self.muKv.Lock()
		self.Kv = kv
		self.muKv.Unlock()
	} else {
		return errNoZkData
	}
	return nil
}

func (self *allConfT) ReloadClientAddrs() error {
	jsstr, err := Zk.GetNodeData(ZkP.ClientAddrs)
	if err != nil {
		return err
	}
	sj, err := simplejson.NewJson([]byte(jsstr))
	if nil != err {
		return err
	}
	sparams, err := sj.Get("params").MarshalJSON()
	if nil != err {
		return err
	}

	self.muClientAddrs.Lock()
	self.ClientAddrsConf = &pb.S_Ntf_Config{
		Jsn: string(sparams),
	}
	self.muClientAddrs.Unlock()

	return nil
}

func (self *allConfT) ReloadWalletConf() error {
	data, err := Zk.GetNodeData(ZkP.Wallet)
	if err != nil {
		return err
	}

	wallet := new(walletConf)
	err = json.Unmarshal(data, wallet)
	if nil != err {
		return err
	}

	self.muWallet.Lock()
	self.Wallet = wallet
	defer self.muWallet.Unlock()

	return nil
}

func (self *allConfT) ReloadCheckin7() error {
	data, err := Zk.GetNodeData(ZkP.Checkin7)
	if err != nil {
		return err
	}

	var tmp [][]int64
	err = json.Unmarshal(data, &tmp)
	if nil != err {
		return err
	}

	self.muCheckin7.Lock()
	self.Checkin7 = []*pb.DimInt64{}
	for i := 0; i < len(tmp); i++ {
		var t pb.DimInt64
		t.Val = tmp[i]
		self.Checkin7 = append(self.Checkin7, &t)
	}
	self.muCheckin7.Unlock()
	return nil
}

// guid 合法性检查
func (self *allConfT) ValidGuid(guid uint64) bool {
	if iguid, ok := self.Kv["start_guid"]; ok {
		start_guid := utils.If_to_uint64(iguid, 0)
		return guid > start_guid
	}
	return guid > DEF_MIN_GUID
}

func (self *allConfT) ReloadGameTasksConf() ([]*pb.GameTask, error) {
	data, err := Zk.GetNodeData(ZkP.GameTask)
	if err != nil {
		return nil, err
	}
	type GameTaskHeader struct {
		Cmd    string         `json:"cmd"`
		Params []*pb.GameTask `json:"params"`
	}

	var header GameTaskHeader
	if err = json.Unmarshal([]byte(data), &header); err != nil {
		return nil, err
	}

	self.muGameTasks.Lock()
	self.GameTasks = header.Params
	self.muGameTasks.Unlock()

	return header.Params, nil
}

func (self *allConfT) ReloadTurntableConf() (*TurntableConf, error) {
	data, err := Zk.GetNodeData(ZkP.Turntable)
	if err != nil {
		return nil, err
	}

	var tc TurntableConf
	if err = json.Unmarshal([]byte(data), &tc); err != nil {
		return nil, err
	}

	self.muTurntable.Lock()
	tc.Sort()
	self.Turntable = &tc
	self.muTurntable.Unlock()

	return self.Turntable, nil
}
