package card

import (
	"fmt"
	cardCfg "server/conf/card"
	"server/game/mod/item"
	GoUtil "server/game_util"
	"server/msg"
	"server/pkg/github.com/name5566/leaf/log"
)

type CardMod struct {
	CardList      map[int]int       // 卡牌列表
	ExchangeStar  int               // 兑换星星
	CollectReward map[int]struct{}  // 已领取奖励
	AllCollect    int               // 总共收集 0未领取， 1已领取
	CardLimit     bool              //卡牌节 限时活动
	EndTime       int64             //周期结束时间
	SeasonFirst   bool              //赛季首次奖励
	AllCard       map[int]int       //
	ExTimes       int               //置换次数
	ReqTimes      int               //请求次数
	GoldTimes     int               // 金卡次数
	ReqFriend     map[int]*CardInfo //今日已请求好友
	ExCard        map[int]*CardInfo // 交换卡牌
	Cache         Cache             // 缓存卡牌
	Round         int               // 轮次
	Handbook      map[int]int       // 图鉴
}

type Cache struct {
	Card     map[int]int
	Master   map[int]int
	Handbook map[int]int
	ExStar   int
}

const (
	MASTER_CARD_NORMAL = 6
	MASTER_CARD_GOLD   = 7
)

const (
	HANDBOOK_STATUS_IDLE = 1 // 未领取
	HANDBOOK_STATUS_GET  = 2 // 已领取
)

const (
	TYPE_CARD_GIVE = 1 // 请求卡牌
	TYPE_CARD_SEND = 2 // 赠送卡牌
	TYPE_CARD_EX   = 3 // 卡牌交换
)

const (
	STATUS_CARD_GIVE_1 = 1 // 请求中
	STATUS_CARD_GIVE_2 = 2 // 对方同意，等待领取
	STATUS_CARD_GIVE_3 = 3 // 请求已结束

	STATUS_CARD_SEND_1 = 1 // 赠送成功 等待领取

	STATUS_CARD_EX_1 = 1 // 发起交换
	STATUS_CARD_EX_2 = 2 // 选择卡牌交换
	STATUS_CARD_EX_3 = 3 // 交换成功，等待领取
)

type CardInfo struct {
	Id        string
	AUid      int
	BUid      int
	CardId    int
	ExId      int
	Type      int
	EndTime   int64
	StartTime int64
	Status    int
	Emoji     int
}

func (c *CardMod) InitData() {
	// 初始化数据
	if c.CardList == nil {
		c.CardList = make(map[int]int)
	}
	if c.CollectReward == nil {
		c.CollectReward = make(map[int]struct{})
	}
	if c.AllCard == nil {
		c.AllCard = make(map[int]int)
	}
	if c.ReqFriend == nil {
		c.ReqFriend = make(map[int]*CardInfo)
	}
	if c.ExCard == nil {
		c.ExCard = make(map[int]*CardInfo)
	}
	if c.Handbook == nil {
		c.Handbook = make(map[int]int)
	}
	if c.Cache.Card == nil {
		c.Cache.Card = make(map[int]int)
	}
	if c.Cache.Master == nil {
		c.Cache.Master = make(map[int]int)
	}
	if c.Cache.Handbook == nil {
		c.Cache.Handbook = make(map[int]int)
	}

	for k := range c.CardList {
		if _, ok := c.Handbook[k]; !ok {
			c.Handbook[k] = HANDBOOK_STATUS_IDLE
		}
	}
}

/*
*
卡牌系统-登录：赛季结束则重置
*/
func (c *CardMod) Login(ServerOpenTime int64) []*item.Item {
	Now := GoUtil.Now()
	Duration := cardCfg.GetCardDuration()
	HandbookItemNum := 0
	if c.EndTime < Now {
		c.CardList = make(map[int]int)
		c.ExchangeStar = 0
		c.CollectReward = make(map[int]struct{})
		c.AllCollect = 0
		c.EndTime = 0
		c.Round = 0
		for k, v := range c.Handbook {
			if v == HANDBOOK_STATUS_GET {
				continue
			}
			Round := cardCfg.GetRoundById(k)
			if Round < c.Round {
				continue
			}
			HandbookItemNum += cardCfg.GetStarById(k)
		}
		c.Handbook = make(map[int]int)
	}
	if c.EndTime == 0 {
		c.EndTime = ((Now-ServerOpenTime)/Duration+1)*Duration + ServerOpenTime
	}
	return []*item.Item{{Id: item.ITEM_ENERGY_ID, Num: HandbookItemNum}}
}

