package main

import (
	"encoding/json"
	"errors"
	"fmt"
	"math/rand"
	"slices"
	"strconv"
	"time"

	"mongo.games.com/goserver/core/basic"
	"mongo.games.com/goserver/core/logger"
	"mongo.games.com/goserver/core/module"
	"mongo.games.com/goserver/core/task"
	"mongo.games.com/goserver/core/timer"

	"mongo.games.com/game/common"
	"mongo.games.com/game/model"
	"mongo.games.com/game/proto"
	hall_proto "mongo.games.com/game/protocol/gamehall"
	"mongo.games.com/game/protocol/shop"
	webapi_proto "mongo.games.com/game/protocol/webapi"
	"mongo.games.com/game/srvdata"
	"mongo.games.com/game/webapi"
)

const (
	BlindBox      int32 = iota + 101 //盲盒
	FirstPay                         //首冲
	ContinuousPay                    //连充
	Exchange                         // 兑换商品
	ShopTypeStart int32 = 900000     //商品
)

// 消费类型
const (
	ShopConsumeCoin       = iota + 1 // 金币
	ShopConsumeDiamond               // 钻石
	ShopConsumeMoney                 // 现金
	ExchangeConsumeCash              //兑换消耗现金
	ShopConsumePhoneScore = 11       //手机积分
)

// page类型
const (
	ShopPageCoin              = iota + 1 //金币页面
	ShopPageDiamond                      //钻石页面
	ShopPageItem                         //道具页面
	ShopPageVip                          //VIP页面
	ShopPagePrivilege                    //VIP特权礼包
	ShopPagePhoneScore        = 61       //手机积分商城
	ShopPagePhoneScore_google = 62
)

// 商品类型
const (
	ShopTypeCoin    = iota + 1 // 金币
	ShopTypeDiamond            // 钻石
	ShopTypeItem               // 道具
)

// 兑换商品状态
const (
	Shop_Status_Keep    = iota //0为待审核
	Shop_Status_Pass           // 1为审核通过
	Shop_Status_Send           // 2为已发货
	Shop_Status_NotSend        // 3为审核不通过
	Shop_Status_Revoke         // 4为撤单
)

const (
	VCard int32 = 30001
	JCard int32 = 30002 //金券
)

/*
1.兑换成功：兑换成功，请等待审核
2.今日兑换已达上限，请明日再来
3.该物品已被兑换完
*/
const (
	Err_ExShopNEnough string = "ExShopNotEnough" // 该物品已被兑换完
	Err_ExShopLimit   string = "ExShopIsLimit"   // 今日兑换已达上限，请明日再来
	Err_ExShopData    string = "ExShopDataErr"   // 收件人地址有误
)

var ShopMgrSington = &ShopMgr{
	ShopInfos: make(map[string]map[int32]*ShopInfo),
	ExShops:   make(map[string]*webapi_proto.ExchangeShopList),
}

type ShopMgr struct {
	ShopInfos map[string]map[int32]*ShopInfo            // Platform:商品id:商品信息
	ExShops   map[string]*webapi_proto.ExchangeShopList //兑换商品 消耗v卡
}

type ShopInfo struct {
	Id          int32            // 商品ID
	Page        int32            // 页面 1，金币页面 2，钻石页面 3，道具页面
	Order       int32            // 排序  页面内商品的位置排序
	Location    []int32          // 显示位置 第1位，竖版大厅 第2位，Tienlen1级选场 第3位，捕鱼1级选场
	Picture     string           // 图片id
	Name        string           // 名称
	Label       []int32          // 标签
	Ad          int32            // 是否观看广告 0不看
	AdTime      int32            // 观看几次广告
	RepeatTimes int32            // 领取次数
	CoolingTime []int32          // 观看冷却时间
	Type        int32            // 获得类型 1，金币 2，钻石 3，道具类型
	Amount      int64            // 获得数量
	AddArea     []int32          // 加送百分比（比如加送10%，就配置110）
	ItemId      int32            // 获得道具ID
	AddItemInfo []*shop.ItemInfo // 获得道具
	ConstType   int32            // 购买消耗类型 1，金币 2，钻石 3，美金 4，柬埔寨币
	CostArea    []int32          // 消耗数量区间
	VipLevel    int32            //Vip等级限制
	Ratio       int32            //权重
	EndTime     int32            //新手礼包结束时间间隔
	//缓存数据
	AdLookedNum   int32 //已经观看的次数
	AdReceiveNum  int32 //已经领取的次数
	RemainingTime int32
	LastLookTime  int32
	RoleAdded     int32
	PetAdded      int32
	RoleAddedId   int32 //加成人物ID
	PetAddedId    int32 //加成宠物ID
	FirstSwitch   bool  // 首冲翻倍
	AmountFinal   int64 // 实际获得数量
}

type ExchangeShopInfo struct {
	Id             int32                //商品ID
	Picture        string               // 图片
	Type           int32                // 类型 1，话费2，实物
	Name           string               // 名称
	Rule           string               //规则说明
	ExType         []*shop.ExchangeType // 获得道具
	OrderId        string               //兑换的订单Id
	ExchangeTypeId int32                //兑换类型的id
	ExchangeNum    int32                //兑换数量

}

func (this *ShopMgr) ModuleName() string {
	return "ShopMgr"
}

func (this *ShopMgr) Init() {
}

// UpdateItemShop 更新商品信息
func (this *ShopMgr) UpdateItemShop(cfgs *webapi_proto.ItemShopList) {
	if cfgs == nil {
		return
	}
	shopInfos := make(map[int32]*ShopInfo)
	for _, itemShop := range cfgs.List {
		var itemInfo []*shop.ItemInfo
		for key, value := range itemShop.Award {
			itemInfo = append(itemInfo, &shop.ItemInfo{
				ItemId:  int32(key),
				ItemNum: value,
			})
		}

		shopInfos[itemShop.Id] = &ShopInfo{
			Id:          itemShop.Id,
			ItemId:      itemShop.ItemId,
			Page:        itemShop.Page,
			Order:       itemShop.Order,
			Type:        itemShop.Type,
			Location:    itemShop.Location,
			Picture:     itemShop.Picture,
			Name:        itemShop.Name,
			Ad:          itemShop.Ad,
			AdTime:      itemShop.AdTime,
			RepeatTimes: itemShop.RepeatTimes,
			CoolingTime: itemShop.CoolingTime,
			Label:       itemShop.Label,
			AddArea:     itemShop.AddArea,
			Amount:      int64(itemShop.Amount),
			ConstType:   itemShop.ConstType,
			CostArea:    itemShop.CostArea,
			AddItemInfo: itemInfo,
			VipLevel:    itemShop.VipLevel,
			Ratio:       itemShop.Ratio,
			EndTime:     itemShop.EndTime,
			FirstSwitch: itemShop.FirstSwitch,
		}
	}
	this.ShopInfos[cfgs.Platform] = shopInfos
}

