package playroom

import (
	"fmt"
	"math"
	"server/GoUtil"
	limitedTimeEventCfg "server/conf/limitedTimeEvent"
	playroomCfg "server/conf/playroom"
	"server/game/mod/item"
	"server/msg"
)

type PlayroomMod struct {
	Collect     map[int]int        // 装饰
	Room        map[int]int        // 房间
	Status      int                // 0: 未拜访 1: 拜访
	Endtime     int64              // 结束时间
	Starttime   int64              // 开始时间
	WorkStatus  int                // 0: 未开始 1: 进行中 2: 结束
	Visitor     map[int]*Info      // 访客
	MoodInfo    map[int]*Mood      // 心情
	AllMood     int                // 总心情
	Reward      []*item.Item       // 奖励
	DayFirstT   int                // 每日未首次触发次数
	Trigger     int                // 未触发次数
	TriggerTime int64              // 触发时间
	HasVisit    map[int]int64      // 今日已拜访的玩家
	Target      int                // 拜访的目标
	GameId      int                // 游戏ID
	GameReward  map[int]*item.Item // 游戏奖励
	GameStatus  int                // 游戏状态
	Exclude     bool               // 是否排除
	LoseItem    []*item.Item       // 失去的物品
	Chip        int                // 碎片
	Flip        map[int]int        // 翻牌
	FlipReward  []*item.Item       // 翻牌奖励
	WorkOutline int                // 是否离线
	LastFlip    int                // 上次翻牌奖励档次
	NoFlip      int                // 连续未获取最高翻牌奖励次数
	TodayFlip   bool               // 今日是否已获得最高档奖励
	JackpotNum  int                // 每日转盘数量
	Physiology  map[int]*Physiology
}

const (
	STATUS_IDLE  = 0 // 未开始
	STATUS_VISIT = 1 // 拜访

	MOOD_TYPE_ENTER = 1 // 娱乐
	MOOD_TYPE_FOOD  = 2 // 食物
	MOOD_TYPE_CLEAN = 3 // 清洁

	GAME_RESULT_LOW    = 1 // 低
	GAME_RESULT_MIDDLE = 2 // 中
	GAME_RESULT_HIGH   = 3 // 高

	FLIP_TYPE_COPPER = 1 // 铜
	FLIP_TYPE_SILVER = 2 // 银
	FLIP_TYPE_GOLD   = 3 // 金

	PHYSIOLOGY_TYPE_STROKE = 1 // 抚摸
	PHYSIOLOGY_TYPE_PLAY   = 2 // 玩耍
	PHYSIOLOGY_TYPE_FEED   = 3 // 进食
	PHYSIOLOGY_TYPE_CLEAN  = 4 // 清洁
	PHYSIOLOGY_TYPE_TOLIET = 5 // 上厕所
)

type Mood struct {
	Id   int
	Num  int
	Time int64
}

type Physiology struct {
	Id   int
	Num  int
	Time int64
}

type Info struct {
	Time  int64
	Times int
}

func (p *PlayroomMod) InitData() {
	if p.Collect == nil {
		p.Collect = make(map[int]int)
	}
	InitCollect := playroomCfg.GetInitDecorate()
	for _, v := range InitCollect {
		p.Collect[v] = 1
	}
	if p.Room == nil {
		p.Room = make(map[int]int)
		p.JackpotNum = playroomCfg.GetJackpotNum()
	}
	if p.Visitor == nil {
		p.Visitor = make(map[int]*Info)
	}
	if p.MoodInfo == nil {
		p.MoodInfo = make(map[int]*Mood)
	}
	if p.Physiology == nil {
		p.Physiology = make(map[int]*Physiology)
	}
	if p.Reward == nil {
		p.Reward = make([]*item.Item, 0)
	}
	if p.HasVisit == nil {
		p.HasVisit = make(map[int]int64)
	}
	if p.GameReward == nil {
		p.GameReward = make(map[int]*item.Item)
	}
	if p.LoseItem == nil {
		p.LoseItem = make([]*item.Item, 0)
	}
	if p.Flip == nil {
		p.Flip = make(map[int]int)
	}
}

func (p *PlayroomMod) ZeroUpdate() {
	p.TodayFlip = false
	p.LastFlip = 0
	p.JackpotNum = playroomCfg.GetJackpotNum()
}

func (p *PlayroomMod) GetVisitor() map[int]*Info {
	return p.Visitor
}

func (p *PlayroomMod) GetTarget() int {
	return p.Target
}

func (p *PlayroomMod) GetHasVisit() map[int]int64 {
	return p.HasVisit
}

func (p *PlayroomMod) GetMood() map[int]int {
	Mood := make(map[int]int)
	for k, v := range p.MoodInfo {
		Mood[k] = v.Num
	}
	return Mood
}