// 零点更新
func (c *CardMod) ZeroUpdate(ServerOpenTime int64) []*item.Item {
	c.ReqTimes = cardCfg.GetReqTimes()
	c.ExTimes = cardCfg.GetExTimes()
	c.GoldTimes = 2
	return c.Login(ServerOpenTime)
}

// 增加卡牌
func (c *CardMod) AddCard(Id int) {
	_, ok := c.CardList[Id]
	if ok {
		star := cardCfg.GetStarById(Id)
		c.ExchangeStar += star
		c.Cache.ExStar += star
		c.CardList[Id]++
	} else {
		c.CardList[Id] = 1
	}
	_, ok = c.Handbook[Id]
	if !ok {
		c.Handbook[Id] = HANDBOOK_STATUS_IDLE
		c.Cache.Handbook[Id] = 1
	}
	c.Cache.Card[Id]++
}

// 开启卡包
func (c *CardMod) OpenCardPack(Star int) ([]int, error) {
	cardId := 0
	newCard := make([]int, 0)
	cnt := cardCfg.GetPackRewardCnt(Star)
	if cnt == 0 {
		return newCard, fmt.Errorf("open star %d card pack cfg err cnt == 0", Star)
	}

	mustHaveStar := cardCfg.GetPackMustHave(Star)
	if mustHaveStar != 0 {
		cardId = randCard(c.Round, mustHaveStar, 0, newCard)
		if cardId == 0 {
			return newCard, fmt.Errorf("OpenCardPack card id err, mustHaveStar: %d", mustHaveStar)
		}
		newCard = append(newCard, cardId)
		c.AddCard(cardId)
		cnt--
	}
	if c.CardLimit { // 卡牌节获得额外的卡牌 获得卡包原本卡牌数50%（向下取整且至少为1）张额外卡牌
		total := cnt + len(newCard)
		Extra := max(1, int(total/2))
		cnt += Extra
	}
	randList := cardCfg.GetRandListByStar(Star)
	for i := 0; i < cnt; i++ {
		CardStar := GoUtil.RandMap(randList)
		switch CardStar {
		case 5: //  四星金
			cardId = randCard(c.Round, 4, 1, newCard)
		case 6: // 五星
			cardId = randCard(c.Round, 5, 0, newCard)
		case 7: // 五星金
			cardId = randCard(c.Round, 5, 1, newCard)
		default:
			cardId = randCard(c.Round, CardStar, 0, newCard)
		}
		if cardId == 0 {
			return newCard, fmt.Errorf("OpenCardPack card id err, CardStar: %d", CardStar)
		}
		newCard = append(newCard, cardId)
		c.AddCard(cardId)
	}
	// 开卡包
	return newCard, nil
}

// cleanExpired 清理过期的请求和交换记录，返回有效 uid 列表
func (c *CardMod) cleanExpired() (reqUid, exUid []int64) {
	Now := GoUtil.Now()
	reqUid = make([]int64, 0, len(c.ReqFriend))
	for k, v := range c.ReqFriend {
		if v.EndTime < Now {
			delete(c.ReqFriend, k)
			continue
		}
		reqUid = append(reqUid, int64(k))
	}
	exUid = make([]int64, 0, len(c.ExCard))
	for k, v := range c.ExCard {
		if v.EndTime < Now {
			delete(c.ExCard, k)
			continue
		}
		exUid = append(exUid, int64(k))
	}
	return
}