// UpExShop 更新兑换商品信息
func (this *ShopMgr) UpExShop(cfgs *webapi_proto.ExchangeShopList) {
	this.ExShops[cfgs.GetPlatform()] = cfgs
}

func (this *ShopMgr) GetShopInfoProto(si *ShopInfo, p *Player, vipShopId int32) (shopInfo *shop.ShopInfo) {
	if si == nil {
		return nil
	}
	var itemInfo []*shop.ItemInfo
	for _, i2 := range si.AddItemInfo {
		itemInfo = append(itemInfo, &shop.ItemInfo{
			ItemId:  i2.ItemId,
			ItemNum: i2.ItemNum,
		})
	}
	added := int32(rand.Intn(int(si.AddArea[1])-int(si.AddArea[0])+1) + int(si.AddArea[0]))
	consumptionAmount := int32(rand.Intn(int(si.CostArea[1])-int(si.CostArea[0])+1) + int(si.CostArea[0]))
	amount := int64(si.Amount)
	isBuy := false
	if si.Page == ShopPageVip {
		shopData := p.GetVipShopData(si.Id, vipShopId)
		if shopData == nil {
			logger.Logger.Errorf("Vip商城 没有当前物品 snid = %v,shopId = %v", p.SnId, si.Id)
			return nil
		}
		added = shopData.AddArea
		consumptionAmount = shopData.CostArea
		amount = si.Amount * int64(consumptionAmount)
		isBuy = shopData.IsBuy
	}
	shopInfo = &shop.ShopInfo{
		Id:                si.Id,
		AdLookedNum:       si.AdLookedNum,
		AdReceiveNum:      si.AdReceiveNum,
		LastLookTime:      si.LastLookTime,
		RoleAdded:         si.RoleAdded,
		PetAdded:          si.PetAdded,
		ItemId:            si.ItemId,
		Order:             si.Order,
		Page:              si.Page,
		Type:              si.Type,
		Location:          si.Location,
		Picture:           si.Picture,
		Name:              si.Name,
		Ad:                si.Ad,
		AdTime:            si.AdTime,
		RepeatTimes:       si.RepeatTimes,
		CoolingTime:       si.CoolingTime,
		Label:             si.Label,
		Added:             added,
		Amount:            amount,
		Consume:           si.ConstType,
		ConsumptionAmount: consumptionAmount,
		AddItemInfo:       itemInfo,
		VipLevel:          si.VipLevel,
		EndTime:           si.EndTime,
		IsBuy:             isBuy,
		RoleAddedId:       si.RoleAddedId,
		AmountFinal:       this.GetAmountFinal(p, si.Id, vipShopId),
	}
	return
}

// GetShopInfo 获取玩家某个商品信息（例如玩家看广告领取）
func (this *ShopMgr) GetShopInfo(shopId int32, p *Player) *ShopInfo {
	if shopId == 0 {
		return nil
	}
	var shopInfo *ShopInfo
	if shops, ok := this.ShopInfos[p.Platform]; ok {
		if shopInf, ok1 := shops[shopId]; ok1 {
			shopInfo = shopInf
		}
	}
	if shopInfo != nil {
		// AdLookedNum 已看次数
		// AdReceiveNum 已领次数
		// remainingTime 商品设置的冷却时长
		var AdLookedNum, AdReceiveNum, remainingTime int32
		var lastLookTime int64
		if shopInfo.Ad > 0 {
			shopTotal := p.ShopTotal[shopInfo.Id]
			if shopTotal != nil {
				AdLookedNum = shopTotal.AdLookedNum
				AdReceiveNum = shopTotal.AdReceiveNum
			}
			lastLookTime = p.ShopLastLookTime[shopInfo.Id]
			if AdLookedNum < int32(len(shopInfo.CoolingTime)) {
				remainingTime = shopInfo.CoolingTime[AdLookedNum]
			}
			if lastLookTime >= 0 {
				dif := int32(time.Now().Unix() - lastLookTime)
				if dif >= remainingTime {
					remainingTime = 0
				} else {
					remainingTime = remainingTime - dif
				}
			}
		}
		award, roleId := PetMgrSington.GetShopAward(shopInfo, p)
		firstBuy := false
		if shopInfo.FirstSwitch {
			firstBuy = !slices.Contains(p.ShopID, int(shopInfo.Id))
		}

		return &ShopInfo{
			Id:            shopInfo.Id,
			Ad:            shopInfo.Ad,
			AdTime:        shopInfo.AdTime,
			RepeatTimes:   shopInfo.RepeatTimes,
			CoolingTime:   shopInfo.CoolingTime,
			AdLookedNum:   AdLookedNum,
			AdReceiveNum:  AdReceiveNum,
			RemainingTime: remainingTime,
			LastLookTime:  int32(lastLookTime),
			RoleAdded:     award,
			ItemId:        shopInfo.ItemId,
			Order:         shopInfo.Order,
			Page:          shopInfo.Page,
			Type:          shopInfo.Type,
			Location:      shopInfo.Location,
			Picture:       shopInfo.Picture,
			Name:          shopInfo.Name,
			Label:         shopInfo.Label,
			AddArea:       shopInfo.AddArea,
			Amount:        shopInfo.Amount,
			ConstType:     shopInfo.ConstType,
			CostArea:      shopInfo.CostArea,
			RoleAddedId:   roleId,
			AddItemInfo:   shopInfo.AddItemInfo,
			VipLevel:      shopInfo.VipLevel,
			EndTime:       shopInfo.EndTime,
			Ratio:         shopInfo.Ratio,
			FirstSwitch:   firstBuy,
			AmountFinal:   this.GetAmountFinal(p, shopId, 0),
		}
	}
	return nil
}