func (p *PlayroomMod) GetPhysiologyList() map[int]int {
	Physiology := make(map[int]int)
	for k, v := range p.Physiology {
		Physiology[k] = v.Num
	}
	return Physiology
}

func (p *PlayroomMod) GetMoodInfo(Id int) *Mood {
	return p.MoodInfo[Id]
}

func (p *PlayroomMod) GetPhysiology(Id int) *Physiology {
	return p.Physiology[Id]
}

func (p *PlayroomMod) GetCollect() map[int]int {
	return p.Collect
}

func (p *PlayroomMod) GetRoom() map[int]int {
	return p.Room
}

func (p *PlayroomMod) GetStatus() int {
	return p.Status
}

func (p *PlayroomMod) GetChip() int {
	return p.Chip
}

func (p *PlayroomMod) AddChip() {
	p.Chip = min(p.Chip+1, 5)
}

func (p *PlayroomMod) SetTarget(Target int) {
	p.Target = Target
	p.Status = 1
	p.HasVisit[Target] = GoUtil.Now()
}

func (p *PlayroomMod) SetGameId(GameId int) {
	p.GameId = GameId
}

func (p *PlayroomMod) CreateOrderReward(Star int, itemMod *item.ItemMod) {
	if Star == 0 {
		return
	}
	p.Reward = make([]*item.Item, 0)
	NormalFoodId, NormalCleanId := playroomCfg.GetNormalItem()
	PremiumFoodId, PremiumCleanId := playroomCfg.GetPremiumItem()

	NormalFoodNum := itemMod.GetItem(NormalFoodId)
	NormalCleanNum := itemMod.GetItem(NormalCleanId)

	PremiumFoodNum := itemMod.GetItem(PremiumFoodId)
	PremiumCleanNum := itemMod.GetItem(PremiumCleanId)
	p.TriggerTime = GoUtil.Now()
	if NormalFoodNum == 0 {
		p.Reward = append(p.Reward, &item.Item{Id: NormalFoodId, Num: 1})
		return
	}
	if NormalCleanNum == 0 {
		p.Reward = append(p.Reward, &item.Item{Id: NormalCleanId, Num: 1})
		return
	}
	if PremiumFoodNum == 0 {
		p.Reward = append(p.Reward, &item.Item{Id: PremiumFoodId, Num: 1})
		return
	}
	if PremiumCleanNum == 0 {
		p.Reward = append(p.Reward, &item.Item{Id: PremiumCleanId, Num: 1})
		return
	}
	var RandSlice []int
	if math.Abs(float64((NormalCleanNum+PremiumCleanNum)-(NormalFoodNum+PremiumFoodNum))) > 3 {
		RandSlice := GoUtil.IfTrue((NormalCleanNum+PremiumCleanNum) > (NormalFoodNum+PremiumFoodNum), []int{PremiumCleanId, NormalCleanId}, []int{NormalFoodId, PremiumFoodId}).([]int)
		Prob := GoUtil.RandSlice(RandSlice)
		p.Reward = append(p.Reward, &item.Item{Id: Prob, Num: 1})
		return
	}
	RandSlice = []int{NormalFoodId, NormalCleanId, PremiumFoodId, PremiumCleanId}
	Prob := GoUtil.RandSlice(RandSlice)
	p.Reward = append(p.Reward, &item.Item{Id: Prob, Num: 1})
}

func (p *PlayroomMod) GetReward() []*item.Item {
	return p.Reward
}

func (p *PlayroomMod) Interact(Id, Type int) ([]*item.Item, int, error) {
	MoodType, ItemList, Effect := playroomCfg.GetInteract(Id, Type)
	if MoodType == 0 {
		return nil, 0, fmt.Errorf("Interact MoodType is 0")
	}
	if Effect > 0 {
		p.AllMood = min(100, p.AllMood+10)
	}
	PType, PEffect := playroomCfg.GetInteractPhysiology(Id)
	p.AddPhysiology(PType, PEffect)
	p.AddMood(MoodType, Effect)
	return ItemList, MoodType, nil
}

func (p *PlayroomMod) AddMood(Id, Num int) {
	_, ok := p.MoodInfo[Id]
	if !ok {
		p.MoodInfo[Id] = &Mood{Id: Id, Num: 0}
	}
	p.MoodInfo[Id].Num = max(0, min(p.MoodInfo[Id].Num+Num, 100))
	if p.MoodInfo[Id].Num != 0 && p.MoodInfo[Id].Time == 0 {
		p.MoodInfo[Id].Time = GoUtil.Now()
	}
	if p.MoodInfo[Id].Num == 0 {
		p.MoodInfo[Id].Time = 0
	}
}