// 协议返回
func (c *CardMod) BackData() *msg.ResCardInfo {
	var cardList []*msg.Card
	for k, v := range c.CardList {
		if v <= 0 {
			continue
		}
		cardList = append(cardList, &msg.Card{Id: int32(k), Count: int32(v)})
	}
	ReqUid, ExUid := c.cleanExpired()

	if c.EndTime < GoUtil.Now() {
		log.Debug("CardMod BackData EndTime < Now, reset card data")
	}
	return &msg.ResCardInfo{
		CardList:    cardList,
		ExStar:      int32(c.ExchangeStar),
		Status:      int32(c.AllCollect),
		CollectId:   GoUtil.MapIntToSlice(c.CollectReward),
		EndTime:     int32(c.EndTime),
		ExTimes:     int32(c.ExTimes),
		ReqTimes:    int32(c.ReqTimes),
		AllCard:     GoUtil.MapIntToInt32(c.AllCard),
		ReqUid:      ReqUid,
		ExUid:       ExUid,
		Round:       int32(c.Round),
		Handbook:    GoUtil.MapIntToInt32(c.Handbook),
		SeasonFirst: c.SeasonFirst,
	}
}

// 领取卡牌收集奖励
func (c *CardMod) GetCollectReward(Id int) ([]*item.Item, int, error) {
	_, ok := c.CollectReward[Id]
	if ok {
		return nil, 0, fmt.Errorf("CollectReward id:%d already collect", Id)
	}
	cardList := cardCfg.GetCardListByColor(Id)
	for _, v := range cardList {
		count, ok := c.CardList[v]
		if !ok || count <= 0 {
			return nil, 0, fmt.Errorf("card not collect all ,id : %d", Id)
		}
	}
	c.CollectReward[Id] = struct{}{}
	Item, Chess := cardCfg.GetCollectReward(Id)
	return Item, Chess, nil
}

// 兑换星星奖励
func (c *CardMod) ExStarReward(Id int) ([]*item.Item, int, error) {
	if c.ExchangeStar < Id {
		return nil, 0, fmt.Errorf("ExStarReward star not enough, Id: %d", Id)
	}
	CostStar, itemList := cardCfg.GetExchangeCfg(Id)
	if c.ExchangeStar < CostStar {
		return nil, 0, fmt.Errorf("ExStarReward star not enough, Id: %d", Id)
	}
	c.ExchangeStar -= CostStar
	c.Cache.ExStar -= CostStar
	return itemList, CostStar, nil
}

// 领取全收集奖励
func (c *CardMod) AllCollectReward() ([]*item.Item, []*item.Item, error) {
	if c.AllCollect == 1 {
		return nil, nil, fmt.Errorf("AllCollectReward already collect")
	}
	AllCardId := cardCfg.GetAllCardId(c.Round)
	for _, v := range AllCardId {
		count, ok := c.CardList[v]
		if !ok || count <= 0 {
			return nil, nil, fmt.Errorf("card not fully collect for all collect reward, card id : %d", v)
		}
	}
	c.AllCollect = 0
	c.CollectReward = make(map[int]struct{})
	ExStar := 0
	for k, v := range c.CardList {
		star := cardCfg.GetStarById(k)
		ExStar += star * (v - 1)
		c.CardList[k] = v - 1
	}
	c.CardList = make(map[int]int)
	c.ExchangeStar += ExStar
	c.Cache.ExStar += ExStar
	Item := cardCfg.GetAllCollectReward()
	HandbookItemNum := 0
	for k, v := range c.Handbook {
		if v == HANDBOOK_STATUS_GET {
			continue
		}
		HandbookItemNum += cardCfg.GetStarById(k)
	}
	c.Round++
	c.Handbook = make(map[int]int)
	return Item, []*item.Item{{Id: item.ITEM_ENERGY_ID, Num: HandbookItemNum}}, nil
}

func (c *CardMod) ResetCardFestival() {
	c.CardLimit = false
}

func (c *CardMod) GetCardFestival() bool {
	return c.CardLimit
}

func (c *CardMod) CreateCardFestival() {
	c.CardLimit = true
}

