package limitedTimeEvent

import (
	"fmt"
	"math"
	limitedTimeEventCfg "server/conf/limited_time_event"
	mergeDataCfg "server/conf/merge_data"
	"server/game/mod/item"
	"server/game/mod/order"
	GoUtil "server/game_util"
	"server/msg"
)

const (
	EVENT_TYPE_HIGH_ROLLER       = 1  // high roller
	EVENT_TYPE_SUPER_EMIT        = 2  // 超级发射器
	EVENT_TYPE_METEOR_SHOW       = 3  // 流星雨
	EVENT_TYPE_CHEST_RAIN        = 4  // 宝箱雨
	EVENT_TYPE_SUPER_ORDER       = 5  // 超级订单
	EVENT_TYPE_SENCE_DASH        = 6  // 场景冲刺
	EVENT_TYPE_CARD_FESTIVAL     = 7  // 卡牌节
	EVENT_TYPE_GOLDCARD_EX       = 8  // 金卡交换
	EVENT_TYPE_PET_THIEF         = 9  // 宠物小偷
	EVENT_TYPE_FAST_PRODUCE      = 10 // 连击快手
	EVENT_TYPE_CAT_CYCLONE       = 11 // 猫咪飓风
	EVENT_TYPE_MONEY_CAT         = 12 // 招财猫
	EVENT_TYPE_LUCKY_CAT         = 13 // 幸运猫
	EVENT_TYPE_CAT_TRICK         = 14 // 猫咪戏法
	EVENT_TYPE_PAYBACK_DAY       = 15 // 回收日
	EVENT_TYPE_LITTLE_APPRENTICE = 16 // 小学徒
	EVENT_TYPE_CAT_DAY_SALE      = 17 // 猫咪大甩卖
	EVENT_TYPE_DECORATE_OFF      = 18 // 装饰打折
)

const (
	EVENT_NOTIFY_TYPE_ADD = 0
	EVENT_NOTIFY_TYPE_DEL = 1
)

type LimitedTimeEventMod struct {
	EventList      map[int]*LTEInfo
	Triggered      map[int]struct{}
	Progress       int
	ProgressReward map[int]int
	LastSelect     int
	Lv             int // 玩家等级 零点更新
	ProgressMax    int
	LastOption     []int
	BonusNum       int
	First          bool
	FirstReward    bool
	CatDaySale     bool  // 是否参与猫咪大甩卖活动
	LastCatDaySale int64 // 上次开启猫咪大甩卖时间
}

type LTEInfo struct {
	StartT int64                  // 开始时间
	Remian int64                  // 剩余时间
	Info   map[string]interface{} // 事件信息
	D      interface{}
}

type MoneyCat struct {
	Id      int
	EndTime int64
	Mul     float64
}

type LuckyCat struct {
	Earnings   int
	MaxEarings int
}

type CatTrick struct {
	List   []CatTrickInfo
	Energy int
}

type CatTrickInfo struct {
	Id   int
	Type int
}

type PaybackDay struct {
	Count int
}

func (l *LimitedTimeEventMod) InitData(Lv int) {
	if l.EventList == nil {
		l.EventList = make(map[int]*LTEInfo)
	}
	if l.Triggered == nil {
		l.Triggered = make(map[int]struct{})
	}
	if l.ProgressReward == nil {
		// 初始化进度奖励
		l.ProgressReward = make(map[int]int)

	}
	if l.ProgressMax == 0 {
		l.Lv = Lv
		l.ProgressMax = limitedTimeEventCfg.GetProgressMax(Lv, l.BonusNum)
	}
	if !l.First {
		l.First = true
		EventId := limitedTimeEventCfg.GetFirstEvent()
		l.ProgressMax = 0
		l.ProgressReward = map[int]int{
			1: EventId,
		}
		l.LastOption = []int{EventId}
	}
	if !l.FirstReward {
		l.ProgressMax = 0
	}

	if len(l.ProgressReward) == 0 {
		SelectNum := limitedTimeEventCfg.GetProgressSelectNum(Lv)
		BonusLv := limitedTimeEventCfg.GetBonusLv(Lv)
		RandMap := limitedTimeEventCfg.GetProgressRewardRand(BonusLv)
		l.fillProgressReward(RandMap, SelectNum)
	}
}