// GetShopInfos 获取玩家商品信息给客户端展示
func (this *ShopMgr) GetShopInfos(p *Player, nowLocation int) []*shop.ShopInfo {
	if p.ShopTotal == nil {
		p.ShopTotal = make(map[int32]*model.ShopTotal)
	}
	if p.ShopLastLookTime == nil {
		p.ShopLastLookTime = make(map[int32]int64)
	}
	var newShops = make([]*shop.ShopInfo, 0)
	if p.VipShopData == nil || len(p.VipShopData) == 0 {
		this.UpdateVipShopData(p)
	}

	for _, shopInfo := range this.ShopInfos[p.Platform] {
		if nowLocation == -1 || (nowLocation < len(shopInfo.Location) && shopInfo.Location[nowLocation] == 1) {
			if shopInfo.Page == ShopPageVip {
				continue
			}
			var AdLookedNum, AdReceiveNum, remainingTime int32
			var lastLookTime int64
			if shopInfo.Ad > 0 {
				shopTotal := p.ShopTotal[shopInfo.Id]
				if shopTotal != nil {
					AdLookedNum = shopTotal.AdLookedNum
					AdReceiveNum = shopTotal.AdReceiveNum
				}
				lastLookTime = p.ShopLastLookTime[shopInfo.Id]
				if AdLookedNum < int32(len(shopInfo.CoolingTime)) {
					remainingTime = shopInfo.CoolingTime[AdLookedNum]
				}
				dif := int32(time.Now().Unix() - lastLookTime)
				if dif >= remainingTime {
					remainingTime = 0
				} else {
					remainingTime = remainingTime - dif
				}
			}
			added := int32(rand.Intn(int(shopInfo.AddArea[1])-int(shopInfo.AddArea[0])+1) + int(shopInfo.AddArea[0]))
			consumptionAmount := int32(rand.Intn(int(shopInfo.CostArea[1])-int(shopInfo.CostArea[0])+1) + int(shopInfo.CostArea[0]))
			var itemInfo []*shop.ItemInfo
			for _, i2 := range shopInfo.AddItemInfo {
				itemInfo = append(itemInfo, &shop.ItemInfo{
					ItemId:  i2.ItemId,
					ItemNum: i2.ItemNum,
				})
			}
			award, roleId := PetMgrSington.GetShopAward(shopInfo, p)
			firstBuy := false
			if shopInfo.FirstSwitch {
				firstBuy = !slices.Contains(p.ShopID, int(shopInfo.Id))
			}
			newShops = append(newShops, &shop.ShopInfo{
				Id:                shopInfo.Id,
				AdLookedNum:       AdLookedNum,
				AdReceiveNum:      AdReceiveNum,
				LastLookTime:      int32(lastLookTime),
				RoleAdded:         award,
				RoleAddedId:       roleId,
				ItemId:            shopInfo.ItemId,
				Order:             shopInfo.Order,
				Page:              shopInfo.Page,
				Type:              shopInfo.Type,
				Location:          shopInfo.Location,
				Picture:           shopInfo.Picture,
				Name:              shopInfo.Name,
				Ad:                shopInfo.Ad,
				AdTime:            shopInfo.AdTime,
				RepeatTimes:       shopInfo.RepeatTimes,
				CoolingTime:       shopInfo.CoolingTime,
				Label:             shopInfo.Label,
				Added:             added,
				Amount:            int64(shopInfo.Amount),
				Consume:           shopInfo.ConstType,
				ConsumptionAmount: consumptionAmount,
				AddItemInfo:       itemInfo,
				VipLevel:          shopInfo.VipLevel,
				EndTime:           shopInfo.EndTime,
				IsBuy:             false,
				FirstBuy:          firstBuy,
				AmountFinal:       this.GetAmountFinal(p, shopInfo.Id, 0),
			})
		}
	}
	//VIP商城数据
	for i, data := range p.VipShopData {
		shopInfo := this.ShopInfos[p.Platform][data.Id]
		var AdLookedNum, AdReceiveNum, remainingTime int32
		var lastLookTime int64
		if shopInfo.Ad > 0 {
			shopTotal := p.ShopTotal[shopInfo.Id]
			if shopTotal != nil {
				AdLookedNum = shopTotal.AdLookedNum
				AdReceiveNum = shopTotal.AdReceiveNum
			}
			lastLookTime = p.ShopLastLookTime[shopInfo.Id]
			if AdLookedNum < int32(len(shopInfo.CoolingTime)) {
				remainingTime = shopInfo.CoolingTime[AdLookedNum]
			}
			dif := int32(time.Now().Unix() - lastLookTime)
			if dif >= remainingTime {
				remainingTime = 0
			} else {
				remainingTime = remainingTime - dif
			}
		}
		var itemInfo []*shop.ItemInfo
		for _, i2 := range shopInfo.AddItemInfo {
			itemInfo = append(itemInfo, &shop.ItemInfo{
				ItemId:  i2.ItemId,
				ItemNum: i2.ItemNum,
			})
		}
		award, roleId := PetMgrSington.GetShopAward(shopInfo, p)
		firstBuy := false
		if shopInfo.FirstSwitch {
			firstBuy = !slices.Contains(p.ShopID, int(shopInfo.Id))
		}
		newShops = append(newShops, &shop.ShopInfo{
			Id:                shopInfo.Id,
			AdLookedNum:       AdLookedNum,
			AdReceiveNum:      AdReceiveNum,
			LastLookTime:      int32(lastLookTime),
			RoleAdded:         award,
			RoleAddedId:       roleId,
			ItemId:            shopInfo.ItemId,
			Order:             shopInfo.Order,
			Page:              shopInfo.Page,
			Type:              shopInfo.Type,
			Location:          shopInfo.Location,
			Picture:           shopInfo.Picture,
			Name:              shopInfo.Name,
			Ad:                shopInfo.Ad,
			AdTime:            shopInfo.AdTime,
			RepeatTimes:       shopInfo.RepeatTimes,
			CoolingTime:       shopInfo.CoolingTime,
			Label:             shopInfo.Label,
			Added:             data.AddArea,
			Amount:            shopInfo.Amount * int64(data.CostArea),
			Consume:           shopInfo.ConstType,
			ConsumptionAmount: data.CostArea,
			AddItemInfo:       itemInfo,
			VipLevel:          shopInfo.VipLevel,
			EndTime:           shopInfo.EndTime,
			IsBuy:             data.IsBuy,
			VipShopId:         i,
			FirstBuy:          firstBuy,
			AmountFinal:       this.GetAmountFinal(p, shopInfo.Id, i),
		})
	}

	return newShops
}

// 更新玩家vipShop数据
func (this *ShopMgr) UpdateVipShopData(p *Player) {
	if p.VIP == 0 {
		return
	}
	if p.VipShopData == nil {
		p.VipShopData = make(map[int32]*model.ShopData)
	} else {
		//购买过的不刷新
		keysToDelete := []int32{}
		for id, data := range p.VipShopData {
			if !data.IsBuy {
				keysToDelete = append(keysToDelete, id)
			}
		}

		// 删除要删除的键
		for _, id := range keysToDelete {
			delete(p.VipShopData, id)
		}
	}

	//获取vip商品刷新个数
	vipConfig := VipMgrSington.GetVIPLevelCfg(p.Platform, p.VIP)
	if vipConfig == nil {
		return
	}
	count := int(vipConfig.Privilege3[1])
	count -= len(p.VipShopData)
	logger.Logger.Trace("VIP商城刷新 刷新商品个数为：", count)
	if count <= 0 {
		logger.Logger.Error("VIP商城 暂时无法刷新！Snid = ", p.SnId)
		return
	}
	//获取对应VIP等级物品列表
	vipShopInfoMap := make(map[int32]*ShopInfo)
	var sumRatio = 0 //权重
	for _, shopInfo := range this.ShopInfos[p.Platform] {
		if shopInfo.Page == ShopPageVip && shopInfo.VipLevel == p.VIP {
			vipShopInfoMap[shopInfo.Id] = shopInfo
			sumRatio += int(shopInfo.Ratio)
		}
	}
	if len(vipShopInfoMap) == 0 {
		return
	}
	for i := 1; i <= int(vipConfig.Privilege3[1]); i++ {
		if p.VipShopData[int32(i)] != nil {
			continue
		}
		//随机vip物品
		random := rand.Intn(sumRatio + 1)
		logger.Logger.Tracef("Vip商城 随机到的值：%v,总权重：%v", random, sumRatio)
		ratio := 0
		for id, shopInfo := range vipShopInfoMap {
			ratio += int(shopInfo.Ratio)
			if random <= ratio {
				//判断商品位置
				p.VipShopData[int32(i)] = &model.ShopData{
					Id:       id,
					AddArea:  int32(rand.Intn(int(shopInfo.AddArea[1]-shopInfo.AddArea[0]+1)) + int(shopInfo.AddArea[0])),
					CostArea: int32(rand.Intn(int(shopInfo.CostArea[1]-shopInfo.CostArea[0]+1)) + int(shopInfo.CostArea[0])),
					IsBuy:    false,
				}
				logger.Logger.Tracef("Vip商城 随机到的物品id = %v,shopInfo = %v,random = %v,num = %v,商品位置：%v", id, shopInfo, random, ratio, i)
				break
			}
		}
	}
}

