package model

import (
	"fmt"
	"strconv"

	"time"

	"github.com/spf13/cast"
	"xorm.io/xorm"
)

// MailStatus 表示邮件状态
type MailStatus int

const (
	MailStatusUnread MailStatus = iota
	MailStatusRead
	MailStatusClaimed
)

// 邮件文案类型
const (
	MailTypeRank           = 2
	MailTypeChapterLost    = 3
	MailTypeEnergy         = 4
	MailTypeMonthCardAward = 5
	MailTypeWarOrderAward  = 6
	MailTypeShop           = 7 //支付购买
	MailType7DayChallenge  = 8
	MailTypeInviteeReward  = 9  //被邀请奖励
	MailTypeOfflineStamina = 10 //离线体力
	MailTypeFirstCharge    = 11 //首充奖励
	MailTypeDailyDeal      = 12 //每日特惠
	MailTypeWeekTask       = 13 //周任务奖励
)

type MailPersonal struct {
	Id          int64
	PlayerId    int64             `xorm:"BIGINT index 'playerId'"`
	MailType    int64             `xorm:"Int 'type'"` //排行奖励
	Title       string            `xorm:"Varchar(255) 'title'"`
	Content     string            `xorm:"Varchar(1024) 'content'"`
	Extra       []*DropedItem     `xorm:"Text json 'extra'"`
	ExtraInfo   map[string]string `xorm:"Text 'extraInfo'"`
	Sender      string            `xorm:"Varchar(255) 'sender'"`
	CreateTime  time.Time         `xorm:"created"`
	DisplayTime time.Time         `xorm:"displayTime"`
	ExpireTime  time.Time         `xorm:"Varchar(255) 'expireTime'"`
	Status      MailStatus        `xorm:"Varchar(255) 'status'"`

	// Extra       ExtraData `xorm:"Text json 'extra'"`
	// ExtraInfo   string    `xorm:"Text 'extraInfo'"`
	// DisplayTime time.Time `xorm:"displayTime"`
	// CreateTime  time.Time `xorm:"created"`
	// ExpireTime  time.Time `xorm:"DateTime 'expireTime'"`
	// ViewState   int       `xorm:"Int default(0) 'viewState'"` //阅读状态
	// DrawState   int       `xorm:"Int default(0) 'drawState'"` // 领取状态
}

func (m *MailPersonal) TableName() string {
	return "mailpersonal"
}

// val只能是string、int等通过 cast.ToString可以转换成string的类型
func (m *MailPersonal) SetExtraInfo(key string, val any) {
	if m.ExtraInfo == nil {
		m.ExtraInfo = make(map[string]string)
	}
	m.ExtraInfo[key] = cast.ToString(val)
}

func (m *MailPersonal) GetExtraInfo(key string) string {
	return m.ExtraInfo[key]
}

func NewMailPersonal(playerId int64, mailType int64, lst []*DropedItem) *MailPersonal {
	lettle := new(MailPersonal)
	lettle.PlayerId = playerId
	lettle.MailType = mailType
	if len(lst) > 0 {
		lettle.Extra = append(lettle.Extra, lst...)
	}

	var expire time.Duration
	lettle.CreateTime = time.Now()
	if len(lst) > 0 {
		expire = time.Hour * 24 * 30
	} else {
		expire = time.Hour * 24 * 7
	}
	lettle.ExpireTime = lettle.CreateTime.Add(expire)
	return lettle
}

// type LetterExtraInfo struct {
// 	Level   int    `json:"level"`
// 	Rank    int    `json:"rank"`
// 	ActName string `json:"functionName"`
// }

type DropedItem struct {
	Id   int64 `json:"id"`
	Type int64 `json:"type"`
	Num  int64 `json:"num"`
}

func SumDropedItem2(items map[string]*DropedItem, typ int64, id int64, num int64) {
	key := fmt.Sprintf("%v:%v", id, typ)

	if it, ok := items[key]; ok {
		it.Num += num
	} else {
		it := new(DropedItem)
		it.Id = id
		it.Type = typ
		it.Num = num
		items[key] = it
	}
}

func SumDropedMaterial(items map[int64]int64, news map[int64]int64) {
	for k, v := range news {
		items[k] += v
	}
}

func GetMapKeys[K comparable, V any](items map[K]V) []K {
	if len(items) == 0 {
		return nil
	}
	lst := make([]K, 0, len(items))
	for k := range items {
		lst = append(lst, k)
	}
	return lst
}

func GetMapValues[K comparable, V any](items map[K]V) []V {
	if len(items) == 0 {
		return nil
	}
	lst := make([]V, 0, len(items))
	for _, v := range items {
		lst = append(lst, v)
	}
	return lst
}

type LevelReward struct {
	Level     int64           `json:"level"`
	Exp       int64           `json:"exp"`
	Materials map[int64]int64 `json:"materials"`
}

type DropedBundle struct {
	Materials      map[int64]int64             `json:"materials"`
	Heros          map[int64]*GrowableHero     `json:"heros"`
	Treasures      map[int64]*GrowableTreasure `json:"treasures"`
	Runes          map[int64]*BagRune          `json:"runes"`
	Legends        map[int64]int64             `json:"legends"`
	EmojisIds      []int64                     `json:"emojisIds"`
	LevelMaterials LevelReward                 `json:"levelMaterials"`
	HeroSkins      []int64                     `json:"heroSkins"`
	Converts       map[int64]int64             `json:"-"` // 辅助查看，已统计到Materials
}