func (l *LimitedTimeEventMod) ZeroUpdate(Lv int) {
	if !l.FirstReward {
		return
	}
	l.Lv = Lv
	l.BonusNum = 0
	l.ProgressMax = limitedTimeEventCfg.GetProgressMax(Lv, l.BonusNum)
}

// 判断限时事件是否存在
func (l *LimitedTimeEventMod) CheckExist(EventId int) bool {
	info, ok := l.EventList[EventId]
	if !ok {
		return false
	}

	return GoUtil.Now() <= info.StartT+info.Remian
}

// 触发限时事件
func (l *LimitedTimeEventMod) Trigger(Lv int) (int, []int, []int) {
	if Lv < 4 {
		return 0, nil, nil
	}
	TriggerEvent := limitedTimeEventCfg.GetLimitedTimeEventCfg()
	TimeoutEvent := make([]int, 0)
	AddEvent := make([]int, 0)
	Now := GoUtil.Now()

	for _, v := range TriggerEvent {
		if _, ok := l.Triggered[v.Id]; ok { //不重复触发
			continue
		}
		if info, ok := l.EventList[v.EventId]; ok {
			info.Remian += int64(v.Duration)
		} else {
			LTEInfo := &LTEInfo{
				StartT: Now,
				Remian: int64(v.Duration),
			}
			initEventInfo(LTEInfo, v.EventId)
			l.EventList[v.EventId] = LTEInfo
			AddEvent = append(AddEvent, v.EventId)
		}
		l.Triggered[v.Id] = struct{}{}
	}

	Remain := 0
	//删除过期事件
	for k, v := range l.EventList {
		EndTime := v.StartT + v.Remian
		if k == EVENT_TYPE_CAT_TRICK {
			EndTime += 5 * 60 // 猫咪戏法事件显示时间为5分钟
		}
		if EndTime <= Now {
			delete(l.EventList, k)
			TimeoutEvent = append(TimeoutEvent, k)
			continue
		}
		NowRemain := (v.StartT + v.Remian) - Now
		if Remain > 0 {
			Remain = min(Remain, int(NowRemain))
		} else {
			Remain = int(NowRemain)
		}
	}
	return Remain, TimeoutEvent, AddEvent
}

// 增加限时事件
func (l *LimitedTimeEventMod) AddEvent(EventId, Duration int) int64 {
	v, ok := l.EventList[EventId]
	if EventId == EVENT_TYPE_CAT_DAY_SALE {
		l.LastCatDaySale = GoUtil.Now()
	}
	if ok && v.StartT+v.Remian > GoUtil.Now() {
		// 事件未过期
		v.Remian += int64(Duration)
		addEventInfo(v, EventId, Duration)
	} else {
		Event := &LTEInfo{
			Remian: int64(Duration),
			StartT: GoUtil.Now(),
		}
		initEventInfo(Event, EventId)
		l.EventList[EventId] = Event
	}
	return l.EventList[EventId].Remian + l.EventList[EventId].StartT
}

// 每周刷新
func (l *LimitedTimeEventMod) WeekUpdate() {
	l.Triggered = make(map[int]struct{})
}

func (l *LimitedTimeEventMod) GetMoneyCatReward(ChessList []int) []*item.Item {
	L := l.EventList[EVENT_TYPE_MONEY_CAT]
	if L == nil {
		return nil
	}
	Star := mergeDataCfg.GetMergeStar(ChessList)
	d := L.D.(*MoneyCat)
	mul := d.Mul

	MaxId := limitedTimeEventCfg.GetMoneyCatMax()
	NextId := min(d.Id+1, MaxId)
	NextMul, Cd := limitedTimeEventCfg.GetMoneyCat(NextId)
	d.Id = NextId
	d.Mul = NextMul
	d.EndTime = GoUtil.Now() + int64(Cd)
	Star = int(math.Ceil(float64(Star) * (mul - 1)))

	return []*item.Item{{Id: item.ITEM_STAR_ID, Num: Star}}
}