// LookAdReceive 看广告领取商品,校验领取次数
func (this *ShopMgr) LookAdReceive(shopId int32, p *Player, position int32) shop.OpResultCode {
	var shopInfo *ShopInfo
	if shops, ok := this.ShopInfos[p.Platform]; ok {
		if shopInf, ok1 := shops[shopId]; ok1 {
			shopInfo = shopInf
		}
	}
	if shopInfo == nil {
		logger.Logger.Errorf("this shop == nil  shopId[%v] ", shopId)
		return shop.OpResultCode_OPRC_Error
	}
	//需要观看广告的
	if shopInfo.Ad > 0 {
		if _, ok1 := p.ShopTotal[shopId]; !ok1 {
			p.ShopTotal[shopId] = &model.ShopTotal{}
		}
		shopTotal := p.ShopTotal[shopId]
		if shopTotal.AdReceiveNum < shopInfo.RepeatTimes {
			shopTotal.AdReceiveNum++
			return this.ReceiveVCPayShop(shopInfo, p, 0, position)
		}
	}
	return shop.OpResultCode_OPRC_Error
}

// ReceiveVCPayShop 领取VC看广告商品
func (this *ShopMgr) ReceiveVCPayShop(shopInfo *ShopInfo, p *Player, vipShopId, position int32) shop.OpResultCode {
	if shopInfo == nil {
		logger.Logger.Errorf("this shop == nil")
		return shop.OpResultCode_OPRC_Error
	}
	//产生订单
	this.PayAway(shopInfo, p, vipShopId, position)
	return shop.OpResultCode_OPRC_Sucess
}

// PayAway 商城 领取商品
func (this *ShopMgr) PayAway(shopInfo *ShopInfo, p *Player, vipShopId, position int32) {
	shopName := shopInfo.Name + "|" + strconv.Itoa(int(shopInfo.Id))
	costNum := rand.Int31n(shopInfo.CostArea[1]-shopInfo.CostArea[0]+1) + shopInfo.CostArea[0]
	if shopInfo.Page == ShopPageVip {
		shopData := p.GetVipShopData(shopInfo.Id, vipShopId)
		if shopData != nil {
			costNum = shopData.CostArea
		}
	}
	if shopInfo.Ad <= 0 { //消耗
		logger.Logger.Tracef("AddOrder Consume[%v],shopName[%v]", shopInfo.ConstType, shopName, costNum)
		switch shopInfo.ConstType {
		case ShopConsumeCoin:
			p.AddCoin(int64(-costNum), 0, common.GainWay_Shop_Buy, "sys", shopName)
		case ShopConsumeDiamond:
			p.AddDiamond(int64(-costNum), 0, common.GainWay_Shop_Buy, "sys", shopName)
		case ShopConsumePhoneScore:
			p.AddPhoneScore(int64(-costNum), 0, common.GainWay_Shop_Buy, "sys", shopName)
		case ShopConsumeMoney:
			//task.New(nil, task.CallableWrapper(func(o *basic.Object) interface{} {
			//	return webapi.API_CreateOrder(common.GetAppId(),"", p.SnId, shopInfo.Id, p.Platform, p.PackageID, p.DeviceOS,
			//		p.DeviceId, shopInfo.Name, shopInfo.Amount, shopInfo.ConsumptionAmount)
			//}), task.CompleteNotifyWrapper(func(data interface{}, t task.Task) {
			//	if data != nil {
			//		//失败
			//	}
			//}), "API_CreateOrder").Start()
			//p.AddMoneyPayTotal(int64(shopInfo.ConsumptionAmount))
			return
		}
	} else {
		TaskSubjectSingleton.Touch(common.TaskTypeAdv, &TaskData{
			SnId:     p.SnId,
			Num:      1,
			Position: position,
		})
	}
	amount := [3]int32{} // 获得
	if shopInfo.Page == ShopPageVip {
		if p.VipShopData[vipShopId] == nil {
			return
		}
		p.VipShopData[vipShopId].IsBuy = true
		logger.Logger.Trace("玩家购买VIP商城物品成功,商品Id = ", shopInfo.Id)
	}

	addTotal := this.GetAmountFinal(p, shopInfo.Id, vipShopId)
	logger.Logger.Trace("addTotal  ", addTotal, shopInfo.Amount)
	switch shopInfo.Type {
	case ShopTypeCoin:
		amount[shopInfo.Type-1] = int32(addTotal)
		p.AddCoin(addTotal, 0, common.GainWay_Shop_Buy, "system", shopName)
		if shopInfo.Ad > 0 { //观看广告
			LogChannelSingleton.WriteMQData(model.GenerateSystemFreeGive(p.SnId, p.Name, p.Platform, model.SystemFreeGive_GiveType_ShopAd, model.SystemFreeGive_CoinType_Coin, addTotal))
		}
		// 记录钻石兑换金币的金币数量，个人水池调控使用
		if shopInfo.ConstType == ShopConsumeDiamond && shopInfo.Ad <= 0 && costNum > 0 {
			p.AddDiamondToCoin(addTotal)
		}
		if shopInfo.Ad <= 0 && costNum != 0 {
			TaskSubjectSingleton.Touch(common.TaskTypeBuyCoin, &TaskData{SnId: p.SnId, Num: 1, Position: position})
		}

	case ShopTypeDiamond:
		//增加钻石
		amount[shopInfo.Type-1] = int32(addTotal)
		p.AddDiamond(addTotal, 0, common.GainWay_Shop_Buy, "system", shopName)
		if shopInfo.Ad > 0 { //观看广告
			LogChannelSingleton.WriteMQData(model.GenerateSystemFreeGive(p.SnId, p.Name, p.Platform, model.SystemFreeGive_GiveType_ShopAd, model.SystemFreeGive_CoinType_Diamond, addTotal))
		}
	case ShopTypeItem:
		//增加道具
		item := &Item{ItemId: shopInfo.ItemId, ItemNum: addTotal, ObtainTime: time.Now().Unix()}
		BagMgrSingleton.AddJybBagInfo(p, []*Item{item}, 0, common.GainWay_Shop_Buy, "system", shopName)
		data := srvdata.PBDB_GameItemMgr.GetData(item.ItemId)
		if data != nil {
			BagMgrSingleton.RecordItemLog(p.Platform, p.SnId, ItemObtain, shopInfo.ItemId, data.Name, addTotal, "商城购买")
		}
		PetMgrSington.CheckShowRed(p)
	}
	this.ShopAddItem(shopInfo, p)

	this.CreateVCOrder(shopInfo, p.SnId, costNum, p.Platform, amount)

	//抽奖兑换统计
	if shopInfo.ConstType == ShopConsumePhoneScore {
		items := make([]*Item, 0)
		itemId := int32(0)
		if shopInfo.Type == ShopTypeCoin {
			itemId = common.ItemIDCoin
		} else if shopInfo.Type == ShopTypeDiamond {
			itemId = common.ItemIDDiamond
		} else {
			//道具
			itemId = shopInfo.ItemId
		}
		items = append(items, &Item{
			ItemId:  itemId,   // 物品id
			ItemNum: addTotal, // 数量
		})
		jsonData, err := json.Marshal(items)
		if err == nil {
			LogChannelSingleton.WriteMQData(model.GeneratePhoneLottery(p.SnId, p.Platform, string(jsonData), 2, 0, 0, int(costNum)))
		}
	}
}

