package friend

import (
	"fmt"
	cardCfg "server/conf/card"
	friendCfg "server/conf/friend"
	"server/game/mod/card"
	"server/game/mod/item"
	GoUtil "server/game_util"
	"server/msg"
)

type FriendMod struct {
	FriendList    map[int]struct{}          // TODO 废弃 好友列表
	NewFriendList map[int]*FriendInfo       // 好友列表
	ApplyList     map[int]int64             // 好友请求列表
	SendApply     map[int]int64             // 发送的申请
	Apply         []*ApplyInfo              // 其他请求列表
	Card          map[string]*card.CardInfo // 收到的申请交换
	Log           []*LogInfo                // 日志
	AutoId        int
	Id            int64               // 已同步msg ID
	Npc           []int               // npc id
	Bubble        map[int]*BubbleInfo // 气泡
	ActivityLog   []*ActLogInfo       // 活动日志
	ReplyList     []*ReplyInfo        // 好友回复列表
	DailySponsor  int                 // 好友赞助次数
	RecommendList map[int]*Recommend
	DailyGetApply int // 每日获得申请次数
}

type Recommend struct {
	Uid  int
	Time int64
}

type ReplyInfo struct {
	Id        int
	Uid       int
	Type      int
	Param     string
	Status    int
	AddTime   int64
	ReplyTime int64
	EndTime   int64
	Items     []*item.Item
}

type ActLogInfo struct {
	Type  int
	Time  int64
	Param string
}

type BubbleInfo struct {
	Id       int   // 气泡ID
	Time     int64 // 气泡时间
	Type     int
	ItemList []*item.Item // 奖励物品
}

type FriendInfo struct {
	AddTime  int64
	DelTime  int64
	Interact []*Interact // 拜访记录
}

type Interact struct {
	VisitTime int64 // 拜访时间
	Type      int   // 1:拜访 2:点赞
}

type ApplyInfo struct {
	Type int // 1:申请 2:同意 3:拒绝 4:删除
	Time int64
	Uid  int64
}

const (
	REPLY_TYPE_GREETING     = 1 // 问候
	REPLY_TYPE_GREETING_Get = 2 // 收到问候
	REPLY_TYPE_CATNIP       = 3 // 猫薄荷加好友
	REPLY_TYPE_CATNIP_ITEMS = 4 // 收到猫薄荷好友道具
)

// 24小时内与玩家进行过以下互动的用户，若被选中参加本次宠物宝藏，在其头像旁添加礼物盒
const (
	INTERACT_TYPE_VISIT  = 1 // 拜访过玩家的Pet Playroom并进行过小游戏或点赞的用户
	INTERACT_TYPE_UPVOTE = 2 // 为玩家的图鉴全收集信息点过赞的用户
	INTERACT_TYPE_CARD   = 3 // 向玩家赠送过卡牌的用户
	INTERACT_TYPE_EX     = 4 // 向玩家发起过卡牌交换
	INTERACT_TYPE_WISH   = 5 // 邀请玩家一同参加活动的用户
)

