package game

import (
	"encoding/gob"
	"fmt"
	"server/game/mod/card"
	"server/game/mod/msg"
	GoUtil "server/game_util"
	"strings"
	"sync"
	"time"
)

type VarMgr struct {
	*ServerMod
}

type VarData struct {
	Var       map[string]interface{}
	VarExpire map[string]*VarExpireData
	UserVar   map[string]*VarUserData

	NewVar    map[string]*VarExpireData
	NewUseVar map[int]map[string]*VarExpireData
	ZeroTime  int64
	Version   int64
	mu        sync.Mutex
}

const (
	VAR_OP_UPVOTE      = 1
	VAR_OP_CHIP        = 2
	VAR_OP_KISS        = 3
	VAR_OP_CHIP_SET    = 4
	VAR_OP_CATNIP_LOCK = 5
)

func (f *VarMgr) Init() {
	gob.Register(&VarGoldCard{})
	gob.Register(&VarExpireData{})
	f.key = VAR_MGR_KEY
	f.data = &VarData{
		NewVar:    map[string]*VarExpireData{},
		NewUseVar: map[int]map[string]*VarExpireData{},
	}
	// 注册处理函数
	f.init()
	// 版本更新 重构
	f.version()
	if f.data.(*VarData).NewVar == nil {
		f.data.(*VarData).NewVar = make(map[string]*VarExpireData)
	}
	if f.data.(*VarData).UserVar == nil {
		f.data.(*VarData).UserVar = make(map[string]*VarUserData)
	}
	if f.data.(*VarData).VarExpire == nil {
		f.data.(*VarData).VarExpire = make(map[string]*VarExpireData)
	}
	if f.getData().ZeroTime == GoUtil.ZeroTimestamp() {
		f.ZeroUpdate()
	}

	f.mDispatr.AfterFunc(time.Duration(GoUtil.NextZeroTimestampDuration())*time.Second, func() {
		f.ZeroUpdate()
	})
}

func (f *VarMgr) version() {
	switch v := f.getData().Version; v {
	case 0:
		// future version update
		data := f.getData()
		data.mu.Lock()
		defer data.mu.Unlock()
		// set to next version
		for k, v := range data.UserVar {
			if v != nil {
				uidStr := strings.Split(k, "_")[2]
				uid := GoUtil.Int(uidStr)
				f.SetUserVar(uid, VAR_PLAYROOM_UPVOTE, v.Upvote)
				f.SetUserVar(uid, VAR_PLAYROOM_CHIP, v.Chip)
				f.SetUserVar(uid, VAR_PLAYROOM_KISS, v.Kiss)
				delete(data.UserVar, k)
			}
		}
		f.getData().Version = 1
	}
}

func (f *VarMgr) ZeroUpdate() {
	f.getData().ZeroTime = GoUtil.ZeroTimestamp()
	// 随机生成两个金卡
	Card1, Card2 := card.RankGoldCard()
	f.SetVar(VAR_GOLD_CARD, &VarGoldCard{
		Four: Card1,
		Five: Card2,
	})
	for k, v := range f.getData().NewVar {
		if v.T < GoUtil.ZeroTimestamp() {
			delete(f.getData().Var, k)
		}
	}
	f.mDispatr.AfterFunc(time.Duration(GoUtil.NextZeroTimestampDuration())*time.Second, func() {
		f.ZeroUpdate()
	})
}

func (f *VarMgr) HandleCatnipPartner(Uid, Partner, GameId int, EndTime int64) (interface{}, error) {
	data := f.getData()
	data.mu.Lock()
	defer data.mu.Unlock()

	OtherPartnerInfo := f.GetUserVar(Uid, VAR_CATNIP_PARTNER)
	MyPartnerInfo := f.GetUserVar(Partner, VAR_CATNIP_PARTNER)
	MyOfPartnerList := GoUtil.IntSlice(MyPartnerInfo.D)
	OtherOfPartnerList := GoUtil.IntSlice(OtherPartnerInfo.D)
	if len(MyOfPartnerList) > 4 || len(OtherOfPartnerList) > 4 {
		return nil, fmt.Errorf("catnip partner already full for uid %d in game %d", Partner, GameId)
	}
	f.SetUserVar(Partner, VAR_CATNIP_PARTNER, &VarExpireData{
		D: append(OtherOfPartnerList, Uid),
		T: EndTime,
	})
	f.SetUserVar(Uid, VAR_CATNIP_PARTNER, &VarExpireData{
		D: append(MyOfPartnerList, Partner),
		T: EndTime,
	})
	return nil, nil
}

