package main

import (
	"container/list"
	"fmt"
	"mongo.games.com/game/common"
	"mongo.games.com/game/model"
	"mongo.games.com/game/proto"
	hall_proto "mongo.games.com/game/protocol/gamehall"
	"mongo.games.com/goserver/core/basic"
	"mongo.games.com/goserver/core/task"
	"strconv"
	"time"
)

const (
	PrivateSceneState_Deleting = iota //删除中
	PrivateSceneState_Deleted         //已删除
)

var PrivateSceneMgrSington = &PrivateSceneMgr{
	pps: make(map[int32]*PlayerPrivateScene),
}

type PlayerPrivateScene struct {
	snid        int32  // 玩家id
	creatorName string //创建人昵称
	platform    string // 平台名称
	channel     string // 渠道名称
	promoter    string // 推广员
	packageTag  string // 推广包标识
	scenes      map[int]*Scene
	logsByDay   map[int]*list.List
	dupLog      map[string]struct{}
	loaded      bool
}

func (pps *PlayerPrivateScene) AddScene(s *Scene) {
	pps.scenes[s.sceneId] = s
}

func (pps *PlayerPrivateScene) GetScene(sceneId int) *Scene {
	if s, exist := pps.scenes[sceneId]; exist {
		return s
	}
	return nil
}

func (pps *PlayerPrivateScene) GetCount() int {
	return len(pps.scenes)
}

func (pps *PlayerPrivateScene) CanDelete() bool {
	return !pps.loaded && len(pps.scenes) == 0
}

func (pps *PlayerPrivateScene) OnPlayerLogin(p *Player) {

}

func (pps *PlayerPrivateScene) OnPlayerLogout(p *Player) {
	pps.logsByDay = nil
	pps.loaded = false
}

func (pps *PlayerPrivateScene) OnCreateScene(p *Player, s *Scene) {
	pps.scenes[s.sceneId] = s
}

func (pps *PlayerPrivateScene) LoadLogs(p *Player, yyyymmdd int32) {
	if !pps.loaded {
		var logs []*model.PrivateSceneLog
		var err error
		task.New(nil, task.CallableWrapper(func(o *basic.Object) interface{} {
			logs, err = model.GetPrivateSceneLogBySnId(p.Platform, p.SnId, model.GameParamData.PrivateSceneLogLimit)
			return nil
		}), task.CompleteNotifyWrapper(func(data interface{}, t task.Task) {
			if err == nil {
				pps.loaded = true
				pps.TidyLog(logs)
				pps.SendLogs(p, yyyymmdd)
			}
		}), "GetPrivateSceneLogBySnId").Start()
	} else {
		pps.SendLogs(p, yyyymmdd)
	}
}

func (pps *PlayerPrivateScene) TidyLog(logs []*model.PrivateSceneLog) {
	if pps.logsByDay == nil {
		pps.logsByDay = make(map[int]*list.List)
	}

	for _, log := range logs {
		if _, exist := pps.dupLog[log.LogId.Hex()]; exist {
			continue
		}
		y, m, d := log.CreateTime.Date()
		day := y*10000 + int(m)*100 + d
		if lst, exist := pps.logsByDay[day]; exist {
			lst.PushBack(log)
		} else {
			lst = list.New()
			pps.logsByDay[day] = lst
			lst.PushBack(log)
		}
	}
	pps.dupLog = nil
}

func (pps *PlayerPrivateScene) SendLogs(p *Player, yyyymmdd int32) {
	pack := &hall_proto.SCGetPrivateRoomHistory{
		QueryTime: proto.Int32(yyyymmdd),
	}
	if logs, exist := pps.logsByDay[int(yyyymmdd)]; exist {
		for e := logs.Front(); e != nil; e = e.Next() {
			if log, ok := e.Value.(*model.PrivateSceneLog); ok {
				data := &hall_proto.PrivateRoomHistory{
					GameFreeId:  proto.Int32(log.GameFreeId),
					RoomId:      proto.Int32(log.SceneId),
					CreateTime:  proto.Int32(int32(log.CreateTime.Unix())),
					DestroyTime: proto.Int32(int32(log.DestroyTime.Unix())),
					CreateFee:   proto.Int32(log.CreateFee),
				}
				pack.Datas = append(pack.Datas, data)
			}
		}
	}
	proto.SetDefaults(pack)
	p.SendToClient(int(hall_proto.GameHallPacketID_PACKET_SC_GETPRIVATEROOMHISTORY), pack)
}

func (pps *PlayerPrivateScene) PushLog(log *model.PrivateSceneLog) {
	if log == nil {
		return
	}

	y, m, d := log.CreateTime.Date()
	day := y*10000 + int(m)*100 + d
	if lst, exist := pps.logsByDay[day]; exist {
		lst.PushFront(log)
	} else {
		lst = list.New()
		pps.logsByDay[day] = lst
		lst.PushFront(log)
	}
	if !pps.loaded {
		pps.dupLog[log.LogId.Hex()] = struct{}{}
	}
}