const (
	LOG_TYPE_FRIEND_APPLY       = 1  // 收到申请好友
	LOG_TYPE_FRIEND_BECOME      = 2  // 成为好友
	LOG_TYPE_CARD_EX_SEND       = 3  // 发起卡牌交换申请
	LOG_TYPE_CARD_SEND          = 4  // 赠送卡牌
	LOG_TYPE_CARD_GIVE          = 5  // 请求卡牌
	LOG_TYPE_CARD_SELECT_GET    = 6  // 选择卡牌交换
	LOG_TYPE_CARD_ACCEPT_GIVE   = 7  // 接受卡牌
	LOG_TYPE_CARD_EX_GET        = 8  // 收到卡牌交换申请
	LOG_TYPE_CARD_SELECT_SEND   = 9  // 选择卡牌交换
	LOG_TYPE_CARD_EX_SUCCESS_1  = 10 // 卡牌交换成功
	LOG_TYPE_CARD_EX_SUCCESS_2  = 11 // 卡牌交换成功
	LOG_TYPE_FRIEND_DELETE      = 14 // 删除好友
	LOG_TYPE_PLAYROOM_VISIT     = 15 // 非小猫游戏，他人偷走了玩家的猫币
	LOG_TYPE_HANDBOOK           = 16 // 图鉴收集
	LOG_TYPE_HANDBOOK_UPVOTE    = 17 // 图鉴点赞
	LOG_TYPE_CHARGE_SEND        = 18 // 赠送充值礼物
	LOG_TYPE_CHARGE_RECEIVE     = 19 // 收到充值礼物
	LOG_TYPE_WISH               = 20 // 心愿单请求
	LOG_TYPE_FRIEND_BECOME_NPC  = 21 // npc成为好友
	LOG_TYPE_PLAYROOM_UPVOTE    = 22 // playroom点赞
	LOG_TYPE_PLAYROOM_CHAMPSHIP = 23 // 竞标赛排名
	LOG_TYPE_TREASURE           = 24 // 好友宝藏
	LOG_TYPE_CARD_SEND_ACCEPT   = 25 // 收到赠送卡牌
	LOG_TYPE_PLAYROOM_CAT_WIN   = 26 // 小猫游戏，给小猫成功装箱
	LOG_TYPE_PLAYROOM_CAT_LOSE  = 27 // 小猫游戏，装箱小猫未成功
	LOG_TYPE_CARD_GIVE_ACCEPT   = 28 // 接受卡牌请求
	LOG_TYPE_FRIEND_INVITE      = 29 // 邀请注册
	LOG_TYPE_TREASURE_HELP      = 30 // 好友宝藏帮助
	LOG_TYPE_FRIEND_SPONSOR     = 31 // 好友赞助体力
	LOG_TYPE_FRIEND_SPONSOR_GET = 32 // 获得好友赞助体力
)

const (
	FRIEND_NOTIFY_APPLY  = 1
	FRIEND_NOTIFY_AGREE  = 2
	FRIEND_NOTIFY_REFUSE = 3
	FRIEND_NOTIFY_DEL    = 4
)

const (
	APPLY_TYPE_WISH = 1 // 心愿单请求
)