func (l *LimitedTimeEventMod) BackData() *msg.ResLimitEvent {
	Res := &msg.ResLimitEvent{}
	EventList := make(map[int32]*msg.LimitEvent)
	for k, v := range l.EventList {
		EventList[int32(k)] = getLimitEventMsg(k, v)
	}
	Res.LimitEventList = EventList
	return Res
}

func (l *LimitedTimeEventMod) ProgressBackData() *msg.ResLimitEventProgress {
	r := make(map[int32]int32)
	for k, v := range l.ProgressReward {
		Type := limitedTimeEventCfg.GetProgressRewardType(v)
		r[int32(k)] = int32(Type)
	}
	return &msg.ResLimitEventProgress{
		Progress:       int32(l.Progress),
		ProgressReward: r,
		ProgressMax:    int32(l.ProgressMax),
	}
}

// 获取流星雨奖励
func (l *LimitedTimeEventMod) GetMeteorReward(MergeList, EmitList []int) []*item.Item {
	energy := order.GetVirtualEnergy(MergeList, EmitList)
	NewStar := int(max(math.Ceil(float64(energy)/0.36*0.1), 1))
	return []*item.Item{{Id: item.ITEM_STAR_ID, Num: NewStar}}
}

// 获取宝箱雨奖励
func (l *LimitedTimeEventMod) GetChestReward(MergeList, EmitList []int) []*item.Item {
	energy := order.GetVirtualEnergy(MergeList, EmitList)
	star := math.Ceil(float64(energy) / 10 / 2.5)
	return []*item.Item{item.NewItem(item.ITEM_DIAMOND_ID, int(star))}
}

// 获取场景冲刺奖励
func (l *LimitedTimeEventMod) GetSceneDashReward() (int, []*item.Item) {
	ProbList := limitedTimeEventCfg.GetSenceJackpotProb()
	Id := GoUtil.RandMap(ProbList)
	Items := limitedTimeEventCfg.GetSenceJackpotReward(Id)
	if len(Items) > 1 {
		// 多个奖励时，随机选择一个
		Items = []*item.Item{GoUtil.RandItem(Items)}
	}
	return Id, Items
}

// 获取连击快手奖励
func (l *LimitedTimeEventMod) GetFastProduceReward(Energy int) ([]*item.Item, error) {
	Event, ok := l.EventList[EVENT_TYPE_FAST_PRODUCE]
	if !ok {
		return nil, fmt.Errorf("FastProduce event not exist")
	}

	Now := GoUtil.Now()
	if Now < GoUtil.Int64(Event.Info["NextPlay"]) {
		return nil, fmt.Errorf("FastProduce CD")
	}
	return limitedTimeEventCfg.GetFastProduceReward(Energy), nil
}

func (l *LimitedTimeEventMod) ResetFastProduceCD() {
	Event, ok := l.EventList[EVENT_TYPE_FAST_PRODUCE]
	if !ok {
		return
	}
	Event.Info["NextPlay"] = 0
}

func (l *LimitedTimeEventMod) GetFastProduceInfo() (int64, int) {
	Event, ok := l.EventList[EVENT_TYPE_FAST_PRODUCE]
	if !ok {
		return 0, 0
	}
	return GoUtil.Int64(Event.Info["NextPlay"]), GoUtil.Int(Event.Info["Times"])
}

// 增加进度
func (l *LimitedTimeEventMod) AddProgress(Lv int) {
	UnlockLv := limitedTimeEventCfg.GetUnlockLv()
	if Lv < UnlockLv {
		return
	}
	l.Progress++
}