func (p *PlayroomMod) AddPhysiology(Id, Num int) {
	Phy := p.GetPhysiology(Id)
	if Phy == nil {
		Phy = &Physiology{Id: Id, Num: 0, Time: 0}
	}
	Max := playroomCfg.GetPhysiologyMax(Id)
	Phy.Num = max(0, min(Phy.Num+Num, Max))
	if Phy.Num != 0 && Phy.Time == 0 {
		Phy.Time = GoUtil.Now()
	}
	if Phy.Num == 0 {
		Phy.Time = 0
	}
}

func (p *PlayroomMod) AddVisitor(Id int, Time int64) {
	v, ok := p.Visitor[Id]
	if !ok {
		p.Visitor[Id] = &Info{Time: Time, Times: 1}
		return
	}
	v.Times++
	v.Time = Time
}

func (p *PlayroomMod) SetRoom(Room map[int]int) error {
	p.Room = Room
	return nil
}

func (p *PlayroomMod) AddCollect(Id int) {
	p.Collect[Id]++
}

func (p *PlayroomMod) ResetGame() {
	p.Target = 0
	p.Status = 0
	p.GameId = 0
	p.GameReward = make(map[int]*item.Item)
}

func (p *PlayroomMod) ResetLose() {
	p.LoseItem = make([]*item.Item, 0)
}

func (p *PlayroomMod) SetGameReward(Chess1, Chess2, Star int) {
	p.GameReward[1] = &item.Item{Id: Chess1, Num: 1}
	p.GameReward[2] = &item.Item{Id: Chess2, Num: 1}
	p.GameReward[3] = &item.Item{Id: item.ITEM_STAR_ID, Num: Star}
}

func (p *PlayroomMod) SetGameRewardFlip(N1, N2, N3 int) {
	p.GameReward[1] = &item.Item{Id: item.ITEM_STAR_ID, Num: N1}
	p.GameReward[2] = &item.Item{Id: item.ITEM_STAR_ID, Num: N2}
	p.GameReward[3] = &item.Item{Id: item.ITEM_STAR_ID, Num: N3}
}

func (p *PlayroomMod) SelectReward(Id int) []*item.Item {
	v, ok := p.GameReward[Id]
	if !ok {
		return nil
	}
	return []*item.Item{v}
}

func (p *PlayroomMod) Lose(Item []*item.Item) {
	p.LoseItem = append(p.LoseItem, Item...)
}

func (p *PlayroomMod) Work() ([]*item.Item, error) {
	if p.Endtime > GoUtil.Now() {
		p.WorkStatus = 1
		return nil, nil
	}
	p.Starttime = GoUtil.Now()
	p.Endtime = GoUtil.Now() + 86400
	p.WorkStatus = 1
	ItemId := playroomCfg.GetWorkItem()
	return []*item.Item{item.NewItem(ItemId, 1)}, nil
}

func (p *PlayroomMod) Rest() {
	p.WorkStatus = 2
}

func (p *PlayroomMod) SetWorkOutline(Status int) {
	p.WorkOutline = Status
}

func (p *PlayroomMod) ResetWork() {
	p.WorkStatus = 0
	p.Endtime = 0
}

func (p *PlayroomMod) Outline() {
	p.WorkOutline = 1
}

func (p *PlayroomMod) GetVisitorInfo(Id int) (int, int64) {
	v, ok := p.Visitor[Id]
	if !ok {
		return 0, 0
	}
	return v.Times, v.Time
}
func (p *PlayroomMod) Draw() (int, []*item.Item, error) {
	if p.AllMood < 100 {
		return 0, nil, fmt.Errorf("Draw AllMood < 100")
	}
	if p.JackpotNum == 0 {
		return 0, nil, fmt.Errorf("Draw JackpotNum is 0")
	}
	p.JackpotNum--
	p.AllMood = 0
	ProbList := limitedTimeEventCfg.GetSenceJackpotProb()
	Id := GoUtil.RandMap(ProbList)
	return Id, limitedTimeEventCfg.GetSenceJackpotReward(Id), nil
}

func (p *PlayroomMod) NotifyWork() *msg.NotifyPlayroomWork {
	return &msg.NotifyPlayroomWork{
		WorkStatus: int32(p.WorkStatus),
		StartTime:  int32(p.Starttime),
	}
}

func (p *PlayroomMod) NotifyLose() *msg.NotifyPlayroomLose {
	return &msg.NotifyPlayroomLose{
		LoseItem: item.ItemToMsg(p.LoseItem),
		Chip:     int32(p.Chip),
	}
}

func (p *PlayroomMod) NotifyStatus() *msg.NofiPlayroomStatus {
	return &msg.NofiPlayroomStatus{
		WorkOutline: int32(p.WorkOutline),
	}
}