// GetAmountFinal 计算商品实际获得数量
func (this *ShopMgr) GetAmountFinal(p *Player, shopId, vipShopId int32) int64 {
	if p == nil {
		return 0
	}

	var shopInfo *ShopInfo
	if shops, ok := this.ShopInfos[p.Platform]; ok {
		if shopInf, ok := shops[shopId]; ok {
			shopInfo = shopInf
		}
	}
	if shopInfo == nil {
		return 0
	}

	//默认加成
	var addTotal = shopInfo.Amount
	added := rand.Int31n(shopInfo.AddArea[1]-shopInfo.AddArea[0]+1) + shopInfo.AddArea[0]
	if shopInfo.Page == ShopPageVip {
		if p.VipShopData[vipShopId] == nil {
			return 0
		}
		addTotal = shopInfo.Amount * int64(p.VipShopData[vipShopId].CostArea)
		added = p.VipShopData[vipShopId].AddArea
	}
	var addNormal int64
	if added > 0 {
		addNormal = int64(float64(addTotal) * float64(added) / 100.0)
	}

	vipAdded := int64(0)
	if shopInfo.Page == ShopPageDiamond {
		//vip加成
		vipAdded = int64(VipMgrSington.GetVipDiamondExtra(p.Platform, p.VIP))
		logger.Logger.Tracef("商城钻石购买，vip加成 vipAdded = %v", vipAdded)
		vipAdded = int64(float64(addTotal) * float64(vipAdded) / 100.0)
	}

	switch shopInfo.Type {
	case ShopTypeCoin:
		var addCoin int64
		award, _ := PetMgrSington.GetShopAward(shopInfo, p)
		if award > 0 {
			addCoin = int64(float64(addTotal) * float64(award) / 100.0)
		}
		//增加金币
		addTotal += addNormal + addCoin
	case ShopTypeDiamond:
		addTotal += addNormal + vipAdded

		// 首充翻倍
		if shopInfo.FirstSwitch {
			if !slices.Contains(p.ShopID, int(shopInfo.Id)) {
				addTotal *= 2
			}
		}
	}
	return addTotal
}

// 商城购买 额外增加道具
func (this *ShopMgr) ShopAddItem(shopInfo *ShopInfo, p *Player) {
	if shopInfo.AddItemInfo != nil {
		for _, info := range shopInfo.AddItemInfo {
			item := &Item{ItemId: info.ItemId, ItemNum: info.ItemNum, ObtainTime: time.Now().Unix()}
			BagMgrSingleton.AddJybBagInfo(p, []*Item{item}, 0, common.GainWay_Shop_Buy, "system", shopInfo.Name)
			data := srvdata.PBDB_GameItemMgr.GetData(item.ItemId)
			if data != nil {
				BagMgrSingleton.RecordItemLog(p.Platform, p.SnId, ItemObtain, shopInfo.ItemId, data.Name, shopInfo.Amount, "商城购买")
			}
			PetMgrSington.CheckShowRed(p)
		}
	}
}

// CreateVCOrder 产生VC订单，记录看广告获取商品的订单
func (this *ShopMgr) CreateVCOrder(shopInfo *ShopInfo, snid, costNum int32, platform string, amount [3]int32) {
	task.New(nil, task.CallableWrapper(func(o *basic.Object) interface{} {
		//获得类型
		if shopInfo.Type < ShopTypeCoin && shopInfo.Type > ShopTypeItem {
			return errors.New("error type")
		}
		//道具
		var item []model.ItemInfo
		if shopInfo.Type == ShopTypeItem {
			item = append(item, model.ItemInfo{ItemId: shopInfo.ItemId, ItemNum: shopInfo.Amount})
			if shopInfo.AddItemInfo != nil {
				for _, info := range shopInfo.AddItemInfo {
					item = append(item, model.ItemInfo{ItemId: info.ItemId, ItemNum: int64(info.ItemNum)})
				}
			}
		}
		dbShop := model.NewDbShop(platform, shopInfo.Page, amount[:], "sys", 0, shopInfo.ConstType, costNum,
			common.GainWay_ShopBuy, item, shopInfo.Id, shopInfo.Name, snid, 1, "shop_goods", []int32{})
		return model.InsertDbShopLog(dbShop)
	}), task.CompleteNotifyWrapper(func(data interface{}, t task.Task) {
		if data != nil {
			logger.Logger.Errorf("err:", data.(error))
		}
	}), "CreateVCOrder").Start()
}

func (this *ShopMgr) GetExchangeData(platform string, id int32) *ExchangeShopInfo {
	if exShops := this.ExShops[platform]; exShops != nil {
		for _, data := range exShops.List {
			if data.Id == id {
				var exType []*shop.ExchangeType
				for _, info := range data.ExType {
					exType = append(exType, &shop.ExchangeType{
						Price:  info.Price,
						JPrice: info.JPrice,
						Cash:   info.Cash,
						Id:     info.Id,
					})
				}
				return &ExchangeShopInfo{
					Id:      data.Id,
					Picture: data.Picture,
					Type:    data.Type,
					Name:    data.Name,
					Rule:    data.Content,
					ExType:  exType,
				}
			}
		}
	}
	return nil
}