const (
	ACT_LOG_TYPE_FIRST_LOGIN                   = 1  // 首次登入游戏
	ACT_LOG_TYPE_COMPLETE_RESTROOM             = 2  // 完成休息室
	ACT_LOG_TYPE_COMPLETE_RESTAURANT           = 3  // 完成餐厅
	ACT_LOG_TYPE_COMPLETE_BATHROOM             = 4  // 完成浴室
	ACT_LOG_TYPE_COMPLETE_CLOAKROOM            = 5  // 完成衣帽间
	ACT_LOG_TYPE_GET_NEW_AVATAR                = 6  // 获得新头像
	ACT_LOG_TYPE_GET_NEW_AVATAR_FRAME          = 7  // 获得新头像框
	ACT_LOG_TYPE_GET_NEW_EMOTION               = 8  // 获得新表情
	ACT_LOG_TYPE_GET_NEW_DECORATION            = 9  // 获得新装饰品
	ACT_LOG_TYPE_GET_NEW_COSTUME               = 10 // 获得新服装
	ACT_LOG_TYPE_COMPLETE_CARD_ALBUM           = 11 // 完成卡册收集
	ACT_LOG_TYPE_COMPLETE_ALL_CARDS            = 12 // 完成全卡牌收集
	ACT_LOG_TYPE_GET_CHAMPIONSHIP_RANK         = 13 // 获得锦标赛名次
	ACT_LOG_TYPE_GET_CHAMPIONSHIP_PRIZE        = 14 // 获得锦标赛大奖
	ACT_LOG_TYPE_GET_LIMITED_ACTIVITY_PRIZE    = 15 // 获得限时活动大奖
	ACT_LOG_TYPE_JOIN_FRIEND_COOP_ACTIVITY     = 16 // 参加好友合作类活动
	ACT_LOG_TYPE_GET_VISIT_GAME_PRIZE          = 17 // 获得拜访小游戏大奖 翻牌
	ACT_LOG_TYPE_GET_VISIT_GAME_PRIZE_1        = 18 // 获得拜访小游戏大奖 除了翻牌
	ACT_LOG_TYPE_OPEN_PET_TREASURE             = 19 // 打开宠物宝藏
	ACT_LOG_TYPE_VISIT_UPVOTE                  = 20 // 拜访时点赞
	ACT_LOG_TYPE_COMPLETE_HANDBOOK_ACHIEVEMENT = 21 // 完成图鉴收集成就
	ACT_LOG_TYPE_COMPLETE_CHAPTER_SCENES       = 22 // 完成第X章所有场景
	ACT_LOG_TYPE_LOST_USER_RETURN              = 23 // 流失用户回归
	ACT_LOG_TYPE_ACCEPT_MY_INVITE_REGISTER     = 24 // 接受"我"的邀请注册
	ACT_LOG_TYPE_BECOME_MY_FRIEND              = 25 // 成为"我"的好友
	ACT_LOG_TYPE_SEND_CARD_TO_ME               = 26 // 向"我"赠送卡牌
	ACT_LOG_TYPE_CARD_EXCHANGE_WITH_ME         = 27 // 与"我"达成卡牌交换
	ACT_LOG_TYPE_APPEAR_IN_MY_PET_TREASURE     = 28 // 出现在"我"的宠物宝藏中并被选中
	ACT_LOG_TYPE_VISIT_MY_CAT_PRIVATE_TREASURE = 29 // 拜访"我"并玩了猫猫私房宝
	ACT_LOG_TYPE_VISIT_MY_OTHER_GAME_WIN       = 30 // 拜访"我"并玩了猫猫私房宝以外的小游戏，成功装箱
	ACT_LOG_TYPE_VISIT_MY_OTHER_GAME_LOSE      = 31 // 拜访"我"并玩了猫猫私房宝以外的小游戏，未成功装箱
	ACT_LOG_TYPE_UPVOTE_MY_COLLECTION_INFO     = 32 // 为"我"的全收集信息点赞
	ACT_LOG_TYPE_UPVOTE_MY_ROOM                = 33 // 为"我"的房间点赞
	ACT_LOG_TYPE_JOIN_COOP_ACTIVITY_WITH_ME    = 34 // 与"我"一起参加好友合作类活动
)

type LogInfo struct {
	Id     int
	Uid    int
	Type   int
	Time   int64
	Param  string
	Upvote bool // 点赞
	Reward bool // 是否已领取奖励
}

// 初始化数据
func (f *FriendMod) InitData() {
	if f.FriendList == nil {
		f.FriendList = make(map[int]struct{})
	}
	if len(f.ActivityLog) == 0 {
		f.AddActLog(ACT_LOG_TYPE_FIRST_LOGIN, "")
	}
	if f.ApplyList == nil {
		f.ApplyList = make(map[int]int64)
	}
	if f.Card == nil {
		f.Card = make(map[string]*card.CardInfo)
	}
	if f.SendApply == nil {
		f.SendApply = make(map[int]int64)
	}
	if f.NewFriendList == nil {
		f.NewFriendList = make(map[int]*FriendInfo)
	}
	if f.Bubble == nil {
		f.Bubble = make(map[int]*BubbleInfo)
	}
	if len(f.FriendList) > 0 && len(f.NewFriendList) == 0 {
		for k := range f.FriendList {
			f.NewFriendList[k] = &FriendInfo{
				AddTime: GoUtil.Now(),
			}
		}
	}
	if f.RecommendList == nil {
		f.RecommendList = make(map[int]*Recommend)
	}
}

// 零点更新
func (f *FriendMod) ZeroUpdate() {
	f.DailySponsor = f.GetDailySponsorLimit()
	f.DailyGetApply = 0
}

func (f *FriendMod) GetNpc() []int {
	return f.Npc
}

// 增加NPC好友
func (f *FriendMod) SetNpc(id int) error {
	if !friendCfg.IsNpcFriend(id) {
		return fmt.Errorf("not npc friend")
	}
	for _, v := range f.Npc {
		if v == id {
			return fmt.Errorf("npc already exist")
		}
	}
	f.Npc = append(f.Npc, id)
	return nil
}