func (c *CardMod) GetCardNum(Card int) int {
	return c.CardList[Card]
}

func (c *CardMod) SubCard(id int) error {
	count, ok := c.CardList[id]
	if ok && count > 0 {
		c.CardList[id]--
		c.Cache.Card[id]--
		return nil
	}
	return fmt.Errorf("SubCard card not enough, id: %d", id)
}

func (c *CardMod) RequestCard() error {
	if c.ReqTimes <= 0 {
		return fmt.Errorf("RequestCard times not enough")
	}
	c.ReqTimes--
	return nil
}

// 增加请求卡牌记录
func (c *CardMod) AddRequestCard(CardInfo *CardInfo) error {
	_, ok := c.ReqFriend[CardInfo.BUid]
	if ok {
		return fmt.Errorf("AddRequestCard already request card to this friend, BUid: %d", CardInfo.BUid)
	}
	c.ReqFriend[CardInfo.BUid] = CardInfo
	return nil
}

func (c *CardMod) DelRequestCard(Uid int) (map[int]*CardInfo, error) {
	ci, ok := c.ReqFriend[Uid]
	if !ok {
		return nil, fmt.Errorf("DelRequestCard not find request card, Uid: %d", Uid)
	}
	r := make(map[int]*CardInfo)
	for k, v := range c.ReqFriend {
		if v.Id == ci.Id && v.BUid != ci.BUid {
			r[k] = v
			continue
		}
	}
	delete(c.ReqFriend, Uid)
	return r, nil
}

func (c *CardMod) AddReqTimes(Id string, Time int64) {
	n := 0
	for _, v := range c.ReqFriend {
		if v.Id == Id {
			n++
		}
	}
	Zero := GoUtil.ZeroTime(Time)
	ZeroTime := GoUtil.ZeroTimestamp()
	if n == 0 && Zero == ZeroTime {
		c.ReqTimes = min(cardCfg.GetReqTimes(), c.ReqTimes+1)
	}

}

func (c *CardMod) AddExTimes(CardInfo *CardInfo) {
	Zero := GoUtil.ZeroTime(CardInfo.StartTime)
	ZeroTime := GoUtil.ZeroTimestamp()
	if Zero == ZeroTime {
		c.ExTimes++
		c.ExTimes = min(cardCfg.GetExTimes(), c.ExTimes)
	}
	if cardCfg.CheckCardIsGold(CardInfo.CardId) {
		c.GoldTimes--
	}

}

// 交换卡牌
func (c *CardMod) ExchangeCard(From, To, CardId int) (*CardInfo, error) {
	if c.ExTimes <= 0 {
		return nil, fmt.Errorf("ExchangeCard times not enough, CardId: %d", CardId)
	}
	err := c.SubCard(CardId)
	if err != nil {
		return nil, err
	}
	c.ExTimes--
	Now := GoUtil.Now()
	Id := GoUtil.CreateCardId(From, To, CardId)
	CardInfo := &CardInfo{
		Id:        Id,
		AUid:      From,
		BUid:      To,
		CardId:    CardId,
		Type:      TYPE_CARD_EX,
		Status:    STATUS_CARD_EX_1,
		StartTime: Now,
		EndTime:   Now + 86400,
	}
	c.ExCard[To] = CardInfo
	return CardInfo, nil
}

func (c *CardMod) SendCard(From, To, CardId int) (*CardInfo, error) {
	if c.ExTimes <= 0 {
		return nil, fmt.Errorf("SendCard times not enough, CardId: %d", CardId)
	}
	err := c.SubCard(CardId)
	if err != nil {
		return nil, err
	}
	c.ExTimes--
	Now := GoUtil.Now()
	Id := GoUtil.CreateCardId(From, To, CardId)
	CardInfo := &CardInfo{
		Id:        Id,
		AUid:      From,
		BUid:      To,
		CardId:    CardId,
		Type:      TYPE_CARD_SEND,
		StartTime: Now,
		Status:    STATUS_CARD_SEND_1,
	}
	return CardInfo, nil
}