// 兑换操作
// Exchange 生成兑换订单（v卡） id 兑换方式 0~2
func (this *ShopMgr) Exchange(p *Player, goodsId int32, username, mobile, comment string, id int32, num int32) (ret bool) {
	ret = true
	cdata := this.GetExchangeData(p.Platform, goodsId)
	pack := &shop.SCShopExchange{
		RetCode: shop.OpResultCode_OPRC_VCoinNotEnough,
	}
	if cdata == nil {
		pack.RetCode = shop.OpResultCode_OPRC_ExchangeSoldOut
		p.SendToClient(int(shop.SPacketID_PACKET_SC_SHOP_EXCHANGE), pack)
		return false
	}

	var info *shop.ExchangeType
	for _, value := range cdata.ExType {
		if value.Id == id {
			info = value
			break
		}
	}

	if info == nil || (info.Price == 0 && info.JPrice == 0 && info.Cash == 0) {
		return false
	}

	var itemInfo []model.ItemInfo
	// TODO 服务器处理 减劵 成功后调后台生成订单
	// 判断p.VCoin是否足够 不足返回错误 足够扣掉 另外需从后台操作回执成功生成扣除V卡的订单 回执失败
	//扣除V卡
	if info.Price > 0 {
		if isF := BagMgrSingleton.SaleItem(p, VCard, int64(info.Price*num)); !isF { // 扣掉V卡
			p.SendToClient(int(shop.SPacketID_PACKET_SC_SHOP_EXCHANGE), pack)
			return false
		}
		itemInfo = append(itemInfo, model.ItemInfo{
			ItemId:  VCard,
			ItemNum: int64(info.Price * num),
		})
	}
	//扣除金券
	if info.JPrice > 0 {
		if isF := BagMgrSingleton.SaleItem(p, JCard, int64(info.JPrice*num)); !isF { // 扣掉金券
			pack.RetCode = shop.OpResultCode_OPRC_JCoinNotEnough
			p.SendToClient(int(shop.SPacketID_PACKET_SC_SHOP_EXCHANGE), pack)
			return false
		}
		itemInfo = append(itemInfo, model.ItemInfo{
			ItemId:  JCard,
			ItemNum: int64(info.JPrice * num),
		})
	}
	task.New(nil, task.CallableWrapper(func(o *basic.Object) interface{} {
		pack := &webapi_proto.ASCreateExchangeOrder{
			Snid:         p.SnId,
			Platform:     p.Platform,
			Type:         cdata.Type,
			GoodsId:      cdata.Id,
			VCard:        info.Price * num,
			GoodsName:    cdata.Name,
			UserName:     username,
			Mobile:       mobile,
			Comment:      comment,
			JPrice:       info.JPrice * num,
			Cash:         info.Cash * num,
			Amount:       num,
			ExchangeType: id,
		}
		buff, err := webapi.API_CreateExchange(common.GetAppId(), pack)
		if err != nil {
			logger.Logger.Error("API_CreateExchange error:", err)
		}

		as := &webapi_proto.SACreateExchangeOrder{}
		if err := proto.Unmarshal(buff, as); err != nil {
			logger.Logger.Errorf("API_CreateExchange err: %v %v", err, as.Tag)
		}
		var amount [ShopTypeItem]int32
		//保存db
		dbShop := this.NewDbShop(p, 0, amount[:], ExchangeConsumeCash, info.Cash*num,
			common.GainWay_ShopBuy, itemInfo, cdata.Id, cdata.Name, 0, "", []int32{})
		err = model.InsertDbShopLog(dbShop)
		if err != nil {
			logger.Logger.Errorf("model.InsertDbShopLog err:", err)
			return nil
		}
		return as

	}), task.CompleteNotifyWrapper(func(data interface{}, t task.Task) {
		pack := &shop.SCShopExchange{
			RetCode: shop.OpResultCode_OPRC_Error,
		}

		as := data.(*webapi_proto.SACreateExchangeOrder) // 必不为空
		//dbShop
		if as.Tag == webapi_proto.TagCode_SUCCESS {
			pack.RetCode = shop.OpResultCode_OPRC_Sucess
			//p.SendVCoinDiffData() // 强推
			if info.Price > 0 {
				name := "V卡"
				if item := BagMgrSingleton.GetItem(p.SnId, VCard); item != nil && item.Name != "" {
					name = item.Name
				} else {
					logger.Logger.Errorf("ExchangeList name err snid %v item %v ", p.SnId, VCard)
				}
				BagMgrSingleton.RecordItemLog(p.Platform, p.SnId, ItemConsume, VCard, name, int64(info.Price*num), fmt.Sprintf("兑换订单 %v-%v", cdata.Id, cdata.Name))
			}

			if info.JPrice > 0 {
				name := "金券"
				if item := BagMgrSingleton.GetItem(p.SnId, JCard); item != nil && item.Name != "" {
					name = item.Name
				} else {
					logger.Logger.Errorf("ExchangeList name err snid %v item %v ", p.SnId, JCard)
				}
				BagMgrSingleton.RecordItemLog(p.Platform, p.SnId, ItemConsume, JCard, name, int64(info.JPrice*num), fmt.Sprintf("兑换订单 %v-%v", cdata.Id, cdata.Name))
			}
		} else {
			if as.GetReturnCPO() != nil {
				switch as.ReturnCPO.Err {
				case Err_ExShopNEnough:
					pack.RetCode = shop.OpResultCode_OPRC_ExchangeNotEnough
				case Err_ExShopLimit:
					pack.RetCode = shop.OpResultCode_OPRC_ExchangeLimit
				case Err_ExShopData:
					pack.RetCode = shop.OpResultCode_OPRC_ExchangeDataRtt
				default:
					pack.RetCode = shop.OpResultCode_OPRC_ExchangeSoldOut
				}
			}
			logger.Logger.Trace("API_CreateExchange: ", as.Tag, as.GetReturnCPO())
			var items = []*Item{}
			//返回V卡
			if info.Price > 0 {
				item1 := &Item{
					ItemId:  VCard,                   // 物品id
					ItemNum: int64(info.Price * num), // 数量
				}
				items = append(items, item1)
			}
			//返回金券
			if info.JPrice > 0 {
				item := &Item{
					ItemId:  JCard,
					ItemNum: int64(info.JPrice * num),
				}
				items = append(items, item)
			}

			if len(items) > 0 {
				BagMgrSingleton.AddJybBagInfo(p, items, 0, common.GainWay_Exchange, "system", "返还物品") // 后台订单创建失败 返回物品
			}
		}

		p.SendToClient(int(shop.SPacketID_PACKET_SC_SHOP_EXCHANGE), pack)
	}), "CreateExchange").Start()

	return
}

