package main

import (
	"container/list"
	"mongo.games.com/goserver/core/logger"

	"mongo.games.com/game/common"
	"mongo.games.com/game/model"
	taskproto "mongo.games.com/game/protocol/task"
	"mongo.games.com/game/srvdata"
)

/*
 任务观察者
*/

var TaskSubjectSingleton = &TaskSubject{
	list: make(map[int]*list.List),
}

type ITask interface {
	// TaskUpdate 更新任务进度
	// id 任务类型
	// data 数据
	TaskUpdate(id int, data any)
}

// TaskSubject 观察者
type TaskSubject struct {
	list map[int]*list.List
}

// Touch 任务统计事件
// id 任务类型
// data 数据
func (t *TaskSubject) Touch(id int, data any) {
	l, ok := t.list[id]
	if !ok {
		return
	}
	for e := l.Front(); e != nil; e = e.Next() {
		if o, ok := e.Value.(ITask); ok {
			o.TaskUpdate(id, data)
		}
	}
}

func (t *TaskSubject) Attach(id int, obj ITask) {
	l, ok := t.list[id]
	if !ok {
		l = new(list.List)
		t.list[id] = l
	}
	for e := l.Front(); e != nil; e = e.Next() {
		if e.Value == obj {
			return
		}
	}
	l.PushBack(obj)
}

type TaskData struct {
	SnId       int32
	GameID     int
	GameFreeID int32
	Num        int64
	Position   int32
	Debug      bool
}

type TaskHandle struct {
}

func (t *TaskHandle) TaskUpdate(id int, data any) {
	info, ok := data.(*TaskData)
	if !ok {
		return
	}
	p := PlayerMgrSington.GetPlayerBySnId(info.SnId)
	if p == nil {
		return
	}

	t.AllTask(id, data)

	num := info.Num
	logger.Logger.Tracef("玩家任务事件 Snid = %d,GameId = %d,GameFreeId = %d,任务 id = %d,num = %d", info.SnId, info.GameID, info.GameFreeID, id, num)
	switch id {
	case common.TaskTypeAdv: // 看广告

	case common.TaskTypeBuyCoin: // 买金币

	case common.TaskTypeLogin: // 每日登录

	case common.TaskTypeWinTimes: // 赢游戏次数

	case common.TaskTypePlayTimes: // 玩游戏次数
		p.InviteTask(common.InviteScoreTypePlayTimes, int32(info.GameID), num)
		p.InviteTask(common.InviteScoreTypeGameTimes, int32(info.GameID), num)

	case common.TaskTypeRankMatchTimes: // 排位赛次数

	case common.TaskTypePay: // 玩家充值
		p.PhoneLotteryTask(common.TaskTypePay, num)
		p.InviteTask(common.InviteScoreTypeRecharge, int32(info.GameID), num)

	case common.TaskTypeWinOrLose: // 游戏输赢金币数量
		p.PhoneLotteryTask(common.TaskTypeWinOrLose, num)
	case common.TaskTypeTienlenCount: //tienlen游戏场次
		p.PhoneLotteryTask(common.TaskTypeTienlenCount, 1)
	case common.TaskTypeBindInviter: // 绑定邀请人数量
		p.InviteTask(common.InviteScoreTypeBind, 0, num)

	case common.TaskTypeWinCoin: // 赢取金币数量

	case common.TaskTypeTienlenWinTimes: // tienlen游戏赢取次数

	case common.TaskTypeActivityScore: // 活跃积分数量

	case common.TaskTypeInviteScore: // 邀请积分数量

	case common.TaskTypeFirstLogin:
		//抽奖次数增加
		p.PhoneLotteryTask(common.TaskTypeFirstLogin, 0)
		p.InviteTask(common.InviteScoreTypeLogin, int32(info.GameID), num)

	case common.TaskTypeInviteNum:

	default:
		return
	}
	return
}