func NewDropedBundle() *DropedBundle {
	pi := new(DropedBundle)
	pi.Materials = make(map[int64]int64)
	pi.Heros = make(map[int64]*GrowableHero)
	pi.Treasures = make(map[int64]*GrowableTreasure)
	pi.Runes = make(map[int64]*BagRune)
	pi.Legends = make(map[int64]int64)
	pi.LevelMaterials.Materials = make(map[int64]int64)
	pi.Converts = make(map[int64]int64)
	return pi
}

func (pi *DropedBundle) SumMaterial(news map[int64]int64) {
	for k, v := range news {
		pi.Materials[k] += v
	}
}

func (pi *DropedBundle) SumConvert(news map[int64]int64) {
	for k, v := range news {
		pi.Converts[k] += v
	}
}

func (pi *DropedBundle) SumHero(news map[int64]*GrowableHero) {
	for k, v := range news {
		pi.Heros[k] = v
	}
}

func (pi *DropedBundle) SumTreasure(news map[int64]*GrowableTreasure) {
	for k, v := range news {
		pi.Treasures[k] = v
	}
}

func (pi *DropedBundle) SumRune(news map[int64]*BagRune) {
	for k, v := range news {
		pi.Runes[k] = v
	}
}

func (pi *DropedBundle) SumLegend(news map[int64]int64) {
	for k, v := range news {
		pi.Legends[k] += v
	}
}

func (pi *DropedBundle) SumLevelMaterial(news map[int64]int64) {
	for k, v := range news {
		pi.LevelMaterials.Materials[k] += v
	}
}

func (pi *DropedBundle) SumEmojisId(ids ...int64) {
	pi.EmojisIds = append(pi.EmojisIds, ids...)
}

func (pi *DropedBundle) GetMaterialNum(id int64) int64 {
	return pi.Materials[id]
}

func (pi *DropedBundle) SumHeroSkin(skinId int64) {
	pi.HeroSkins = append(pi.HeroSkins, skinId)
}

// func (pi *DropedBundle) SumHeadId(ids ...int64) {
// 	pi.HeadIds = append(pi.HeadIds, ids...)
// }

// func (pi *DropedBundle) SumHeadFrameId(ids ...int64) {
// 	pi.HeadFrameIds = append(pi.HeadFrameIds, ids...)
// }

// func (pi *DropedBundle) SumChatFrameId(ids ...int64) {
// 	pi.ChatFrameIds = append(pi.ChatFrameIds, ids...)
// }

// func (m *Letter) QueryExist(eng *xorm.Engine) (bool, error) {
// 	return false, nil
// }

// // 邮件立即插入，不是延迟插入
// func (m *Letter) UpdateDB(eng *xorm.Engine) (int64, error) {

// 	return eng.Where("playerid=?", m.PlayerId).MustCols("materials", "equipments", "calcItems", "startTick", "timeLen").Update(m)
// }

// func CopyLetter(old *Letter) *Letter {
// 	new1, err := deepcopy.Copy(old)
// 	if err != nil {
// 		return nil
// 	}
// 	return new1.(*Letter)
// }

type MailGlobal struct {
	Id          int64
	MailType    int64             `xorm:"Int 'type'"`
	MaxPlayerId int64             `xorm:"BIGINT 'maxPlayerId'"`
	Title       string            `xorm:"Varchar(255) 'title'"`
	Content     string            `xorm:"Varchar(1024) 'content'"`
	Extra       []*DropedItem     `xorm:"Text json 'extra'"`
	ExtraInfo   map[string]string `xorm:"Text 'extraInfo'"`
	CreateTime  time.Time         `xorm:"created"`
	ExpireTime  time.Time         `xorm:"DateTime 'expireTime'"`

	//
}

func (m *MailGlobal) TableName() string {
	return "mailglobal"
}

// 邮箱
type MailPlayer struct {
	Id           int64
	PlayerId     int64           `xorm:"BIGINT index 'playerId'"`
	LastGlobalId int64           `xorm:"BIGINT 'lastGlobalId'"`
	LastLoadTick int64           `xorm:"-"`
	Letters      []*MailPersonal `xorm:"-"`
}

func (m *MailPlayer) TableName() string {
	return "mailplayer"
}

func (m *MailPlayer) QueryExist(eng *xorm.Engine) (bool, error) {
	q := new(MailPlayer)
	q.PlayerId = m.PlayerId
	return eng.Exist(q)
}

func (m *MailPlayer) UpdateDB(eng *xorm.Engine) (int64, error) {
	return eng.Where("playerid=?", m.PlayerId).MustCols("lastGlobalId").Update(m)
}

func (m *MailPlayer) GetUniqueKey() string {
	return strconv.FormatInt(m.PlayerId, 10)
}

func (m *MailPlayer) IsDirty() bool {
	return (m.LastLoadTick == -1)
}

func CopyMailBox(old *MailPlayer) *MailPlayer {
	newIt := new(MailPlayer)
	*newIt = *old
	newIt.Letters = nil

	return newIt
}

// 邮件-Mail exported from 邮件.xlsx
type Mail struct {
	Type    int64  `json:"Type"`    // 邮件类型 1-后台邮件
	Title   string `json:"Title"`   // 标题
	Content string `json:"Content"` // 内容
}