func (f *VarMgr) SetUserVar(uid int, key string, value interface{}) {
	varData := f.getData().NewUseVar[uid]
	if varData == nil {
		varData = make(map[string]*VarExpireData)
		f.getData().NewUseVar[uid] = varData
	}
	ved, ok := varData[key]
	if !ok {
		ved = &VarExpireData{}
	}
	ved.D = value
	varData[key] = ved
	f.getData().NewUseVar[uid] = varData
	SaveCacheVarData(GoUtil.GetVarKey(uid), varData)
}

func (f *VarMgr) GetUserVar(uid int, key string) *VarExpireData {
	varData := f.getData().NewUseVar[uid]
	if varData == nil {
		varData = make(map[string]*VarExpireData)
		f.getData().NewUseVar[uid] = varData
	}
	ved, ok := varData[key]
	if !ok {
		ved = &VarExpireData{}
		varData[key] = ved
	}
	return ved
}

func (f *VarMgr) SetVar(key string, value interface{}) {
	f.getData().NewVar[key] = &VarExpireData{
		D: value,
	}
	SaveCacheVarData(key, f.getData().NewVar[key])
}

func (f *VarMgr) GetVar(key string) *VarExpireData {
	if v, ok := f.getData().NewVar[key]; ok {
		return v
	}
	data := &VarExpireData{}
	f.getData().NewVar[key] = data
	return data
}

func (f *VarMgr) DelVar(key string) {
	delete(f.getData().Var, key)
}

func (f *VarMgr) getData() *VarData {
	return f.data.(*VarData)
}

func getVarData() *VarData {
	return G_GameLogicPtr.VarMgr.getData()
}

func SetVarDataHandler(m *msg.Msg) (interface{}, error) {
	data := getVarData()
	data.mu.Lock()
	defer data.mu.Unlock()
	if v, ok := m.Extra.(msg.VarData); ok {
		ved, ok := data.NewVar[v.Key]
		if !ok {
			ved = &VarExpireData{}
		}
		switch v.SetType {
		case msg.VAR_OP_SET:
			ved.D = v.Value
		case msg.VAR_OP_ADD:
			if num, ok := ved.D.(int); ok {
				ved.D = num + 1
			} else {
				ved.D = 1
			}
		case msg.VAR_OP_SUB:
			if num, ok := ved.D.(int); ok {
				if num > 0 {
					ved.D = num - 1
				} else {
					ved.D = 0
				}
			} else {
				ved.D = 0
			}
		}
		ved.U = time.Now().Unix()
		if m.End > 0 {
			ved.T = m.End
		}
		data.NewVar[v.Key] = ved
		SaveCacheVarData(v.Key, ved)
	}
	return nil, nil
}

func GetUserVarDataHandler(m *msg.Msg) (interface{}, error) {
	data := getVarData()
	userVar := &VarExpireData{}
	if v, ok := m.Extra.(msg.VarData); ok {
		if varData, ok := data.NewUseVar[m.From]; ok {
			userVar, _ = varData[v.Key]
		}
		if userVar == nil {
			userVar = &VarExpireData{}
		}
		ReplyPlayerMsgASync(m, userVar.D)
		return userVar, nil
	}
	return nil, fmt.Errorf("invalid parameters for getting var data")
}

func SetUserVarDataHandler(m *msg.Msg) (interface{}, error) {
	data := getVarData()
	data.mu.Lock()
	defer data.mu.Unlock()
	if v, ok := m.Extra.(msg.VarData); ok {
		varData := data.NewUseVar[m.To]
		if varData == nil {
			varData = make(map[string]*VarExpireData)
			data.NewUseVar[m.To] = varData
		}
		ved, ok := varData[v.Key]
		if !ok {
			ved = &VarExpireData{}
		}
		switch v.SetType {
		case msg.VAR_OP_SET:
			ved.D = v.Value
		case msg.VAR_OP_ADD:
			if num, ok := ved.D.(int); ok {
				ved.D = num + 1
			} else {
				ved.D = 1
			}
		case msg.VAR_OP_SUB:
			if num, ok := ved.D.(int); ok {
				if num > 0 {
					ved.D = num - 1
				} else {
					ved.D = 0
				}
			} else {
				ved.D = 0
			}
		}
		ved.U = time.Now().Unix()
		if m.End > 0 {
			ved.T = m.End
		}
		varData[v.Key] = ved
		data.NewUseVar[m.To] = varData
		SaveCacheVarData(GoUtil.GetVarKey(m.To), data.NewUseVar[m.To])
	}
	// 保存到缓存中
	return nil, nil
}

func GetVarDataHandler(m *msg.Msg) (interface{}, error) {
	data := getVarData()
	varData := &VarExpireData{}
	if v, ok := m.Extra.(msg.VarData); ok {
		varData, _ = data.NewVar[v.Key]
		if varData == nil {
			varData = &VarExpireData{}
		}
		ReplyPlayerMsgASync(m, varData.D)
		return varData, nil
	}
	return nil, fmt.Errorf("invalid parameters for getting var data")
}