func (p *PlayroomMod) NotifyMood() *msg.NotifyPlayroomMood {
	Mood := make(map[int32]int32, 0)
	for k, v := range p.MoodInfo {
		Mood[int32(k)] = int32(v.Num)
	}
	return &msg.NotifyPlayroomMood{
		AllMood:    int32(p.AllMood),
		Mood:       Mood,
		Physiology: GoUtil.MapIntToInt32(p.GetPhysiologyList()),
	}
}

func (p *PlayroomMod) Fire(ChargeId int) []*item.Item {
	WorkChargeId := playroomCfg.GetWorkChargeId()
	if ChargeId == WorkChargeId {
		ItemId := playroomCfg.GetWorkItem()
		return []*item.Item{item.NewItem(ItemId, 1)}
	}
	return nil
}

func (p *PlayroomMod) RemoveChip(Num int) []*item.Item {
	Num = min(Num, p.Chip)
	p.Chip -= Num
	return []*item.Item{item.NewItem(item.ITEM_STAR_ID, Num*50)}
}

func (p *PlayroomMod) FlipCard(Pos int) (int, error) {
	if p.Status != STATUS_VISIT {
		return 0, fmt.Errorf("FlipCard Status is not STATUS_VISIT")
	}
	RandMap := map[int]int{
		FLIP_TYPE_COPPER: 35,
		FLIP_TYPE_SILVER: 45,
		FLIP_TYPE_GOLD:   20,
	}
	Prob := GoUtil.RandMap(RandMap)

	/**
	若玩家同一天内上一次游玩猫猫小金库未能获得金币档位奖励，且当天还未获得过金币档位奖励
	或玩家已连续三次未能获得金币档位奖励，则启用以下保底逻辑
	玩家已翻出两个银币或铜币图案的情况下，后续翻牌必然为金币
	*/
	check := make(map[int]int)
	for _, v := range p.Flip {
		check[v]++
	}
	if check[FLIP_TYPE_COPPER] == 2 || check[FLIP_TYPE_SILVER] == 2 {
		if p.LastFlip != FLIP_TYPE_GOLD && !p.TodayFlip {
			Prob = FLIP_TYPE_GOLD
		}
		if p.NoFlip == 3 {
			Prob = FLIP_TYPE_GOLD
		}
	}
	p.Flip[Pos] = Prob

	return Prob, nil
}

func (p *PlayroomMod) GetFlipReward() ([]*item.Item, int, error) {
	check := make(map[int]int)
	Items := make([]*item.Item, 0)
	T := p.Target
	for _, v := range p.Flip {
		check[v]++
		if check[v] == 3 {
			switch v {
			case FLIP_TYPE_COPPER:
				p.NoFlip++
				Items = append(Items, p.GameReward[FLIP_TYPE_COPPER])
			case FLIP_TYPE_SILVER:
				p.NoFlip++
				Items = append(Items, p.GameReward[FLIP_TYPE_SILVER])
			case FLIP_TYPE_GOLD:
				p.NoFlip = 0
				p.TodayFlip = true
				Items = append(Items, p.GameReward[FLIP_TYPE_GOLD])
			}
			p.LastFlip = v
			p.Status = STATUS_IDLE
			p.GameId = 0
			p.Flip = make(map[int]int)
			p.Target = 0
			return Items, T, nil
		}
	}
	return Items, T, fmt.Errorf("GetFlipReward check is not 3")
}

func (p *PlayroomMod) BuyItem(Id int) ([]*item.Item, []*item.Item) {
	return playroomCfg.GetBuyItem(Id)
}

func (p *PlayroomMod) UnLock(Lv int) {
	UnlockLv := playroomCfg.GetUnLockLv()
	if Lv < UnlockLv {
		return
	}
	if len(p.Physiology) == 0 {
		Now := GoUtil.Now()
		p.Physiology = make(map[int]*Physiology)
		TypeList := playroomCfg.GetPhysiologyTypeList()
		for _, v := range TypeList {
			Max := playroomCfg.GetPhysiologyMax(v)
			p.Physiology[v] = &Physiology{Id: v, Num: Max, Time: Now}
		}
	}
	if len(p.MoodInfo) == 0 {
		p.MoodInfo = make(map[int]*Mood)
		for k := 1; k <= 3; k++ {
			p.MoodInfo[k] = &Mood{Id: k, Num: 100}
		}
	}
}

// shop
func (p *PlayroomMod) ShopBuy(Id, Num int) ([]*item.Item, []*item.Item, error) {
	AddItemId, CostItem := playroomCfg.GetShopItem(Id)
	if AddItemId == 0 {
		return nil, nil, fmt.Errorf("ShopBuy AddItemId is 0")
	}
	NewCostItem := item.MutilItem(CostItem, Num)
	return []*item.Item{item.NewItem(AddItemId, Num)}, NewCostItem, nil
}