// 兑换列表
func (this *ShopMgr) ExchangeList(p *Player) (ret bool) {
	ret = true

	task.New(nil, task.CallableWrapper(func(o *basic.Object) interface{} {
		pack := &webapi_proto.ASGetExchangeShop{
			Snid:     p.SnId,
			Platform: p.Platform,
		}
		buff, err := webapi.API_ExchangeList(common.GetAppId(), pack)

		// spack := &shop.SCShopExchangeRecord{}
		as := &webapi_proto.SAGetExchangeShop{}
		logger.Logger.Trace("SCShopOrder:", pack)
		if err != nil {
			logger.Logger.Error("API_ExchangeList error:", err)
			return nil
		} else if err := proto.Unmarshal(buff, as); err != nil { // 有订单

			logger.Logger.Errorf("ExchangeRecord: %v", err)
			return nil

		}

		return as
	}), task.CompleteNotifyWrapper(func(data interface{}, t task.Task) {

		pack := &shop.SCShopExchangeList{
			RetCode: shop.OpResultCode_OPRC_Sucess,
		}

		if data != nil {
			if as := data.(*webapi_proto.SAGetExchangeShop); as != nil {
				for _, v := range as.List {
					var exChangeType []*shop.ExchangeType
					for _, info := range v.ExType {
						exChangeType = append(exChangeType, &shop.ExchangeType{
							Price:  info.Price,
							JPrice: info.JPrice,
							Id:     info.Id,
							Cash:   info.Cash,
						})
					}
					pack.Infos = append(pack.Infos, &shop.ShopExchangeInfo{
						Type:         v.Type,
						Picture:      v.Picture,
						Name:         v.Name,
						Rule:         v.Content,
						GoodsId:      v.Id,
						ShopLimit:    v.ShopLimit,
						DayMaxLimit:  v.DayMaxLimit,
						DayPlayLimit: v.DayPlayLimit,
						ExType:       exChangeType,
						TelCharge:    v.TelCharge,
					})
				}
			}
		} else {
			pack.RetCode = shop.OpResultCode_OPRC_Error
		}
		p.SendToClient(int(shop.SPacketID_PACKET_SC_SHOP_EXCHANGELIST), pack)
	}), "ExchangeList").Start()

	return
}

// 获取兑换记录
func (this *ShopMgr) GetExchangeRecord(p *Player, pageNo int32) {
	task.New(nil, task.CallableWrapper(func(o *basic.Object) interface{} {
		pack := &webapi_proto.ASGetExchangeOrder{
			Snid:     p.SnId,
			Platform: p.Platform,
			Page:     pageNo,
		}
		buff, err := webapi.API_ExchangeRecord(common.GetAppId(), pack)

		// spack := &shop.SCShopExchangeRecord{}
		as := &webapi_proto.SAGetExchangeOrder{}
		logger.Logger.Trace("SCShopOrder:", pack)
		if err != nil {
			logger.Logger.Error("API_ExchangeRecord error:", err)
			return nil
		} else if err := proto.Unmarshal(buff, as); err != nil { // 有订单

			logger.Logger.Errorf("ExchangeRecord: %v", err)
			return nil

		}

		return as
	}), task.CompleteNotifyWrapper(func(data interface{}, t task.Task) {
		pack := &shop.SCShopExchangeRecord{}
		if data != nil {
			if as := data.(*webapi_proto.SAGetExchangeOrder); as != nil {

				pack.PageNo = as.CurPage
				pack.PageSize = as.PageLimit
				pack.PageSum = as.PageTotal
				for _, v := range as.OrderList {

					record := &shop.ShopExchangeRecord{
						CreateTs:     v.CreateTime,
						OrderId:      fmt.Sprintf("%v", v.Id),
						State:        v.Status,
						Name:         v.Name,
						Remark:       v.Remark,
						PayState:     v.PayStatus,
						ExchangeNum:  v.ExchangeNum,
						EXchangeType: v.EXchangeType,
						GoodsId:      v.GoodsId,
					}
					// remark
					pack.Infos = append(pack.Infos, record)
				}

			}
		}
		p.SendToClient(int(shop.SPacketID_PACKET_SC_SHOP_EXCHANGERECORD), pack)
	}), "ExchangeRecord").Start()

}

// ShopCheckShowRed 商城红点通知
func (this *ShopMgr) ShopCheckShowRed(p *Player) {
	if p == nil {
		return
	}
	for i := 0; i < 3; i++ {
		var isShow bool
		for _, shopInfo := range this.ShopInfos[p.Platform] {
			var AdLookedNum, remainingTime int32
			var lastLookTime int64
			if shopInfo.Ad > 0 && (i == -1 || (i < len(shopInfo.Location) && shopInfo.Location[i] == 1)) {
				shopTotal := p.ShopTotal[shopInfo.Id]
				if shopTotal != nil {
					AdLookedNum = shopTotal.AdLookedNum
				}
				lastLookTime = p.ShopLastLookTime[shopInfo.Id]
				if AdLookedNum < int32(len(shopInfo.CoolingTime)) {
					remainingTime = shopInfo.CoolingTime[AdLookedNum]
				} else {
					continue
				}
				dif := int32(time.Now().Unix() - lastLookTime)
				if dif >= remainingTime {
					remainingTime = 0
					if i+1 <= len(shopInfo.Location) {
						isShow = true
						p.SendShowRed(hall_proto.ShowRedCode_Shop, int32(i+1), 1)
					}
				}
			}
		}
		if !isShow {
			p.SendShowRed(hall_proto.ShowRedCode_Shop, int32(i+1), 0)
		}
	}
}

// 现金订单
func (this *ShopMgr) NewDbShop(p *Player, pageId int32, amount []int32, consume, consumeNum, gainWay int32,
	itemInfo []model.ItemInfo, shopId int32, shopName string, state int32, remark string, other []int32) (dbShop *model.DbShop) {
	ct, cr := PlatformMgrSingleton.GetCurrencyByPackageTag(p.PackageID)
	dbShop = model.NewDbShop(p.Platform, pageId, amount[:], ct, consumeNum*cr, consume, consumeNum,
		gainWay, itemInfo, shopId, shopName, p.SnId, state, remark, other)
	return
}