func (c *CardMod) DelExCard(CardInfo *CardInfo) {
	delete(c.ExCard, CardInfo.BUid)
}

func (c *CardMod) AddMasterCard(Id int) {
	c.Cache.Master[Id]++
	c.AllCard[Id]++
}

func (c *CardMod) MasterCardEx(Id, CardId int) error {
	if c.AllCard[Id] <= 0 {
		return fmt.Errorf("MasterCardEx card not enough, Id: %d", Id)
	}
	if Id == MASTER_CARD_NORMAL && cardCfg.CheckCardIsGold(CardId) {
		return fmt.Errorf("MasterCardEx card type err, Id: %d, CardId: %d", Id, CardId)
	}
	c.AllCard[Id]--
	c.Cache.Master[Id]--
	c.AddCard(CardId)
	return nil
}

func (c *CardMod) NotifyCard() *msg.ResNotifyCard {
	m := &msg.ResNotifyCard{
		Card:     GoUtil.MapIntToInt32(c.Cache.Card),
		Master:   GoUtil.MapIntToInt32(c.Cache.Master),
		Handbook: GoUtil.MapIntToInt32(c.Cache.Handbook),
		ExStar:   int32(c.Cache.ExStar),
	}
	// log.Debug("NotifyCard %v", c.Cache.Card)
	c.Cache = Cache{
		Card:     make(map[int]int),
		Master:   make(map[int]int),
		Handbook: make(map[int]int),
	}
	return m
}

func (c *CardMod) NotifyTimes() *msg.ResNotifyCardTimes {
	ReqUid, ExUid := c.cleanExpired()
	return &msg.ResNotifyCardTimes{
		ExTimes:   int32(c.ExTimes),
		ReqTimes:  int32(c.ReqTimes),
		ExUid:     ExUid,
		ReqUid:    ReqUid,
		GoldTimes: int32(c.GoldTimes),
	}
}

func (c *CardMod) ResetGoldCardEx() {
	for k, v := range c.ExCard {
		if cardCfg.CheckCardIsGold(v.CardId) {
			delete(c.ExCard, k)
		}
		if GoUtil.ZeroTime(v.StartTime) == GoUtil.ZeroTimestamp() {
			c.ExTimes++
		}
	}
}

func (c *CardMod) SubGoldTimes() error {
	if c.GoldTimes <= 0 {
		return fmt.Errorf("SubGoldTimes times not enough")
	}
	c.GoldTimes--
	return nil
}

func (c *CardMod) AddGoldTimes() {
	c.GoldTimes++
	c.GoldTimes = min(2, c.GoldTimes)
}

func (c *CardMod) GetHandbookReward(CardId int) ([]*item.Item, error) {
	if v, ok := c.Handbook[CardId]; ok {
		if v == HANDBOOK_STATUS_GET {
			return nil, fmt.Errorf("GetHandbookReward already get reward, CardId: %d", CardId)
		}
		Star := cardCfg.GetStarById(CardId)
		c.Handbook[CardId] = HANDBOOK_STATUS_GET
		c.Cache.Handbook[CardId] = HANDBOOK_STATUS_GET
		return []*item.Item{item.NewItem(item.ITEM_ENERGY_ID, Star)}, nil
	}
	return nil, fmt.Errorf("GetHandbookReward not find card in handbook, CardId: %d", CardId)
}

func (c *CardMod) RandCard(Star int) int {
	return randCard(c.Round, Star, 0, []int{})
}

func (c *CardMod) SeasonFirstReward() ([]*item.Item, error) {
	if c.SeasonFirst {
		return nil, fmt.Errorf("SeasonFirstReward already get reward")
	}
	c.SeasonFirst = true
	return cardCfg.GetSeasonFirstReward(), nil
}

func (c *CardMod) GetCardList() []int {
	cardList := make([]int, 0, len(c.CardList))
	for k, v := range c.CardList {
		if v > 0 {
			cardList = append(cardList, k)
		}
	}
	return cardList
}