func (f *FriendMod) GetSyncId() int64 {
	return f.Id
}

func (f *FriendMod) SetSyncId(Id int64) {
	f.Id = Id
}

// 好友交互
func (f *FriendMod) Interact(id, t int, T int64) {
	if _, ok := f.NewFriendList[id]; !ok {
		return
	}
	for _, v := range f.NewFriendList[id].Interact {
		if v.Type == t && v.VisitTime < T {
			v.VisitTime = T
			return
		}
	}
	f.NewFriendList[id].Interact = append(f.NewFriendList[id].Interact, &Interact{
		VisitTime: T,
		Type:      t,
	})
}

// 获取好友交互时间
func (f *FriendMod) GetInteractTime(id int) int64 {
	if _, ok := f.NewFriendList[id]; !ok {
		return 0
	}
	var LastTime int64
	// 获取最近一次拜访或点赞的时间
	for _, v := range f.NewFriendList[id].Interact {
		if v.VisitTime > LastTime {
			LastTime = v.VisitTime
		}
	}
	return LastTime
}

// 获取好友添加时间
func (f *FriendMod) GetAddTime(id int) int64 {
	if _, ok := f.NewFriendList[id]; !ok {
		return 0
	}
	return f.NewFriendList[id].AddTime
}

// 增加好友
func (f *FriendMod) AddFriend(id int) {
	f.NewFriendList[id] = &FriendInfo{
		AddTime: GoUtil.Now(),
	}
	delete(f.ApplyList, id)
}

// 获取卡牌交换信息
func (f *FriendMod) GetCardInfo(Id string) *card.CardInfo {
	v, ok := f.Card[Id]
	if !ok {
		return nil
	}
	return v
}

// 设置卡牌交换信息
func (f *FriendMod) SetCardInfo(CardInfo *card.CardInfo) {
	f.Card[CardInfo.Id] = CardInfo
}

// 删除卡牌交换信息
func (f *FriendMod) DelCardInfo(Id string) {
	delete(f.Card, Id)
}

// 删除好友
func (f *FriendMod) DelFriend(id int) {
	f.NewFriendList[id].DelTime = GoUtil.Now()
}

// 检查是否好友
func (f *FriendMod) CheckFriend(Uid int) bool {
	v, ok := f.NewFriendList[Uid]
	return ok && v.DelTime == 0
}

// 获取好友数量
func (f *FriendMod) GetFriendLen() int {
	return len(f.GetFriendList())
}

// 拒绝好友申请
func (f *FriendMod) RefuseApply(id int) {
	delete(f.ApplyList, id)
	delete(f.SendApply, id)
}

// 检查好友申请
func (f *FriendMod) CheckApply(id int) bool {
	_, ok := f.ApplyList[id]
	return ok
}
func (f *FriendMod) GetFriendNum() int {
	i := 0
	for _, v := range f.NewFriendList {
		if v.DelTime == 0 {
			i++
		}
	}
	return i
}

// 获取好友列表
func (f *FriendMod) GetFriendList() map[int]*FriendInfo {
	res := make(map[int]*FriendInfo)
	for k, v := range f.NewFriendList {
		if v.DelTime == 0 {
			res[k] = v
		}
	}
	return res
}

// 获取好友uid列表
func (f *FriendMod) GetSimpleFriendList() []int {
	rs := make([]int, 0, len(f.NewFriendList))
	for k, v := range f.NewFriendList {
		if v.DelTime != 0 {
			continue
		}
		rs = append(rs, k)
	}
	return rs
}

// 检查是否有新的好友
func (f *FriendMod) CheckAddBefore(uid int) bool {
	_, ok := f.NewFriendList[uid]
	return ok
}

// 收到申请
func (f *FriendMod) AddFriendApply(Uid int) bool {
	if f.DailyGetApply >= 30 {
		return true
	}
	f.ApplyList[Uid] = GoUtil.Now()
	f.DailyGetApply++
	return false
}

// 发送申请
func (f *FriendMod) AddSendApply(Uid int) bool {
	f.SendApply[Uid] = GoUtil.Now()
	return false
}