// SendAPICreateOrder 创建订单
func (this *ShopMgr) SendAPICreateOrder(p *Player, ConfigPayId int32, data any, remark string) {
	//三方购买
	task.New(nil, task.CallableWrapper(func(o *basic.Object) interface{} {
		var amount [ShopTypeItem]int32
		var dbShop *model.DbShop
		if shopInfo, ok := data.(*ShopInfo); ok {
			// 目前现金只能买钻石
			var addTotal = int64(shopInfo.Amount)
			added := rand.Int31n(shopInfo.AddArea[1]-shopInfo.AddArea[0]+1) + shopInfo.AddArea[0]
			costNum := rand.Int31n(shopInfo.CostArea[1]-shopInfo.CostArea[0]+1) + shopInfo.CostArea[0]
			/*			if shopInfo.Page == ShopPageVip {
						//暂时这样修改 VIP礼包没有现金支付
						shopData := p.GetVipShopData(shopInfo.Id, 0)
						if shopData != nil {
							added = shopData.AddArea
							costNum = shopData.CostArea
						}
					}*/
			vipAdded := int32(0)
			if shopInfo.Page == ShopPageDiamond {
				//vip加成
				vipAdded = VipMgrSington.GetVipDiamondExtra(p.Platform, p.VIP)
				logger.Logger.Tracef("商城钻石购买，vip加成 vipAdded = %v", vipAdded)
			}

			if added > 0 || vipAdded > 0 {
				addTotal = shopInfo.Amount + int64((float64(shopInfo.Amount)*float64(added+vipAdded))/100.0)
			}

			// 首充翻倍
			if shopInfo.FirstSwitch {
				if !slices.Contains(p.ShopID, int(shopInfo.Id)) {
					addTotal *= 2
				}
			}

			amount[ShopTypeDiamond-1] = int32(addTotal)
			var itemInfo []model.ItemInfo
			var webItemInfo []*webapi_proto.ItemInfo
			if shopInfo.AddItemInfo != nil {
				for _, info := range shopInfo.AddItemInfo {
					itemInfo = append(itemInfo, model.ItemInfo{
						ItemId:  info.ItemId,
						ItemNum: int64(info.ItemNum),
					})
					webItemInfo = append(webItemInfo, &webapi_proto.ItemInfo{
						ItemId:  info.ItemId,
						ItemNum: info.ItemNum,
					})
				}
			}

			dbShop = this.NewDbShop(p, shopInfo.Page, amount[:], ShopConsumeMoney, costNum,
				common.GainWay_ShopBuy, itemInfo, shopInfo.Id, shopInfo.Name, 0, remark, []int32{})
			err := model.InsertDbShopLog(dbShop)
			if err != nil {
				logger.Logger.Errorf("model.InsertDbShopLog err:", err)
				return nil
			}
			return webapi.API_CreateOrder(common.GetAppId(), dbShop.LogId.Hex(), ConfigPayId, p.SnId, shopInfo.Id, p.Platform, p.PackageID, p.DeviceOS,
				p.DeviceId, shopInfo.Name, [ShopTypeItem]int32{0, int32(addTotal), 0}, costNum, webItemInfo, "")

		} else if cdata, ok := data.(*ExchangeShopInfo); ok {
			var info *shop.ExchangeType
			for _, value := range cdata.ExType {
				if value.Id == cdata.ExchangeTypeId {
					info = value
					break
				}
			}
			if info.Cash <= 0 {
				return nil
			}
			//保存到db
			dbShop = this.NewDbShop(p, 0, amount[:], ExchangeConsumeCash, info.Cash*cdata.ExchangeNum,
				common.GainWay_ShopBuy, nil, cdata.Id, cdata.Name, 0, remark, []int32{})
			err := model.InsertDbShopLog(dbShop)
			if err != nil {
				logger.Logger.Errorf("model.InsertDbShopLog err:", err)
				return nil
			}
			orderId := cdata.OrderId
			//兑换 充值订单
			logger.Logger.Infof("客户端请求兑换 创建支付订单！AppId = %v,SnId = %v,Id = %v,dbShop.LogId.Hex() = %v,cash = %v", common.GetAppId(), p.SnId, cdata.Id, dbShop.LogId.Hex(), info.Cash*cdata.ExchangeNum)
			return webapi.API_CreateOrder(common.GetAppId(), dbShop.LogId.Hex(), ConfigPayId, p.SnId, cdata.Id, p.Platform, p.PackageID, p.DeviceOS,
				p.DeviceId, cdata.Name, [ShopTypeItem]int32{0, 0, 0}, info.Cash*cdata.ExchangeNum, nil, orderId)
		} else if bbd, ok := data.(*webapi_proto.BlindBoxData); ok {
			if bbd.Type == 1 {
				//金币
				amount[0] = bbd.Grade
			} else if bbd.Type == 2 {
				//钻石
				amount[1] = bbd.Grade
			}
			dbShop = this.NewDbShop(p, 0, amount[:], ShopConsumeMoney, int32(bbd.Price2), common.GainWay_ActBlindBox, nil, 0, "", 0, remark, []int32{bbd.Id})
			err := model.InsertDbShopLog(dbShop)
			if err != nil {
				logger.Logger.Errorf("model.InsertDbShopLog err:", err)
				return nil
			}
			return webapi.API_CreateOrder(common.GetAppId(), dbShop.LogId.Hex(), ConfigPayId, p.SnId, 0, p.Platform, p.PackageID, p.DeviceOS,
				p.DeviceId, bbd.Name, amount, int32(bbd.Price2), nil, "")
		} else if wfs, ok := data.(*webapi_proto.WelfareSpree); ok {
			for _, it := range wfs.Item {
				if it.Type == 1 {
					amount[0] = it.Grade
				} else if it.Type == 2 {
					amount[1] = it.Grade
				}
			}
			var gainWay int32 = common.GainWay_ActFirstPay
			if remark == "ContinuousPay" {
				gainWay = common.GainWay_ActContinuousPay
			}
			dbShop = this.NewDbShop(p, 0, amount[:], ShopConsumeMoney, int32(wfs.Price2), gainWay, nil, 0, "", 0, remark, []int32{wfs.Day})
			err := model.InsertDbShopLog(dbShop)
			if err != nil {
				logger.Logger.Errorf("model.InsertDbShopLog err:", err)
				return nil
			}
			return webapi.API_CreateOrder(common.GetAppId(), dbShop.LogId.Hex(), ConfigPayId, p.SnId, 0, p.Platform, p.PackageID, p.DeviceOS,
				p.DeviceId, "FirstRecharge", amount, int32(wfs.Price2), nil, "")
		}
		return nil
	}), task.CompleteNotifyWrapper(func(retdata interface{}, t task.Task) {
		logger.Logger.Trace("API_CreateOrder:", retdata)
		pack := &shop.SCPayInfo{
			RetCode: shop.OpResultCode_OPRC_Error,
		}
		if retdata == nil {
			p.SendToClient(int(shop.SPacketID_PACKET_SCPAYINFO), pack)
			return
		}
		info := retdata.(*webapi_proto.ASCreateOrder)
		if info == nil || info.Tag != 0 {
			logger.Logger.Errorf("SCPayInfo:Tag[%v] Msg[%v] Url[%v]", info.Tag, info.Msg, info.Url)
			//失败
			p.SendToClient(int(shop.SPacketID_PACKET_SCPAYINFO), pack)
		} else {
			pack.RetCode = shop.OpResultCode_OPRC_Sucess
			pack.Url = info.Url
			logger.Logger.Trace("SCPayInfo:", pack)
			p.SendToClient(int(shop.SPacketID_PACKET_SCPAYINFO), pack)
		}
	}), "API_CreateOrder").Start()
}

func (this *ShopMgr) StartTimer(SnId int32, afterTs int32) {
	timer.StartTimer(timer.TimerActionWrapper(func(h timer.TimerHandle, ud interface{}) bool {
		p := PlayerMgrSington.GetPlayerBySnId(SnId)
		if p == nil || !p.IsOnLine() {
			return true
		}
		this.ShopCheckShowRed(p)
		return true
	}), nil, time.Duration(afterTs)*time.Second, 1)
}

func (this *ShopMgr) Update() {

}

func (this *ShopMgr) Shutdown() {
	module.UnregisteModule(this)
}

func init() {
	module.RegisteModule(ShopMgrSington, time.Second, 0)
}