func (pps *PlayerPrivateScene) SendPrivateScenes(p *Player) {
	pack := &hall_proto.SCGetPrivateRoomList{}
	for sceneid, s := range pps.scenes {
		data := &hall_proto.PrivateRoomInfo{
			GameFreeId: proto.Int32(s.dbGameFree.GetId()),
			RoomId:     proto.Int(sceneid),
			CurrRound:  proto.Int32(s.currRound),
			MaxRound:   proto.Int32(s.totalRound),
			CurrNum:    proto.Int(len(s.players)),
			MaxPlayer:  proto.Int(s.playerNum),
			CreateTs:   proto.Int32(int32(s.createTime.Unix())),
		}
		pack.Datas = append(pack.Datas, data)
	}
	proto.SetDefaults(pack)
	p.SendToClient(int(hall_proto.GameHallPacketID_PACKET_SC_GETPRIVATEROOMLIST), pack)
}

type PrivateSceneMgr struct {
	pps map[int32]*PlayerPrivateScene
}

func (psm *PrivateSceneMgr) GetOrCreatePlayerPrivateScene(p *Player) *PlayerPrivateScene {
	snid := p.SnId
	if pps, exist := psm.pps[snid]; exist {
		return pps
	}

	pps := &PlayerPrivateScene{
		snid:        snid,
		creatorName: p.Name,
		platform:    p.Platform,
		channel:     p.Channel,
		promoter:    strconv.Itoa(int(p.PromoterTree)),
		packageTag:  p.PackageID,
		scenes:      make(map[int]*Scene),
		logsByDay:   make(map[int]*list.List),
		dupLog:      make(map[string]struct{}),
	}

	psm.pps[snid] = pps
	return pps
}

func (psm *PrivateSceneMgr) GetPlayerPrivateScene(snid int32) *PlayerPrivateScene {
	if pps, exist := psm.pps[snid]; exist {
		return pps
	}
	return nil
}

func (psm *PrivateSceneMgr) OnDestroyScene(scene *Scene) {
	if scene == nil {
		return
	}

	if !scene.IsPrivateScene() {
		return
	}

	pps := psm.GetPlayerPrivateScene(scene.creator)
	if pps != nil {
		if pps.GetScene(scene.sceneId) == scene {
			delete(pps.scenes, scene.sceneId)
			var tax int32
			var returnCoin int32
			p := PlayerMgrSington.GetPlayerBySnId(scene.creator)

			if scene.currRound == 0 && !scene.starting && scene.createFee > 0 { //未开始
				if scene.manualDelete && time.Now().Sub(scene.createTime) < time.Second*time.Duration(model.GameParamData.PrivateSceneFreeDistroySec) { //低于指定时间，要扣除部分费用
					tax = scene.createFee * int32(model.GameParamData.PrivateSceneDestroyTax) / 100
					returnCoin = scene.createFee - tax
				} else {
					returnCoin = scene.createFee
				}
				if returnCoin > 0 {
					if p != nil {
						var remark string
						if tax > 0 {
							remark = fmt.Sprintf("提前解散扣除费用%.02f", float32(tax)/100.0)
						}
						p.AddCoin(int64(returnCoin), 0, common.GainWay_PrivateSceneReturn, "", remark)
					} else {
						//TODO 发送邮件
						//sendClubMail_ClubCreateRoomRefund(scene.creator, scene.limitPlatform.Name, int32(scene.sceneId), int64(tax), int64(returnCoin))
					}
				}
				//if p != nil {
				//	//统计创建房间数量
				//	key := scene.dbGameFree.GetGameDif()
				//	if gd, ok := p.GameData[key]; ok {
				//		gd.CreateRoomTimes--
				//	} else {
				//		p.GameData[key] = &model.PlayerGameStatics{
				//			CreateRoomTimes: 0,
				//		}
				//	}
				//}
			}

			if p != nil {
				pack := &hall_proto.SCDestroyPrivateRoom{
					OpRetCode: hall_proto.OpResultCode_Game_OPRC_Sucess_Game,
					RoomId:    proto.Int(scene.sceneId),
					State:     proto.Int(PrivateSceneState_Deleted),
				}
				proto.SetDefaults(pack)
				p.SendToClient(int(hall_proto.GameHallPacketID_PACKET_SC_DESTROYPRIVATEROOM), pack)
			}

			//写log
			log := model.NewPrivateSceneLog()
			if log != nil {
				log.SnId = pps.snid
				log.Platform = pps.platform
				log.Channel = pps.channel
				log.Promoter = pps.promoter
				log.GameFreeId = scene.dbGameFree.GetId()
				log.SceneId = int32(scene.sceneId)
				log.CreateTime = scene.createTime
				log.DestroyTime = time.Now()
				if returnCoin > 0 {
					log.CreateFee = tax
				} else {
					log.CreateFee = scene.createFee
				}
				//PrivateSceneLogChannelSington.Write(log)
				pps.PushLog(log)
			}

			if pps.CanDelete() && p == nil {
				delete(psm.pps, scene.creator)
			}
		}
	}
}