func (f *FriendMod) CheckSendApply(Id int) bool {
	_, ok := f.SendApply[Id]
	return ok
}

// 获取发送申请时间
func (f *FriendMod) GetSendApplyTime(Id int) int64 {
	if t, ok := f.SendApply[Id]; ok {
		return t
	}
	return 0
}

// 同意申请
func (f *FriendMod) AgreeApply(UId int) {
	f.AddFriend(UId)
	delete(f.SendApply, UId)
	delete(f.ApplyList, UId)
}

// 增加好友日志
func (f *FriendMod) AddLog(Uid, Type int, Param string) int {
	f.AutoId++
	f.Log = append(f.Log, &LogInfo{
		Id:    f.AutoId,
		Uid:   Uid,
		Type:  Type,
		Time:  GoUtil.Now(),
		Param: Param,
	})
	switch Type {
	case LOG_TYPE_HANDBOOK_UPVOTE, LOG_TYPE_PLAYROOM_UPVOTE:
		f.AddBubble(f.AutoId, Type, nil)
	case LOG_TYPE_TREASURE_HELP:
		ItemNum := GoUtil.RandNum(2, 5)
		ItemList := []*item.Item{item.NewItem(item.ITEM_STAR_ID, ItemNum)}
		f.AddBubble(f.AutoId, Type, ItemList)
	}
	if len(f.Log) > 30 {
		f.Log = f.Log[len(f.Log)-30:]
	}
	return f.AutoId
}

// 增加气泡
func (f *FriendMod) AddBubble(Id, Type int, ItemList []*item.Item) {
	f.Bubble[Id] = &BubbleInfo{
		Id:       Id,
		Time:     GoUtil.Now(),
		Type:     Type,
		ItemList: ItemList,
	}
}

// 获取气泡信息
func (f *FriendMod) GetBubble(Id int) *msg.FriendBubbleInfo {
	if v, ok := f.Bubble[Id]; ok {
		return &msg.FriendBubbleInfo{
			Id:    int32(v.Id),
			Type:  int32(v.Type),
			Items: item.ItemToMsg(v.ItemList),
		}
	}
	return nil
}

func (f *FriendMod) BubbleBackData() *msg.ResFriendBubble {
	rs := make([]*msg.FriendBubbleInfo, 0, len(f.Bubble))
	for _, v := range f.Bubble {
		rs = append(rs, &msg.FriendBubbleInfo{
			Id:    int32(v.Id),
			Type:  int32(v.Type),
			Items: item.ItemToMsg(v.ItemList),
		})
	}
	return &msg.ResFriendBubble{
		Bubble: rs,
	}
}

// 金卡限时事件结束后， 重置金卡交换请求
func (f *FriendMod) ResetGoldCardEx() {
	for _, v := range f.Card {
		if cardCfg.CheckCardIsGold(v.CardId) || cardCfg.CheckCardIsGold(v.ExId) {
			v.EndTime = 1
		}
	}
}

// 增加活动日志
func (f *FriendMod) AddActLog(Type int, Param string) {
	f.ActivityLog = append(f.ActivityLog, &ActLogInfo{
		Type:  Type,
		Time:  GoUtil.Now(),
		Param: Param,
	})
	if len(f.ActivityLog) > 20 {
		f.ActivityLog = f.ActivityLog[len(f.ActivityLog)-20:]
	}
}

// 时间线点赞
func (f *FriendMod) Upvote(Id int) ([]*item.Item, int, error) {
	info := &LogInfo{}
	for _, v := range f.Log {
		if v.Id == Id {
			info = v
			break
		}
	}
	if info.Id == 0 {
		return nil, 0, fmt.Errorf("log not exist")
	}
	if info.Upvote {
		return nil, 0, fmt.Errorf("already upvote")
	}
	info.Upvote = true
	return []*item.Item{item.NewItem(item.ITEM_ENERGY_ID, 5)}, info.Uid, nil
}

