package game

import (
	"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
	DailyVar  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() {
	f.key = VAR_MGR_KEY
	f.data = &VarData{
		NewVar:    map[string]*VarExpireData{},
		NewUseVar: map[int]map[string]*VarExpireData{},
	}
	// 注册处理函数
	f.init()
	// 版本更新 重构
	f.version()
	if f.getData().NewVar == nil {
		f.getData().NewVar = make(map[string]*VarExpireData)
	}
	if f.getData().UserVar == nil {
		f.getData().UserVar = make(map[string]*VarUserData)
	}
	if f.getData().VarExpire == nil {
		f.getData().VarExpire = make(map[string]*VarExpireData)
	}
	if f.getData().DailyVar == nil {
		f.getData().DailyVar = 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) fixbug() {
	data := f.getData()
	data.mu.Lock()
	defer data.mu.Unlock()
	for k, v := range data.NewUseVar {
		if v != nil {
			del := true
			for _, ved := range v {
				if n, ok := ved.D.(int); ok && n != 0 {
					del = false
				}
			}
			if del {
				delete(data.NewUseVar, k)
			}

		}
	}
}

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, userData := range data.UserVar {
			if userData != nil {
				uidStr := strings.Split(k, "_")[2]
				uid := GoUtil.Int(uidStr)
				f.SetUserVar(uid, VAR_PLAYROOM_UPVOTE, userData.Upvote)
				f.SetUserVar(uid, VAR_PLAYROOM_CHIP, userData.Chip)
				f.SetUserVar(uid, VAR_PLAYROOM_KISS, userData.Kiss)
				delete(data.UserVar, k)
			}
		}
		f.getData().Version = 1
	case 1:
		// future version update
		f.fixbug() // 修复用户变量冗余数据
		f.getData().Version = 2
	}
}

func (f *VarMgr) ZeroUpdate() {
	data := f.getData()
	data.mu.Lock()
	defer data.mu.Unlock()
	data.ZeroTime = GoUtil.ZeroTimestamp()
	// 随机生成两个金卡
	Card1, Card2 := card.RankGoldCard()
	f.SetVar(VAR_GOLD_CARD, &VarGoldCard{
		Four: Card1,
		Five: Card2,
	})
	for k, v := range data.NewVar {
		if v.T < GoUtil.ZeroTimestamp() {
			delete(data.NewVar, k)
		}
	}
	// 清空每日变量
	data.DailyVar = make(map[string]*VarExpireData)
	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
	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)
	}
	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) 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()
	v, ok := m.Extra.(msg.VarData)
	if !ok {
		return nil, fmt.Errorf("invalid parameters for setting var data")
	}
	ved, ok := data.NewVar[v.Key]
	if !ok {
		ved = &VarExpireData{}
	}
	varDataOperation(ved, v.SetType, v.Value)
	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()
	data.mu.Lock()
	defer data.mu.Unlock()
	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()
	v, ok := m.Extra.(msg.VarData)
	if !ok {
		return nil, fmt.Errorf("invalid parameters for setting var data")
	}
	varData := data.NewUseVar[m.To]
	if varData == nil {
		varData = make(map[string]*VarExpireData)
		data.NewUseVar[m.To] = varData
	}
	ved := varData[v.Key]
	if ved == nil {
		ved = &VarExpireData{}
	}
	varDataOperation(ved, v.SetType, v.Value)
	if m.End > 0 {
		ved.T = m.End
	}
	varData[v.Key] = ved
	SaveCacheVarData(GoUtil.GetVarKey(m.To), varData)
	return nil, nil
}

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

func SetDailyVarDataHandler(m *msg.Msg) (interface{}, error) {
	data := getVarData()
	data.mu.Lock()
	defer data.mu.Unlock()
	info, ok := m.Extra.(msg.VarData)
	if !ok {
		return nil, fmt.Errorf("invalid parameters for getting daily var data")
	}
	varData := data.DailyVar[info.Key]
	if varData == nil {
		varData = &VarExpireData{}
	}
	varDataOperation(varData, info.SetType, info.Value)
	if m.End > 0 {
		varData.T = m.End
	}
	data.DailyVar[info.Key] = varData
	SaveCacheVarData(GoUtil.GetVarKey(m.To), varData)
	return nil, nil
}

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

func varDataOperation(varData *VarExpireData, setType int, value interface{}) *VarExpireData {
	switch setType {
	case msg.VAR_OP_SET:
		varData.D = value
	case msg.VAR_OP_ADD:
		if num, ok := varData.D.(int); ok {
			varData.D = num + 1
		} else {
			varData.D = 1
		}
	case msg.VAR_OP_SUB:
		if num, ok := varData.D.(int); ok {
			if num > 0 {
				varData.D = num - 1
			} else {
				varData.D = 0
			}
		} else {
			varData.D = 0
		}
	}
	varData.U = GoUtil.Now()
	return varData
}