// AllTask 任务活动
func (t *TaskHandle) AllTask(id int, data any) {
	info, ok := data.(*TaskData)
	if !ok {
		return
	}
	p := PlayerMgrSington.GetPlayerBySnId(info.SnId)
	if p == nil {
		return
	}

	if p.WelfData == nil {
		p.WelfData = model.NewWelfareData()
	}
	if p.WelfData.Task == nil {
		p.WelfData.Task = make(map[int32]*model.TaskData)
	}

	logger.Logger.Tracef("AllTask taskID:%v %v", id, p.WelfData.Task[int32(id)])

	change := map[int32][]*taskproto.TaskData{}
	for _, v := range srvdata.PBDB_TaskMgr.Datas.GetArr() {
		// 任务类型
		if int(v.TaskType) != id {
			continue
		}
		if !info.Debug {
			// 游戏类型
			switch v.GetGameType() {
			case common.TaskGameTypeTienlen:
				if !common.IsTienLen(info.GameID) {
					continue
				}
			case common.TaskGameTypeThirteen:
				if !common.IsThirteen(info.GameID) {
					continue
				}
			case common.TaskGameTypeChess:
				if !common.IsChess(info.GameID) {
					continue
				}
			case common.TaskGameTypeSmallRocket:
				if !common.IsSmallRocket(info.GameID) {
					continue
				}
			default:
			}
			// 大厅类型
			if len(v.Position) > 0 && info.Position > 0 {
				if len(v.Position) > int(info.Position) {
					if v.Position[info.Position-1] != 1 {
						continue
					}
				}
			}
		}

		if p.WelfData.Task[v.Id] == nil {
			p.WelfData.Task[v.Id] = &model.TaskData{N: 0} // 初始化任务数据
		}
		p.WelfData.Task[v.Id].N += info.Num
		// 通知变更
		if !IsTaskReward(p, v.Id) {
			item := &taskproto.TaskData{
				Id:      v.Id,
				N:       p.WelfData.Task[v.Id].N,
				TargetN: v.TargetTimes,
				Status:  0,
				Reward:  v.Award,
			}
			if item.N > item.TargetN {
				item.N = item.TargetN
			}
			if IsTaskFinish(p, v.Id) {
				item.Status = TaskStateFinish
			}
			change[v.GetActivityType()] = append(change[v.GetActivityType()], item)
		}
	}
	// 通知变更
	for k, v := range change {
		if len(v) == 0 {
			continue
		}
		pack := &taskproto.SCTaskChange{
			Tp:   k,
			List: v,
		}
		p.SendToClient(int(taskproto.TaskPacketID_PACKET_SCTaskChange), pack)
		logger.Logger.Tracef("SCTaskChange %v", pack)
	}
}

func init() {
	taskHandle := new(TaskHandle)
	TaskSubjectSingleton.Attach(common.TaskTypeAdv, taskHandle)
	TaskSubjectSingleton.Attach(common.TaskTypeBuyCoin, taskHandle)
	TaskSubjectSingleton.Attach(common.TaskTypeLogin, taskHandle)
	TaskSubjectSingleton.Attach(common.TaskTypeWinTimes, taskHandle)
	TaskSubjectSingleton.Attach(common.TaskTypePlayTimes, taskHandle)
	TaskSubjectSingleton.Attach(common.TaskTypeRankMatchTimes, taskHandle)
	TaskSubjectSingleton.Attach(common.TaskTypePay, taskHandle)
	TaskSubjectSingleton.Attach(common.TaskTypeWinOrLose, taskHandle)
	TaskSubjectSingleton.Attach(common.TaskTypeTienlenCount, taskHandle)
	TaskSubjectSingleton.Attach(common.TaskTypeBindInviter, taskHandle)
	TaskSubjectSingleton.Attach(common.TaskTypeWinCoin, taskHandle)
	TaskSubjectSingleton.Attach(common.TaskTypeTienlenWinTimes, taskHandle)
	TaskSubjectSingleton.Attach(common.TaskTypeInviteScore, taskHandle)
	TaskSubjectSingleton.Attach(common.TaskTypeActivityScore, taskHandle)
	TaskSubjectSingleton.Attach(common.TaskTypeFirstLogin, taskHandle)
	TaskSubjectSingleton.Attach(common.TaskTypeInviteNum, taskHandle)
}