// 选择进度奖励
func (l *LimitedTimeEventMod) SelectProgressReward(Id, Lv, Energy int) ([]*item.Item, int, int, map[int]int, error) {
	RewardId, ok := l.ProgressReward[Id]
	RewardList := l.ProgressReward
	if !ok {
		return nil, 0, 0, nil, fmt.Errorf("RewardId not exist")
	}
	Item := limitedTimeEventCfg.GetProgressReward(RewardId)
	OrderNum := l.ProgressMax
	l.LastSelect = RewardId
	l.ProgressReward = make(map[int]int)
	l.Progress = 0
	l.BonusNum++
	l.ProgressMax = limitedTimeEventCfg.GetProgressMax(l.Lv, l.BonusNum)

	// 重新生成进度奖励
	SelectNum := limitedTimeEventCfg.GetProgressSelectNum(Lv)
	BonusLv := limitedTimeEventCfg.GetBonusLv(Lv)
	RandMap := limitedTimeEventCfg.GetProgressRewardRand(BonusLv)
	// 体力小于200 high roller事件不进池子
	if Energy < limitedTimeEventCfg.GetHighRollerNeedEnergy() {
		delete(RandMap, limitedTimeEventCfg.GetJackpotIdByType(EVENT_TYPE_HIGH_ROLLER))
	}
	if GoUtil.Now()-l.LastCatDaySale < limitedTimeEventCfg.GetCatSaleCD() {
		// 参与猫咪大甩卖活动时，猫咪大甩卖事件不进池子
		delete(RandMap, limitedTimeEventCfg.GetJackpotIdByType(EVENT_TYPE_CAT_DAY_SALE))
	}
	l.fillProgressReward(RandMap, SelectNum)
	l.FirstReward = true
	return Item, limitedTimeEventCfg.GetProgressRewardType(RewardId), OrderNum, RewardList, nil
}

// fillProgressReward 随机填充进度奖励（最多尝试10次避免与上次相同）
func (l *LimitedTimeEventMod) fillProgressReward(RandMap map[int]int, SelectNum int) {
	LastOption := l.LastOption
	var r []int
	for n := 0; n < 10; n++ {
		r = GoUtil.RandMapNum(RandMap, SelectNum)
		Id := 1
		for _, v := range r {
			l.ProgressReward[Id] = v
			Id++
		}
		if !GoUtil.SliceEqual(LastOption, r) {
			break
		}
	}
	l.LastOption = r
}

func (l *LimitedTimeEventMod) RemoveSuperOrder() bool {
	if _, ok := l.EventList[EVENT_TYPE_SUPER_ORDER]; ok {
		delete(l.EventList, EVENT_TYPE_SUPER_ORDER)
		return true
	}
	return false
}

func (l *LimitedTimeEventMod) LuckyCat(ChessId int) error {
	L := l.EventList[EVENT_TYPE_LUCKY_CAT]
	if L == nil {
		return fmt.Errorf("LuckyCat event not exist")
	}
	MaxEarning := limitedTimeEventCfg.GetLuckyCatMaxEarning(int(L.Remian))
	d := L.D.(*LuckyCat)
	Lv := mergeDataCfg.GetLvById(ChessId)
	Earn := math.Pow(2, float64(Lv-1))
	d.Earnings += int(Earn)
	if d.Earnings >= MaxEarning {
		delete(l.EventList, EVENT_TYPE_LUCKY_CAT)
	}
	return nil
}

func (l *LimitedTimeEventMod) AddCatTrickEnergy(Energy int) {
	Event, ok := l.EventList[EVENT_TYPE_CAT_TRICK]
	if !ok {
		return
	}
	if Event.Remian+Event.StartT <= GoUtil.Now() {
		return
	}
	// 事件未过期
	d := Event.D.(*CatTrick)
	d.Energy += Energy
}

func (l *LimitedTimeEventMod) SubPaybackDay() error {
	return nil
}

func (l *LimitedTimeEventMod) GetCatTrickReward() ([]*item.Item, error) {
	Event, ok := l.EventList[EVENT_TYPE_CAT_TRICK]
	if !ok {
		return nil, fmt.Errorf("CatTrick event not exist")
	}
	d := Event.D.(*CatTrick)
	if d.Energy < 100 {
		return nil, fmt.Errorf("CatTrick energy not enough")
	}
	d.Energy -= 100
	// TODO 放到配置中
	return []*item.Item{
		{Id: item.ITEM_DIAMOND_ID, Num: 5},
	}, nil
}