// 获取时间线点赞奖励
func (f *FriendMod) GetReward(Id int) ([]*item.Item, error) {
	info, ok := f.Bubble[Id]
	if !ok {
		return nil, fmt.Errorf("bubble not exist")
	}
	var reward []*item.Item
	switch info.Type {
	case LOG_TYPE_HANDBOOK_UPVOTE, LOG_TYPE_PLAYROOM_UPVOTE:
		reward = append(reward, item.NewItem(item.ITEM_ENERGY_ID, 5))
	case LOG_TYPE_TREASURE_HELP:
		reward = append(reward, info.ItemList...)
	default:
		return nil, fmt.Errorf("log type not support")
	}
	delete(f.Bubble, Id)
	return reward, nil
}

// 增加心愿单申请
func (f *FriendMod) AddWishApply(Uid int64) error {
	for _, v := range f.Apply {
		if v.Type == APPLY_TYPE_WISH && v.Uid == Uid {
			return fmt.Errorf("wish apply already exist")
		}
	}
	f.Apply = append(f.Apply, &ApplyInfo{
		Type: APPLY_TYPE_WISH,
		Uid:  Uid,
		Time: GoUtil.Now(),
	})
	return nil
}

// 获取心愿单申请列表
func (f *FriendMod) GetWishApply() []*ApplyInfo {
	var rs []*ApplyInfo
	for _, v := range f.Apply {
		if v.Type == APPLY_TYPE_WISH {
			rs = append(rs, v)
		}
	}
	return rs
}

// 同意心愿单申请
func (f *FriendMod) ApplyWish(Uid int64) error {
	for k, v := range f.Apply {
		if v.Type == APPLY_TYPE_WISH && v.Uid == Uid {
			f.Apply = append(f.Apply[:k], f.Apply[k+1:]...)
			return nil
		}
	}
	return fmt.Errorf("wish apply not exist")
}

// 获取最后一次活动日志
func (f *FriendMod) GetActLogLast() *ActLogInfo {
	if len(f.ActivityLog) == 0 {
		return nil
	}
	return f.ActivityLog[len(f.ActivityLog)-1]
}

// 增加待回复请求
func (f *FriendMod) AddReplyInfo(Uid int, Type int, Param string, EndTime int64, Items []*item.Item) *ReplyInfo {
	f.AutoId++
	ReplyInfo := &ReplyInfo{
		Id:      f.AutoId,
		Uid:     Uid,
		Type:    Type,
		Param:   Param,
		AddTime: GoUtil.Now(),
		EndTime: EndTime,
		Items:   Items,
	}
	f.ReplyList = append(f.ReplyList, ReplyInfo)
	return ReplyInfo
}

// 回复请求
func (f *FriendMod) ReplyFriend(LogId int) *ReplyInfo {
	for _, v := range f.ReplyList {
		if v.Id == LogId {
			v.Status = 1
			v.ReplyTime = GoUtil.Now()
			return v
		}
	}
	return nil
}

// 获取每日赞助次数
func (f *FriendMod) GetSponsor() int {
	return f.DailySponsor
}

// 获取每日赞助上限，随好友数量增加而减少
func (f *FriendMod) GetDailySponsorLimit() int {
	n := f.GetFriendNum()
	if n < 5 {
		return 3
	}
	if n <= 30 {
		return 2
	}
	return 1
}

// 获取好友赞助体力奖励
func (f *FriendMod) GetSponsorReward() ([]*item.Item, error) {
	if f.DailySponsor <= 0 {
		return nil, fmt.Errorf("no sponsor left")
	}
	f.DailySponsor--
	itemNum := friendCfg.GetFriendSponsorNum()
	return []*item.Item{item.NewItem(item.ITEM_ENERGY_ID, itemNum)}, nil
}

// 增加好友推荐记录
func (f *FriendMod) AddRecommend(Uid int) {
	now := GoUtil.Now()
	if v, ok := f.RecommendList[Uid]; ok {
		v.Time = now
		return
	}
	f.RecommendList[Uid] = &Recommend{
		Uid:  Uid,
		Time: now,
	}
}

// 获取好友推荐时间
func (f *FriendMod) GetRecommendTime(uid int) int64 {
	if recommend, ok := f.RecommendList[uid]; ok {
		return recommend.Time
	}
	return 0
}