// #region 事件信息初始化
func initEventInfo(E *LTEInfo, EventType int) {
	switch EventType {
	case EVENT_TYPE_FAST_PRODUCE:
		E.Info = map[string]interface{}{
			"Times":    0,
			"NextPlay": 0,
		}
	case EVENT_TYPE_MONEY_CAT:
		E.D = &MoneyCat{
			Id:  1,
			Mul: 1.1,
		}
	case EVENT_TYPE_LUCKY_CAT:
		MaxEarning := limitedTimeEventCfg.GetLuckyCatMaxEarning(int(E.Remian))
		E.D = &LuckyCat{
			MaxEarings: MaxEarning,
		}
	case EVENT_TYPE_PAYBACK_DAY:
		E.D = &PaybackDay{
			Count: limitedTimeEventCfg.GetPaybackDay(),
		}
	case EVENT_TYPE_CAT_TRICK:
		Type := limitedTimeEventCfg.GetCatTrickType(int(E.Remian))
		E.D = &CatTrick{
			List: []CatTrickInfo{
				{
					Id:   1,
					Type: Type,
				},
			},
		}
	}
}

func addEventInfo(E *LTEInfo, EventType, Duration int) {
	switch EventType {
	case EVENT_TYPE_CAT_TRICK:
		d := E.D.(*CatTrick)
		d.List = append(d.List, CatTrickInfo{
			Id:   len(d.List) + 1,
			Type: limitedTimeEventCfg.GetCatTrickType(Duration),
		})
	case EVENT_TYPE_LUCKY_CAT:
		MaxEarning := limitedTimeEventCfg.GetLuckyCatMaxEarning(Duration)
		d := E.D.(*LuckyCat)
		d.MaxEarings += MaxEarning
	case EVENT_TYPE_PAYBACK_DAY:
		d := E.D.(*PaybackDay)
		d.Count += limitedTimeEventCfg.GetPaybackDay()
	}
}

func getLimitEventMsg(t int, e *LTEInfo) *msg.LimitEvent {
	Cd := 0
	Mul := 0.0
	Param := make(map[string]int32)
	ShowTime := int32(e.StartT + e.Remian)
	EndTime := int32(e.StartT + e.Remian)
	switch t {
	case EVENT_TYPE_FAST_PRODUCE:
		NextPlay := GoUtil.Int64(e.Info["NextPlay"])
		Cd = int(max(NextPlay-GoUtil.Now(), 0))
	case EVENT_TYPE_MONEY_CAT:
		d := e.D.(*MoneyCat)
		Cd = int(d.EndTime)
		Mul = d.Mul
	case EVENT_TYPE_LUCKY_CAT:
		d := e.D.(*LuckyCat)
		Param[msg.LimitEventParam_LUCKY_CAT_EARNINGS.String()] = int32(d.MaxEarings)
	case EVENT_TYPE_CAT_TRICK:
		d := e.D.(*CatTrick)
		Energy := d.Energy
		Param[msg.LimitEventParam_CAT_TRICK_ENERGY.String()] = int32(Energy)
		info := d.List[0]
		Param[msg.LimitEventParam_CAT_TRICK_TYPE.String()] = int32(info.Type)
		Diamon1, Energy1 := limitedTimeEventCfg.GetCatTrickDiamond(info.Type)
		if d.Energy >= Diamon1*Energy1 {
			// 进度条已满
			EndTime += 5 * 60 // 5分钟
		}
	case EVENT_TYPE_PAYBACK_DAY:
		d := e.D.(*PaybackDay)
		Param[msg.LimitEventParam_PAYBACK_DAY_COUNT.String()] = int32(d.Count)
	}
	return &msg.LimitEvent{
		EndTime:   EndTime,
		ShowTime:  ShowTime,
		Cd:        int32(Cd),
		Mul:       float32(Mul),
		StartTime: int32(e.StartT),
		Param:     Param,
	}
}

func (l *LimitedTimeEventMod) EndCatDaySale() {
	delete(l.EventList, EVENT_TYPE_CAT_DAY_SALE)
}

func (l *LimitedTimeEventMod) GetCatDaySaleEndTime() int64 {
	v, ok := l.EventList[EVENT_TYPE_CAT_DAY_SALE]
	if !ok {
		return 0
	}
	return v.StartT + v.Remian
}
