package models

import (
	"encoding/json"
	"errors"
	"fmt"
	"github.com/gin-gonic/gin"
	"github.com/xuri/excelize/v2"
	orm "go-admin/common/global"
	"go-admin/logger"
	"go-admin/tools"
	"go-admin/tools/config"
	"gorm.io/gorm"
	"strconv"
	"strings"
	"time"
)

type GameCard struct {
	Model

	Name            string   `json:"name" gorm:"column:name;index"`                  // 名称
	Price           uint32   `json:"price" gorm:"column:price;index"`                // 价格
	CoverImg        string   `json:"coverImg" gorm:"column:cover_img"`               // 封面
	OrderCount      uint32   `json:"orderCount" gorm:"column:order_count;index"`     // 订单数
	NewProducts     uint8    `json:"newProducts"`                                    // 新品: 1-新品 2-非新品
	Status          uint8    `json:"status"`                                         // 状态: 1-上架 2-下架
	GameTypeId      uint32   `json:"gameTypeId"`                                     // 游戏类型id
	GoodsGalleryUrl string   `json:"goodsGalleryUrl" gorm:"type:text;comment:'轮播图'"` // 轮播图
	ViewCount       uint32   `json:"viewCount"`                                      // 查看人数
	Playability     uint32   `json:"playability"`                                    // 耐玩度
	Playfulness     uint32   `json:"playfulness"`                                    // 好玩度
	GameTime        uint32   `json:"gameTime"`                                       // 游戏时间
	Likes           uint32   `json:"likes"`                                          // 点赞
	DetailInfo      string   `json:"detailInfo" gorm:"type:text;comment:'详情描述'"`     // 详情描述
	DetailImg       string   `json:"detailImg"`                                      // 详情图片
	EstimateVm      uint32   `json:"estimate_vm" gorm:"-"`                           // 预计积分
	RealPrice       uint32   `json:"real_price"`                                     // 真实价格
	VideoLink       string   `json:"video_link"`                                     // 链接
	HomeCategoryId  []uint32 `json:"home_category_id" gorm:"-"`                      // 首页分类ID
}

func (*GameCard) TableName() string {
	return "game_card"
}

// gen:qs
type GameCardLabel struct {
	Model

	GameCardId uint32 `json:"game_card_id" gorm:"index"`
	GameLabel  string `json:"game_label" gorm:"index"`
}

func (*GameCardLabel) TableName() string {
	return "game_card_label"
}

func GetGameCardList(gameType, status, page, pageSize int, key string) ([]GameCard, uint32, uint32, error) {
	var (
		cards     = make([]GameCard, 0)
		totalPage uint32
	)
	page -= 1
	if page < 0 {
		page = 0
	}

	gdb := orm.Eloquent.Table("game_card").Where("id!=?", 914)

	if gameType != 0 {
		//gdb = gdb.Where("game_type_id", gameType)
		// TODO
		fmt.Println("gameType", gameType)
		gameId, err := GameType{}.GetGameCardByType([]int{gameType})
		if err != nil {
			logger.Error(err.Error())
		}
		fmt.Println("gameId", gameId)
		if len(gameId) > 0 {
			gdb = gdb.Where("id  in (?)", gameId)
		} else {

		}
	}
	if status != 0 {
		gdb = gdb.Where("status", status)
	}
	if key != "" {
		gdb = gdb.Where("name LIKE ?", "%"+key+"%")
	}

	var count int64
	err := gdb.Count(&count).Error
	if err != nil {
		logger.Errorf(err.Error())
		return cards, 0, 0, err
	}

	err = gdb.Order("created_at DESC").Offset(page * pageSize).Limit(pageSize).Find(&cards).Error

	if err != nil && err != RecordNotFound {
		logger.Errorf(err.Error())
		return cards, 0, 0, err
	}

	// 查询每个 GameCard 的 home_category_id 数据
	gameIds := make([]uint32, len(cards))
	for i, card := range cards {
		gameIds[i] = card.ID
	}

	// 从 home_category_game 表中查询关联的 home_category_id
	var categoryMappings []struct {
		GameID         uint32 `json:"game_id"`
		HomeCategoryID uint32 `json:"home_category_id"`
	}
	err = orm.Eloquent.Table("home_category_game").
		Where("game_id IN (?)", gameIds).
		Select("game_id, home_category_id").
		Find(&categoryMappings).Error
	if err != nil {
		logger.Errorf("Failed to fetch home_category_game mappings: %v", err)
		return cards, 0, 0, err
	}

	// 将查询结果映射到 GameCard 的 HomeCategoryId 字段
	categoryMap := make(map[uint32][]uint32)
	for _, mapping := range categoryMappings {
		categoryMap[mapping.GameID] = append(categoryMap[mapping.GameID], mapping.HomeCategoryID)
	}

	for i := range cards {
		cards[i].HomeCategoryId = categoryMap[cards[i].ID]
	}

	totalPage = uint32(int(count)/pageSize + 1)

	return cards, totalPage, uint32(count), nil
}

type GetGameCardGoodsListReq struct {
	Page         int    `json:"pageIndex"`
	PageSize     int    `json:"pageSize"`
	StoreId      uint32 `json:"store_id"`
	Status       int    `json:"status"`
	GameCardId   int    `json:"game_card_id"`
	SerialNumber string `json:"serial_number" ` // 编号
}
type GetGameCardGoodsListResp struct {
	List      []GameCardGoods `json:"list"`
	Total     int             `json:"total"`
	PageIndex int             `json:"pageIndex"`
	TotalPage int             `json:"total_page"`
}

func (m *GetGameCardGoodsListReq) GetGameCardGoodsList(c *gin.Context) (*GetGameCardGoodsListResp, error) {
	var (
		cardGoods = make([]GameCardGoods, 0)
		totalPage uint32
	)
	m.Page -= 1
	if m.Page < 0 {
		m.Page = 0
	}
	if m.PageSize == 0 {
		m.PageSize = 10
	}
	resp := &GetGameCardGoodsListResp{List: cardGoods, PageIndex: m.Page}
	fmt.Println("GetGameCardGoodsListReq:", m)
	gdb := orm.Eloquent.Table("game_card_goods")

	// 非管理员才判断所属门店
	if !(tools.GetRoleName(c) == "admin" || tools.GetRoleName(c) == "系统管理员") {
		sysUser, err := GetSysUserByCtx(c)
		if err != nil {
			return nil, err
		}

		// 返回sysUser未过期的门店id列表
		storeList := GetValidStoreIDs(sysUser.StoreData)
		if m.StoreId != 0 {
			if !Contains(storeList, uint32(m.StoreId)) {
				return nil, errors.New("您没有该门店权限")
			}
		} else {
			if len(storeList) > 0 {
				if len(storeList) == 1 {
					gdb = gdb.Where("store_id = ?", storeList[0])
				} else {
					gdb = gdb.Where("store_id IN (?)", storeList)
				}
			} else {
				return nil, errors.New("用户未绑定门店")
			}
		}
	}

	if m.Status != 0 {
		gdb = gdb.Where("status=?", m.Status)
	}
	if m.StoreId != 0 {
		gdb = gdb.Where("store_id=?", m.StoreId)
	}
	if m.GameCardId != 0 {
		gdb = gdb.Where("game_card_id=?", m.GameCardId)
	}
	if m.SerialNumber != "" {
		gdb = gdb.Where("serial_number=?", m.SerialNumber)
	}
	var count int64
	err := gdb.Count(&count).Error
	if err != nil {
		logger.Errorf(err.Error())
		return resp, err
	}
	resp.Total = int(count)
	err = gdb.Order("created_at DESC").Offset(m.Page * m.PageSize).Limit(m.PageSize).Find(&cardGoods).Error
	if err != nil && err != RecordNotFound {
		logger.Errorf(err.Error())
		return resp, err
	}

	if len(cardGoods) > 0 {
		storeIds := make([]uint32, 0)
		gameCardIds := make([]uint32, 0)

		for i, _ := range cardGoods {
			storeIds = append(storeIds, uint32(cardGoods[i].StoreId))
			gameCardIds = append(gameCardIds, uint32(cardGoods[i].GameCardId))
		}

		cardMap := GetGameCardMapByIds(gameCardIds)
		storeMap := GetStoreMapByIds(storeIds)

		for i, _ := range cardGoods {
			gameCard, ok1 := cardMap[cardGoods[i].GameCardId]
			if ok1 {
				cardGoods[i].GameCard = gameCard
			}
			store, ok2 := storeMap[cardGoods[i].StoreId]
			if ok2 {
				cardGoods[i].Store = store
			}
		}
	}

	totalPage = uint32(int(count)/m.PageSize + 1)
	resp.TotalPage = int(totalPage)
	resp.List = cardGoods
	return resp, nil
}

type CooperativeGameCardGoodsReq struct {
	StoreId               uint32 `json:"store_id"`
	CooperativeBusinessId uint32 `json:"cooperative_business_id"`
	Status                int    `json:"status"`
	GameCardId            int    `json:"game_card_id"`
	SerialNumber          string `json:"serial_number" ` // 编号
	PageIndex             int    `json:"pageIndex"`
	PageSize              int    `json:"pageSize"`
}
type CooperativeGameCardGoodsResp struct {
	List      []GameCardGoods `json:"list"`
	Total     int             `json:"total"`
	PageIndex int             `json:"pageIndex"`
	PageSize  int             `json:"pageSize"`
}

func (m *CooperativeGameCardGoodsReq) List() (*CooperativeGameCardGoodsResp, error) {
	var (
		cardGoods = make([]GameCardGoods, 0)
		totalPage uint32
	)
	m.PageIndex -= 1
	if m.PageIndex < 0 {
		m.PageIndex = 0
	}
	if m.PageSize == 0 {
		m.PageSize = 10
	}
	resp := &CooperativeGameCardGoodsResp{
		List:      cardGoods,
		PageIndex: m.PageIndex,
		PageSize:  m.PageSize,
	}
	fmt.Println("GetGameCardGoodsListReq:", m)
	gdb := orm.Eloquent.Table("game_card_goods")
	if m.Status != 0 {
		gdb = gdb.Where("status=?", m.Status)
	}

	if m.StoreId != 0 {
		gdb = gdb.Where("store_id=?", m.StoreId)
	} else {
		storeIds, err := GetStoreIdsByCooperativeBusinessId(m.CooperativeBusinessId)
		if err != nil {
			logger.Error("get store ids err:", logger.Field("err", err))
			return resp, err
		}
		if len(storeIds) > 0 {
			gdb = gdb.Where("store_id in (?)", storeIds)
		}
	}
	if m.GameCardId != 0 {
		gdb = gdb.Where("game_card_id=?", m.GameCardId)
	}
	if m.SerialNumber != "" {
		gdb = gdb.Where("serial_number=?", m.SerialNumber)
	}
	var count int64
	err := gdb.Count(&count).Error
	if err != nil {
		logger.Errorf(err.Error())
		return resp, err
	}
	resp.Total = int(count)
	err = gdb.Order("created_at DESC").Offset(m.PageIndex * m.PageSize).Limit(m.PageSize).Find(&cardGoods).Error
	if err != nil && err != RecordNotFound {
		logger.Errorf(err.Error())
		return resp, err
	}

	if len(cardGoods) > 0 {
		storeIds := make([]uint32, 0)
		gameCardIds := make([]uint32, 0)

		for i, _ := range cardGoods {
			storeIds = append(storeIds, uint32(cardGoods[i].StoreId))
			gameCardIds = append(gameCardIds, uint32(cardGoods[i].GameCardId))
		}

		cardMap := GetGameCardMapByIds(gameCardIds)
		storeMap := GetStoreMapByIds(storeIds)

		for i, _ := range cardGoods {
			gameCard, ok1 := cardMap[cardGoods[i].GameCardId]
			if ok1 {
				cardGoods[i].GameCard = gameCard
			}
			store, ok2 := storeMap[cardGoods[i].StoreId]
			if ok2 {
				cardGoods[i].Store = store
			}
		}
	}

	totalPage = uint32(int(count)/m.PageSize + 1)
	resp.PageSize = int(totalPage)
	resp.List = cardGoods
	return resp, nil
}

func GetGameCardMapByIds(gameCardIds []uint32) map[uint64]*GameCard {
	gameCardMap := make(map[uint64]*GameCard, 0)
	if len(gameCardIds) == 0 {
		return gameCardMap
	}
	var gameCards []GameCard
	err := orm.Eloquent.Table("game_card").Where("id in (?)", gameCardIds).Find(&gameCards).Error
	if err != nil {
		logger.Error(err.Error())
	}

	if len(gameCards) == 0 {
		return gameCardMap
	}
	for i, _ := range gameCards {
		gameCardMap[uint64(gameCards[i].ID)] = &gameCards[i]
	}
	return gameCardMap
}

func GetStoreMapByIds(storeIds []uint32) map[uint64]*Store {
	storeMap := make(map[uint64]*Store, 0)
	if len(storeIds) == 0 {
		return storeMap
	}
	var stores []Store
	err := orm.Eloquent.Table("store").Where("id in (?)", storeIds).Find(&stores).Error
	if err != nil {
		logger.Error(err.Error())
	}

	if len(stores) == 0 {
		return storeMap
	}
	for i, _ := range stores {
		storeMap[uint64(stores[i].ID)] = &stores[i]
	}
	return storeMap
}

func StoreMapByIds(storeIds []uint32) map[uint64]Store {
	storeMap := make(map[uint64]Store, 0)
	if len(storeIds) == 0 {
		return storeMap
	}
	var stores []Store
	err := orm.Eloquent.Table("store").Where("id in (?)", storeIds).Find(&stores).Error
	if err != nil {
		logger.Error(err.Error())
	}

	if len(stores) == 0 {
		return storeMap
	}
	for i, _ := range stores {
		storeMap[uint64(stores[i].ID)] = stores[i]
	}
	return storeMap
}

func (m *GameCard) Add() error {
	m.OrderCount = 0
	m.ViewCount = 0
	m.Likes = 0
	if m.NewProducts == 0 {
		m.NewProducts = 2
	}
	err := orm.Eloquent.Create(m).Error
	if err != nil {
		logger.Errorf(err.Error())
		return err
	}
	return nil
}

//func (m *GameCard) Modify() error {
//	para := m.getModifyPara()
//	if len(para) > 0 {
//		err := orm.Eloquent.Table("game_card").Unscoped().Where("id", m.ID).Updates(para).Error
//		if err != nil {
//			logger.Errorf(err.Error())
//			return err
//		}
//	}
//	return nil
//}

func (m *GameCard) Modify() error {
	// 获取需要更新的字段
	para := m.getModifyPara()
	if len(para) > 0 {
		// 更新 game_card 表
		err := orm.Eloquent.Table("game_card").Unscoped().Where("id = ?", m.ID).Updates(para).Error
		if err != nil {
			logger.Errorf("Failed to update game_card, id: %d, err: %v", m.ID, err)
			return err
		}
	}

	// 删除与 game_id 相关的所有 home_category_game 记录
	err := orm.Eloquent.Table("home_category_game").
		Where("game_id = ?", m.ID).
		Delete(&HomeCategoryGame{}).Error
	if err != nil {
		logger.Errorf("Failed to delete home_category_game records for game_id: %d, err: %v", m.ID, err)
		return err
	}

	// 新增当前 HomeCategoryId 的所有记录
	if len(m.HomeCategoryId) > 0 {
		var newRecords []HomeCategoryGame
		for _, categoryID := range m.HomeCategoryId {
			// 查询新的 HomeCategoryId 的最大排序值
			type MaxSortOrderResult struct {
				MaxSortOrder int `json:"max_sort_order"` // 数据库字段类型应与此字段匹配
			}

			var result MaxSortOrderResult
			err = orm.Eloquent.Table("home_category_game").
				Where("home_category_id = ?", categoryID).
				Select("COALESCE(MAX(sort_order), 0) AS max_sort_order").
				Scan(&result).Error
			if err != nil {
				logger.Errorf("Failed to fetch max sort_order for home_category_id: %d, err: %v", categoryID, err)
				return err
			}

			// 构建新的记录
			newRecords = append(newRecords, HomeCategoryGame{
				HomeCategoryID: categoryID,
				GameID:         m.ID,
				GameName:       m.Name,
				SortOrder:      result.MaxSortOrder + 1,
			})
		}

		// 批量插入记录
		err = orm.Eloquent.Table("home_category_game").Create(&newRecords).Error
		if err != nil {
			logger.Errorf("Failed to create new home_category_game records for game_id: %d, err: %v", m.ID, err)
			return err
		}
	}

	return nil
}

func (m *GameCard) getModifyPara() map[string]interface{} {
	paraMap := make(map[string]interface{}, 0)
	if m.Name != "" {
		paraMap["name"] = m.Name
	}
	if m.Price != 0 {
		paraMap["price"] = m.Price
	}
	if m.CoverImg != "" {
		paraMap["cover_img"] = m.CoverImg
	}
	if m.NewProducts != 0 {
		paraMap["new_products"] = m.NewProducts
	}
	if m.Status != 0 {
		paraMap["status"] = m.Status
	}
	if m.GameTypeId != 0 {
		paraMap["game_type_id"] = m.GameTypeId
	}
	if m.GoodsGalleryUrl != "" {
		paraMap["goods_gallery_url"] = m.GoodsGalleryUrl
	}
	if m.Playability != 0 {
		paraMap["playability"] = m.Playability
	}
	if m.Playfulness != 0 {
		paraMap["playfulness"] = m.Playfulness
	}
	if m.GameTime != 0 {
		paraMap["game_time"] = m.GameTime
	}
	if m.DetailInfo != "" {
		paraMap["detail_info"] = m.DetailInfo
	}
	if m.DetailImg != "" {
		paraMap["detail_img"] = m.DetailImg
	}
	if m.RealPrice != 0 {
		paraMap["real_price"] = m.RealPrice
	}
	if m.VideoLink != "" {
		paraMap["video_link"] = m.VideoLink
	}
	return paraMap
}

func (m *GameCard) MDel(ids []uint32) error {
	err := orm.Eloquent.Table(m.TableName()).Unscoped().Where("id in (?)", ids).Delete(m).Error
	if err != nil {
		logger.Errorf(err.Error())
		return err
	}
	return nil
}

// gen:qs
type GameCardType struct {
	Model

	Name string `json:"name"`              // 游戏类型
	Sort uint32 `json:"sort" gorm:"index"` // 排序
	//GameCount uint32 `json:"game_count"`        // 游戏数量
}

func (*GameCardType) TableName() string {
	return "game_card_type"
}

func GetGameCardTypeList() ([]GameCardType, error) {
	var cardTypes []GameCardType
	err := orm.Eloquent.Table("game_card_type").Unscoped().Order("sort ASC").Find(&cardTypes).Error
	if err != nil {
		logger.Errorf(err.Error())
		return cardTypes, err
	}
	return cardTypes, nil
}

func (m *GameCardType) Modify() error {
	paraMap := make(map[string]interface{}, 0)
	if m.Name != "" {
		paraMap["name"] = m.Name
	}
	if m.Sort > 0 {
		paraMap["sort"] = m.Sort
	}
	err := orm.Eloquent.Table(m.TableName()).Unscoped().Where("id", m.ID).Updates(paraMap).Error
	if err != nil {
		logger.Errorf(err.Error())
		return err
	}
	return nil

}

func (m *GameCardType) Add() error {
	err := orm.Eloquent.Create(m).Error
	if err != nil {
		logger.Errorf(err.Error())
		return err
	}
	return nil
}

func (m *GameCardType) MDel(ids []uint32) error {
	gameCard := &GameCard{}
	cardDb := orm.Eloquent.Table(gameCard.TableName()).Unscoped()

	cardTypeIds := make([]uint32, 0)
	count := int64(0)
	for _, id := range ids {
		err := cardDb.Where("game_type_id", id).Count(&count).Error
		if err != nil {
			logger.Errorf(err.Error())
			continue
		}
		if count == 0 {
			cardTypeIds = append(cardTypeIds, id)
		}
	}
	err := orm.Eloquent.Table(m.TableName()).Unscoped().Where("id in (?)", cardTypeIds).Delete(m).Error
	if err != nil {
		logger.Errorf(err.Error())
		return err
	}

	return nil
}

type GameType struct {
	Model

	GameCardId     uint64 `json:"gameCardId" gorm:"column:game_card_id;index"`          // 游戏卡id
	GameCardTypeId uint64 `json:"gameCardTypeId" gorm:"column:game_card_type_id;index"` // 分类id
}

func (*GameType) TableName() string {
	return "game_type"
}

func GameCardAddType(ids []int, gameId int) error {
	if len(ids) == 0 {
		return nil
	}
	for i, _ := range ids {
		gameType := &GameType{
			GameCardId:     uint64(gameId),
			GameCardTypeId: uint64(ids[i]),
		}
		err := orm.Eloquent.Create(gameType).Error
		if err != nil {
			logger.Error(err.Error())
			continue
		}
	}
	return nil
}

func (m GameType) GetGameCardByType(ids []int) ([]int, error) {
	var games []GameType
	err := orm.Eloquent.Table(m.TableName()).Where("game_card_type_id in (?)", ids).Find(&games).Error
	if err != nil {
		logger.Error(err.Error())
		return nil, err
	}
	gameId := make([]int, 0, len(games))
	for i, _ := range games {
		gameId = append(gameId, int(games[i].GameCardId))
	}
	return gameId, nil
}

func (m GameType) GameCardTypeModify(ids []int) error {
	err := orm.Eloquent.Unscoped().Table(m.TableName()).Where("game_card_id", m.GameCardId).Delete(m).Error
	if err != nil {
		logger.Error(err.Error())
		return err
	}

	err = GameCardAddType(ids, int(m.GameCardId))
	if err != nil {
		logger.Error(err.Error())
		return err
	}
	return nil
}

func (m GameCard) GetGameType() ([]GameCardType, error) {
	gameCardTypes := make([]GameCardType, 0)
	gameTypes := make([]GameType, 0)
	err := orm.Eloquent.Unscoped().Table("game_type").Where("game_card_id", m.ID).Find(&gameTypes).Error
	if err != nil {
		logger.Error(err.Error())
		return gameCardTypes, err
	}
	gameCardTypeId := make([]uint32, 0)
	for i, _ := range gameTypes {
		gameCardTypeId = append(gameCardTypeId, uint32(gameTypes[i].GameCardTypeId))
	}
	err = orm.Eloquent.Unscoped().Table("game_card_type").Where("id in (?)", gameCardTypeId).Find(&gameCardTypes).Error
	if err != nil {
		logger.Error(err.Error())
		return gameCardTypes, err
	}
	return gameCardTypes, nil
}

type RspAliyunStsToken struct {
	AccessKeyId     string `json:"accessKeyId"`
	AccessKeySecret string `json:"accessKeySecret"`
	SecurityToken   string `json:"SecurityToken"`
	BucketName      string `json:"bucketName"`
	Expiration      uint64 `json:"expiration"`
}

type HomeCarousel struct {
	Model

	Name   string `json:"name" gorm:"index"` // 名称
	Img    string `json:"img"`               // 图片
	Sort   uint32 `json:"sort" gorm:"index"`
	IsShow uint32 `json:"is_show"`
	Detail string `json:"detail"`
	Link   string `json:"link"`
}

func (*HomeCarousel) TableName() string {
	return "home_carousel"
}

func (*HomeCarousel) List() ([]HomeCarousel, error) {
	carousels := make([]HomeCarousel, 0)
	err := orm.Eloquent.Table("home_carousel").Order("sort desc").Find(&carousels).Error
	if err != nil {
		logger.Error(err.Error())
		return carousels, err
	}

	return carousels, nil
}

func (m *HomeCarousel) Add() error {
	err := orm.Eloquent.Create(m).Error
	if err != nil {
		logger.Error(err.Error())
		return err
	}

	return nil
}

func (m *HomeCarousel) Del() error {
	err := orm.Eloquent.Table("home_carousel").Where("id", m.ID).Delete(m).Error
	if err != nil {
		logger.Error(err.Error())
		return err
	}

	return nil
}

type HomeCarouselModifyReq struct {
	ID         uint32    `json:"id"`
	Name       string    `json:"name" gorm:"index"` // 名称
	Img        string    `json:"img"`               // 图片
	Sort       uint32    `json:"sort" gorm:"index"`
	IsShow     uint32    `json:"is_show"`
	Detail     string    `json:"detail"`
	Link       string    `json:"link"`
	CreateTime time.Time `json:"create_time"`
}

func (m *HomeCarouselModifyReq) Modify() error {
	paraMap := make(map[string]interface{})
	if m.Name != "" {
		paraMap["name"] = m.Name
	}
	if m.Img != "" {
		paraMap["img"] = m.Img
	}
	if m.Sort != 0 {
		paraMap["sort"] = m.Sort
	}
	if m.IsShow != 0 {
		paraMap["is_show"] = m.IsShow == 1
	}
	if m.Detail != "" {
		paraMap["detail"] = m.Detail
	}
	if m.Link != "" {
		paraMap["link"] = m.Link
	}
	paraMapJson, _ := json.Marshal(&paraMap)
	fmt.Println("paraMapJson:", string(paraMapJson))

	carousel := &HomeCarousel{}
	carousel.ID = m.ID
	err := orm.Eloquent.Table("home_carousel").Where("id", m.ID).Updates(&paraMap).Error
	if err != nil {
		logger.Error(err.Error())
		return err
	}

	return nil
}

const (
	GameCardGoodsStatusStock         = 1 // 库存中
	GameCardGoodsStatusInWay         = 2 // 在途
	GameCardGoodsStatusCustomerHold  = 3 // 客户持有
	GameCardGoodsStatusCannibalize   = 4 // 调拨
	GameCardGoodsStatusReceivingCard = 5 //
	GameCardGoodsStatusReceivedCard  = 6 // 调拨
	GameCardGoodsStatusUnusual       = 7 // 异常
)

const (
	GameCardGoodsTypeShare  = "user_share" // 用户共享
	GameCardGoodsTypeCommon = "common"     // 公共
)

// gen:qs
type GameCardGoods struct {
	Model

	GameCardId            uint64    `json:"game_card_id"`                         // 游戏卡id
	SerialNumber          string    `json:"serial_number" gorm:"index"`           // 编号
	Status                uint8     `json:"status"`                               // 状态:1-库存中 2-在途 3-客户持有 4-调拨 5-待收回 6-已收回 7-锁定
	StoreId               uint64    `json:"store_id"`                             // 门店id
	Provider              string    `json:"provider"`                             // 供应商
	StockTime             time.Time `json:"stock_time"`                           // 入库时间
	CardType              string    `json:"card_type" gorm:"index"`               // -用户共享  -公共
	FunctionState         uint32    `json:"function_state"`                       // 1-异常 2-正常
	ShareProfitType       uint32    `json:"share_profit_type"`                    // 1-非共享收益卡 2-共享收益卡
	CooperativeBusinessId uint32    `json:"cooperative_business_id" gorm:"index"` // 合作商id
	CooperativeName       string    `json:"cooperative_name"`                     // 合作商名称
	Store                 *Store    `json:"store"  gorm:"-"`                      // 门店
	GameCard              *GameCard `json:"game_card" gorm:"-"`                   // 游戏

	//StockRemovalType  string             `json:"stock_removal_type"` // 出库类型: card_retrieve 收回卡 card_issue_retrieve 收回卡异常
	UserShareCardBill *UserShareCardBill `json:"user_share_card_bill" gorm:"-"`
}

func (*GameCardGoods) TableName() string {
	return "game_card_goods"
}

// GameCardGoodsStock
// 锁定数量 = 卡池总数 - 库存数量 - 客户持有数量
type GameCardGoodsStock struct {
	Model

	StoreId       uint64 `json:"store_id"`           // 门店id
	GameCardId    uint64 `json:"game_card_id"`       // 游戏卡id
	StoreStock    uint32 `json:"store_stock"`        // 门店库存
	RentStock     uint32 `json:"rent_stock"`         // 库存数量
	UserHoldStock uint32 `json:"user_hold_stock"`    // 客户持有数量
	OrderCount    uint32 `json:"order_count"`        // 订单数量
	TotalStock    uint32 `json:"total_stock"`        // 卡池总数
	Name          string `json:"name" gorm:"-"`      // 名称
	CoverImg      string `json:"cover_img" gorm:"-"` // 封面
}

func (*GameCardGoodsStock) TableName() string {
	return "game_card_goods_stock"
}

func (m *GameCardGoodsStock) ToInfo(card *GameCard) GameCardGoodsStockInfo {
	return GameCardGoodsStockInfo{
		GameCardGoodsStock: *m,
		GameName:           card.Name,
		GamePrice:          card.Price,
		GameCoverImg:       card.CoverImg,
	}
}

type GameCardGoodsStockInfo struct {
	GameCardGoodsStock
	GameName     string `json:"name" gorm:"index"`  // 名称
	GamePrice    uint32 `json:"price" gorm:"index"` // 价格
	GameCoverImg string `json:"cover_img"`          // 封面
}

type GameCardGoodsStockListReq struct {
	Page                  int    `json:"pageIndex"`
	PageSize              int    `json:"pageSize"`
	StoreId               uint64 `json:"store_id" `               // 门店id
	GameCardId            uint64 `json:"game_card_id"`            // 游戏卡id
	GameCardName          string `json:"game_card_name"`          // 游戏卡
	CooperativeBusinessId uint32 `json:"cooperative_business_id"` // 合作商id
}

type GameCardGoodsStockListResp struct {
	PageSize       int                      `json:"pageSize"`
	List           []GameCardGoodsStockInfo `json:"list"`
	Count          int                      `json:"total"`
	PageIndex      int                      `json:"pageIndex"`
	TotalPage      int                      `json:"total_page"`
	CardTotalCount int                      `json:"card_total_count"`
	CardTotalStock int                      `json:"card_total_stock"`
	CardHoldCount  int                      `json:"card_hold_count"`
	//"count":      count,
	//"list":       list,
	//"pageIndex":  req.PageIndex,
	//"total_page": req.PageSize,
	//StoreId      uint64 `json:"store_id" `      // 门店id
	//GameCardId   uint64 `json:"game_card_id"`   // 游戏卡id
	//GameCardName string `json:"game_card_name"` // 游戏卡
}

func (m *GameCardGoodsStockListReq) List(c *gin.Context) (*GameCardGoodsStockListResp, error) {
	resp := &GameCardGoodsStockListResp{PageIndex: m.Page, PageSize: m.PageSize}
	//resp.List
	resp.List = make([]GameCardGoodsStockInfo, 0)
	stocks := make([]GameCardGoodsStock, 0)
	qs := orm.Eloquent.Table("game_card_goods_stock").Where("store_id=?", m.StoreId)
	if m.GameCardId != 0 {
		qs = qs.Where("game_card_id", m.GameCardId)
	}

	// 非管理员才判断所属门店
	if !(tools.GetRoleName(c) == "admin" || tools.GetRoleName(c) == "系统管理员") {
		sysUser, err := GetSysUserByCtx(c)
		if err != nil {
			return nil, err
		}

		// 返回sysUser未过期的门店id列表
		storeList := GetValidStoreIDs(sysUser.StoreData)
		if m.StoreId != 0 {
			if !Contains(storeList, uint32(m.StoreId)) {
				return nil, errors.New("您没有该门店权限")
			}
		} else {
			if len(storeList) > 0 {
				if len(storeList) == 1 {
					qs = qs.Where("store_id = ?", storeList[0])
				} else {
					qs = qs.Where("store_id IN (?)", storeList)
				}
			} else {
				return nil, errors.New("用户未绑定门店")
			}
		}
	}

	if m.GameCardName != "" {
		var cards []GameCard
		err := orm.Eloquent.Table("game_card").Where("name  LIKE ?", "%"+m.GameCardName+"%").Find(&cards).Error
		if err != nil {
			logger.Error(err.Error())
			return resp, err
		}
		gameCardIds := make([]uint32, 0)
		for i, _ := range cards {
			gameCardIds = append(gameCardIds, cards[i].ID)
		}
		if len(gameCardIds) == 0 {
			logger.Error(err.Error())
			return resp, err
		}
		qs = qs.Where("game_card_id  IN (?)", gameCardIds)
	}
	//if m.CooperativeBusinessId != 0 {
	//	var stores []Store
	//	err := orm.Eloquent.Table("").Where("cooperative_business_id=?", m.CooperativeBusinessId).Find(&stores).Error
	//	if err != nil {
	//		logger.Error("stores err:", logger.Field("err", err))
	//		return resp, err
	//	}
	//	ids := make([]uint32, 0, len(stores))
	//	for i, _ := range stores {
	//		ids = append(ids, stores[i].ID)
	//	}
	//
	//	qs = qs.Where("store_id in (?)", ids)
	//}
	var count int64
	err := qs.Count(&count).Error
	if err != nil {
		logger.Error(err.Error())
		return resp, err
	}
	resp.Count = int(count)
	page := m.Page
	pageSize := m.PageSize
	page -= 1
	if page < 0 {
		page = 0
	}
	err = qs.Order("id DESC").Offset(page * pageSize).Limit(pageSize).Find(&stocks).Error
	if err != nil {
		logger.Error(err.Error())
		return resp, err
	}
	gameIds := make([]uint32, 0, len(stocks))
	for i, _ := range stocks {
		gameIds = append(gameIds, uint32(stocks[i].GameCardId))
	}
	if len(gameIds) == 0 {
		logger.Error("stockIds is nil")
		return resp, nil
	}
	games := make([]GameCard, 0)
	err = orm.Eloquent.Table("game_card").Where("id IN (?)", gameIds).Find(&games).Error
	if err != nil {
		logger.Errorf(err.Error())
		return resp, err
	}
	gameMap := make(map[uint32]GameCard, 0)
	for i, _ := range games {
		gameMap[games[i].ID] = games[i]
	}

	//type UserHold struct {
	//	CardCount  uint32 `json:"card_count"`
	//	StoreId    uint32 `json:"store_id"`
	//	GameCardId uint64 `json:"game_card_id"`
	//}
	//userHold := make([]UserHold, 0)
	//sqlHold := fmt.Sprintf("SELECT COUNT(game_card_id) AS card_count,store_id,game_card_id FROM (SELECT store_id,game_card_id FROM game_card_goods WHERE  store_id=%d AND status=3 ) store GROUP BY game_card_id;", m.StoreId)
	//err = orm.Eloquent.Raw(sqlHold).Scan(&userHold).Error
	//if err != nil {
	//	logger.Errorf(err.Error())
	//	return resp, err
	//}
	userHoldMap := make(map[uint64]uint32)
	totalCountMap := make(map[uint64]uint32)
	//for i, _ := range userHold {
	//	userHoldMap[userHold[i].GameCardId] = userHold[i].CardCount
	//	resp.CardHoldCount += int(userHold[i].CardCount)
	//}
	var gameCardGoods []GameCardGoods
	err = orm.Eloquent.Table("game_card_goods").Where("store_id", m.StoreId).Find(&gameCardGoods).Error
	if err != nil {
		logger.Errorf(err.Error())
		return resp, err
	}
	for i, _ := range gameCardGoods {
		if gameCardGoods[i].Status == GameCardGoodsStatusCustomerHold {
			userHoldMap[gameCardGoods[i].GameCardId] += 1
			resp.CardHoldCount += 1
		}
		if gameCardGoods[i].Status != GameCardGoodsStatusReceivingCard && gameCardGoods[i].Status != GameCardGoodsStatusReceivedCard {
			totalCountMap[gameCardGoods[i].GameCardId] += 1
		}
	}

	for i, _ := range stocks {
		game, ok := gameMap[uint32(stocks[i].GameCardId)]
		if ok {
			if v, ok := userHoldMap[stocks[i].GameCardId]; ok {
				stocks[i].UserHoldStock = v
			}
			if v, ok := totalCountMap[stocks[i].GameCardId]; ok {
				stocks[i].TotalStock = v
			}
			resp.List = append(resp.List, stocks[i].ToInfo(&game))
		}
	}

	var rentStock uint32
	var cardStocks []GameCardGoodsStock
	err = orm.Eloquent.Table("game_card_goods_stock").Where("store_id", m.StoreId).Find(&cardStocks).Error
	if err != nil {
		logger.Errorf(err.Error())
		return resp, err
	}
	for i, _ := range cardStocks {
		rentStock += cardStocks[i].RentStock
	}
	//var game GameCardGoods
	var totalCount int64
	err = orm.Eloquent.Table("game_card_goods").Where("store_id", m.StoreId).
		Where("status in (?)", []uint32{1, 2, 3, 4}).Count(&totalCount).Error
	if err != nil {
		logger.Errorf(err.Error())
		return resp, err
	}

	resp.CardTotalStock = int(rentStock)
	resp.CardTotalCount = int(totalCount)
	return resp, nil
}

type GameCardGoodsStockCardListReq struct {
	Page       int    `json:"pageIndex"`
	PageSize   int    `json:"pageSize"`
	GameCardId uint64 `json:"game_card_id"` // 游戏id
	StoreId    uint64 `json:"store_id"`     // 门店id
	Status     uint8  `json:"status"`       // 状态:1-库存中 2-在途 3-客户持有
}

func (m *GameCardGoodsStockCardListReq) List() ([]GameCardGoods, int64, error) {
	goodses := make([]GameCardGoods, 0)
	qs := orm.Eloquent.Table("game_card_goods").Where("game_card_id", m.GameCardId).Where("store_id", m.StoreId)
	if m.Status != 0 {
		qs = qs.Where("status", m.Status)
	}
	var count int64
	err := qs.Count(&count).Error
	if err != nil {
		logger.Error(err.Error())
		return goodses, 0, err
	}
	page := m.Page
	pageSize := m.PageSize
	page -= 1
	if page < 0 {
		page = 0
	}

	err = qs.Order("created_at DESC").Offset(page * pageSize).Limit(pageSize).Find(&goodses).Error
	if err != nil {
		logger.Error(err.Error())
		return goodses, 0, err
	}
	return goodses, count, err
}

func (*GameCardGoods) Adds(cards []GameCardGoods) error {
	for i, _ := range cards {
		//err := orm.Eloquent.FirstOrCreate(&cards[i]).Error
		var count int64
		err := orm.Eloquent.Table("game_card_goods").Where("serial_number", cards[i].SerialNumber).Count(&count).Error
		if err != nil {
			logger.Error(err.Error())
			continue
		}
		if count == 0 {
			begin := orm.Eloquent.Begin()
			// 入库 公共添加数据
			cards[i].StockTime = time.Now()

			cards[i].FunctionState = 2

			//err = orm.Eloquent.Create(&cards[i]).Error
			err = begin.Create(&cards[i]).Error
			if err != nil {
				begin.Rollback()
				logger.Error(err.Error())
				continue
			}

			stock := GameCardGoodsStock{StoreId: cards[i].StoreId, GameCardId: cards[i].GameCardId}
			err = stock.Add(begin)
			if err != nil {
				begin.Rollback()
				logger.Error(err.Error())
				continue
			}
			if cards[i].CardType == GameCardGoodsTypeShare {
				userShareCard := &UserShareCard{
					Uid:                 cards[i].UserShareCardBill.Uid,
					SerialNumber:        cards[i].SerialNumber,
					BillSn:              cards[i].UserShareCardBill.BillSn,
					GameCardId:          uint32(cards[i].GameCardId),
					State:               ShareCardStateSharing,
					GameCardGoodsId:     cards[i].ID,
					UserShareCardBillId: cards[i].UserShareCardBill.ID,
					ShareCardBillGameId: 0,
					StoreId:             uint32(cards[i].StoreId),
					ProfitState:         1,
				}
				if cards[i].CardType == GameCardGoodsTypeShare {
					userShareCard.AllotSerialNumber = userShareCard.SerialNumber
					userShareCard.AllotCardGoodsId = userShareCard.GameCardGoodsId
				}
				err = begin.Create(userShareCard).Error
				if err != nil {
					begin.Rollback()
					logger.Error(err.Error())
					return err
				}

			}
			err := begin.Commit().Error
			if err != nil {
				begin.Rollback()
				logger.Error(err.Error())
				continue
			}
		}

	}
	return nil
}

type GameCardGoodsStockDelsReq struct {
	SerialNumberList []string `json:"serial_number_list"`
}

func (*GameCardGoods) Dels(serials []string, c *gin.Context) error {
	if len(serials) == 0 {
		return nil
	}

	sysUser, err := GetSysUserByCtx(c)
	if err != nil {
		return err
	}

	//serials := make([]string, 0)
	//for i, _ := range cards {
	//	serials = append(serials, cards[i].SerialNumber)
	//}
	list := make([]GameCardGoods, 0)
	err = orm.Eloquent.Table("game_card_goods").Where("serial_number in (?)", serials).Find(&list).Error
	if err != nil {
		logger.Error(err.Error())
		return err
	}

	for i, _ := range list {
		if list[i].Status != 1 {
			continue
		}
		if list[i].CardType == GameCardGoodsTypeShare {
			continue
		}
		var cardGoodsStock GameCardGoodsStock
		err = orm.Eloquent.Table("game_card_goods_stock").Where("store_id", list[i].StoreId).Where("game_card_id", list[i].GameCardId).Find(&cardGoodsStock).Error
		if err != nil {
			logger.Error(err.Error())
			continue
		}
		if cardGoodsStock.RentStock < 1 {
			//continue
			return errors.New("该卡带库存数量已为0")
		}

		begin := orm.Eloquent.Begin()
		err = begin.Table("game_card_goods").Where("serial_number", list[i].SerialNumber).Delete(&GameCardGoods{}).Error
		if err != nil {
			begin.Rollback()
			logger.Error(err.Error())
			return err
		}

		sql := fmt.Sprintf("UPDATE game_card_goods_stock SET rent_stock= rent_stock-1,store_stock=store_stock-1,total_stock=total_stock-1 WHERE store_id=%d AND game_card_id=%d;", list[i].StoreId, list[i].GameCardId)
		fmt.Println("sql:", sql)
		err = begin.Exec(sql).Error
		if err != nil {
			begin.Rollback()
			logger.Errorf(err.Error())
			return err
		}

		// 记录到出库明细表
		nowTime := time.Now()
		var record GameCardOutRecord
		record.SerialNumber = list[i].SerialNumber
		record.StoreId = list[i].StoreId
		record.GameCardId = list[i].GameCardId
		record.FirstStockTime = &list[i].CreatedAt
		record.StockTime = &list[i].StockTime
		record.OutStockTime = &nowTime
		record.MakerId = uint32(sysUser.UserId)
		record.MakerName = sysUser.NickName

		err = begin.Create(&record).Error
		if err != nil {
			begin.Rollback()
			logger.Errorf(err.Error())
			return err
		}

		err = begin.Commit().Error
		if err != nil {
			begin.Rollback()
			logger.Error("commit err:", logger.Field("err", err))
			return err
		}

	}
	return nil
}

func (m *GameCardGoodsStock) Add(begin *gorm.DB) error {
	var count int64
	err := orm.Eloquent.Table("game_card_goods_stock").Where("store_id", m.StoreId).
		Where("game_card_id", m.GameCardId).Count(&count).Error
	if err != nil {
		logger.Error(err.Error())
		return err
	}
	if count == 0 {
		m.StoreStock = 1
		m.RentStock = 1
		m.TotalStock = 1
		//err := orm.Eloquent.Create(m).Error
		err := begin.Create(m).Error
		if err != nil {
			logger.Error(err.Error())
			return err
		}
		return nil
	}

	sql := fmt.Sprintf("UPDATE game_card_goods_stock SET rent_stock= rent_stock+1,store_stock=store_stock+1,total_stock=total_stock+1 WHERE store_id=%d AND game_card_id=%d;", m.StoreId, m.GameCardId)
	fmt.Println("sql:", sql)
	err = begin.Exec(sql).Error
	if err != nil {
		logger.Errorf(err.Error())
		return err
	}
	return nil
}

func (m *GameCardGoodsStock) Del() error {
	sql := fmt.Sprintf("UPDATE game_card_goods_stock SET rent_stock= rent_stock-1,store_stock=store_stock-1 WHERE store_id=%d AND game_card_id=%d;", m.StoreId, m.GameCardId)
	fmt.Println("sql:", sql)
	err := orm.Eloquent.Exec(sql).Error
	if err != nil {
		logger.Errorf(err.Error())
		return err
	}
	return nil
}

func GameCardBatchStand(standType uint32) error {
	var gamees []GameCard
	err := orm.Eloquent.Table("game_card").Find(&gamees).Error
	if err != nil {
		logger.Error(err.Error())
		return err
	}

	//gameIds := make([]uint32,0,len(gamees))
	//for i, _ := range gamees {
	//	gameIds = append(gameIds, gamees[i].ID)
	//}
	fmt.Println("gamees:", gamees)
	var gameStocks []GameCardGoodsStock
	err = orm.Eloquent.Table("game_card_goods_stock").Find(&gameStocks).Error
	if err != nil {
		logger.Error(err.Error())
		return err
	}
	fmt.Println("gameStocks:", gameStocks)
	gameStockMap := make(map[uint32]uint32, 0)

	for i, _ := range gameStocks {
		gameStockMap[uint32(gameStocks[i].GameCardId)] += gameStocks[i].StoreStock
	}

	gameIds := make([]uint32, 0, len(gameStocks))
	gameId := make([]uint32, 0, len(gameStocks))
	for i, _ := range gamees {
		count, ok := gameStockMap[gamees[i].ID]
		if !ok || count == 0 {
			gameIds = append(gameIds, gamees[i].ID)
		}
		if count > 0 {
			gameId = append(gameId, gamees[i].ID)
		}
	}
	fmt.Println("gameIds 下架:", gameIds)
	fmt.Println("gameId 上架:", gameId)
	qs := orm.Eloquent.Table("game_card")
	if standType == 1 {
		qs = qs.Where("id IN (?)", gameId).Update("status", 1)
	} else if standType == 2 {
		qs = qs.Where("id IN (?)", gameIds).Update("status", 2)
	}
	err = qs.Error
	if err != nil {
		logger.Error(err.Error())
		return err
	}

	return nil
}

func GameCardBatchStandUp(gameIds []uint32) error {
	err := orm.Eloquent.Table("game_card").Where("id IN (?)", gameIds).Update("status", 1).Error
	if err != nil {
		logger.Error(err.Error())
		return err
	}
	return nil
}

func GoodsPutDownAway() {
	var games []GameCard
	err := orm.Eloquent.Table("game_card").Order("id DESC").Find(&games).Error
	if err != nil {
		logger.Error(err.Error())
		return
	}
	// 上下架
	for i, _ := range games {
		//fmt.Println("游戏:", games[i].ID, games[i].Name)
		GameCardStatusUpdate(&games[i])
	}
}

func UnPayOrderStatusUpdate() {
	// 待支付订单
	var orders []Order
	orm.Eloquent.Table("order").Where("created_at < ?", time.Now().Add(-30*time.Minute-30*time.Second)).
		//orm.Eloquent.Table("order").Where("created_at < ?", time.Now().Add(-3*time.Minute-30*time.Second)).
		Where("pay_status=?", PayStatusUnPay).Where("card_status = ?", OrderCardStatusUnPick).Find(&orders)

	//ids := make([]string, 0)
	if len(orders) == 0 {
		return
	}
	for i, _ := range orders {
		var expireOrder Order
		err := orm.Eloquent.Table("order").Where("id=?", orders[i].ID).Find(&expireOrder).Error
		if err != nil {
			logger.Error(err.Error())
			continue
		}
		if expireOrder.PayStatus != PayStatusUnPay || expireOrder.CardStatus != OrderCardStatusUnPick {
			continue
		}

		err = WxPayTransactionOrderClose(orders[i].OrderSn)
		if err != nil {
			logger.Error(err.Error())
			continue
		}

		begin := orm.Eloquent.Begin()
		sqlOrder := fmt.Sprintf("UPDATE `order` SET card_status=5 WHERE id =%d", orders[i].ID)
		err = begin.Exec(sqlOrder).Error
		if err != nil {
			begin.Rollback()
			logger.Error(err.Error())
			continue
		}
		sql := fmt.Sprintf("UPDATE game_card_goods_stock SET rent_stock= rent_stock+1 WHERE store_id=%d AND game_card_id=%d;", orders[i].StoreId, orders[i].GameCardId)
		fmt.Println("sql:", sql)
		err = begin.Exec(sql).Error
		if err != nil {
			begin.Rollback()
			logger.Errorf(err.Error())
			continue
		}
		err = begin.Commit().Error
		if err != nil {
			begin.Rollback()
			logger.Errorf(err.Error())
			continue
		}
		//ids = append(ids, fmt.Sprintf("%d", orders[i].ID))
	}

	//if len(ids) > 0 {
	//	sql := fmt.Sprintf("UPDATE `order` SET card_status=5 WHERE id IN (%s)", strings.Join(ids, ","))
	//	err := begin.Exec(sql).Error
	//	if err != nil {
	//		logger.Error(err.Error())
	//	}
	//}
	//err := begin.Commit().Error
	//if err != nil {
	//	logger.Errorf(err.Error())
	//}
}

func DeliveryStorePickStatusUpdate() {
	// 门店自取订单
	var orders []Order
	// 待上门店取货
	orm.Eloquent.Table("order").Where("created_at < ?", time.Now().Add(-24*time.Hour-1*time.Minute)).
		//orm.Eloquent.Table("order").Where("created_at < ?", time.Now().Add(-3*time.Minute)).
		Where("pay_status=?", PayStatusPaid).Where("card_status = ?", OrderCardStatusUnPick).
		Where("delivery_type", 1).Find(&orders)

	//ids := make([]string, 0)

	for i, _ := range orders {
		var (
			expireOrder     Order
			expireOrderCard []OrderCard
		)
		err := orm.Eloquent.Table("order").Where("id=?", orders[i].ID).Find(&expireOrder).Error
		if err != nil {
			logger.Error(err.Error())
			continue
		}

		if expireOrder.PayStatus != PayStatusPaid || expireOrder.CardStatus != OrderCardStatusUnPick {
			continue
		}

		err = orm.Eloquent.Table("order_card").Where("order_id=?", orders[i].ID).Find(&expireOrderCard).Error
		if err != nil {
			logger.Error(err.Error())
			continue
		}

		begin := orm.Eloquent.Begin()
		sqlOrder := fmt.Sprintf("UPDATE `order` SET card_status=5 WHERE id = %d", orders[i].ID)
		err = begin.Exec(sqlOrder).Error
		if err != nil {
			begin.Rollback()
			logger.Error(err.Error())
			return
		}
		addCardCount := 0
		for _, v := range expireOrderCard {
			if v.CardStatus != OrderCardStatusUnPick {
				continue
			}
			sqlOrderCard := fmt.Sprintf("UPDATE `order_card` SET card_status=5 WHERE id = %d", v.ID)
			err = begin.Exec(sqlOrderCard).Error
			if err != nil {
				begin.Rollback()
				logger.Error(err.Error())
				return
			}

			sql := fmt.Sprintf("UPDATE game_card_goods_stock SET rent_stock= rent_stock+1 WHERE store_id=%d AND game_card_id=%d;", v.StoreId, v.GameCardId)
			fmt.Println("sql:", sql)
			err = begin.Exec(sql).Error
			if err != nil {
				begin.Rollback()
				logger.Errorf(err.Error())
				continue
			}

			addCardCount++
		}
		if addCardCount > 0 {
			sqlRent := fmt.Sprintf("UPDATE user_rent_card SET have_rent_count = have_rent_count-%d,can_rent_count=can_rent_count+%d WHERE uid =%d;", addCardCount, addCardCount, expireOrder.Uid)
			fmt.Println("sqlRent:", sqlRent)
			err = begin.Exec(sqlRent).Error
			if err != nil {
				begin.Rollback()
				logger.Errorf("err:%#v", err)
				continue
			}
		}
		err = begin.Commit().Error
		if err != nil {
			begin.Rollback()
			logger.Errorf(err.Error())
			continue
		}
		//ids = append(ids, fmt.Sprintf("%d", orders[i].ID))
	}

	//if len(ids) > 0 {
	//	sql := fmt.Sprintf("UPDATE `order` SET card_status=5 WHERE id IN (%s)", strings.Join(ids, ","))
	//	err := begin.Exec(sql).Error
	//	if err != nil {
	//		begin.Rollback()
	//		logger.Error(err.Error())
	//		return
	//	}
	//}
	//err := begin.Commit().Error
	//if err != nil {
	//	begin.Rollback()
	//	logger.Errorf(err.Error())
	//}
}

// MemberExpirationReminder 给会员即将过期且有卡带未归还的用户发短信提醒续费
func MemberExpirationReminder() {
	list := []int64{7, 4, 0}

	for i, _ := range list {
		MemberExpirationReminderDay(list[i])
	}
}

func MemberExpirationReminderDay(days int64) {
	smsSend := &ExpireMemberSmsSend{
		Status:  1,
		SmsType: SmsTypeRenewRemind,
	}

	start := time.Now().Add(time.Duration(days) * 24 * time.Hour)
	end := start.AddDate(0, 0, 1)

	var users []UserInfo
	err := orm.Eloquent.Table("user").Where("member_expire > ?", start).Where("member_expire < ?", end).
		Where("member_level in (?)", []uint32{2, 3, 4, 5}).Find(&users).Error
	if err != nil {
		logger.Error(err.Error())
		return
	}

	if len(users) == 0 {
		logger.Info("users is null")
		return
	}

	for _, u := range users {
		if u.Tel == "" {
			continue
		}

		// 查询未归还卡带
		var cards []OrderCard
		err = orm.Eloquent.Table("order_card").
			Where("uid = ? AND pay_status = 2 AND card_status IN (1,2,3)", u.Uid).
			Find(&cards).Error
		if err != nil || len(cards) == 0 {
			logger.Error("Query order_card failed", logger.Field("err", err))
			continue
		}

		// 填充游戏信息
		cards = OrderCardListSetGameInfo(cards)
		// 提取游戏名称
		gameNames := make([]string, 0)
		for _, card := range cards {
			if card.GameName != "" {
				gameNames = append(gameNames, card.GameName)
			}
		}
		// 拼接短信内容
		cardNamesStr := strings.Join(gameNames, "、")

		userStore, err := GetUserBelongStore(u.Uid, u.StoreId)
		if err != nil {
			smsSend.Message = fmt.Sprintf("【明慧科技】温馨提示：您的go2ns租卡会员还有%d天将到期，如卡带到期未归将产生滞纳金，您可将游戏卡（%s）邮寄/到店归还，更多续约优惠可联系咨询~",
				days, cardNamesStr)
		} else {
			smsSend.Message = fmt.Sprintf("【明慧科技】温馨提示：您的go2ns租卡会员还有%d天将到期，如卡带到期未归将产生滞纳金，您可将游戏卡（%s）邮寄/到店归还，更多续约优惠可联系咨询~（%s %s）",
				days, cardNamesStr, userStore.Name, userStore.Landline)
		}
		smsSend.Tel = u.Tel
		smsSend.SendTime = time.Now()

		// 发送短信
		err = GtSendMessage([]string{u.Tel}, smsSend.Message)
		if err != nil {
			smsSend.Status = 2
			logger.Error("sms send failed", logger.Field("err", err))
		}

		// 存记录
		err = orm.Eloquent.Create(&smsSend).Error
		if err != nil {
			logger.Error("create expire member sms send err:", logger.Field("err", err))
		}
	}
}

func MemberExpirationReminderDayOld(days int64) {
	smsSend := &ExpireMemberSmsSend{
		SendTime: time.Now(),
		Tel:      "",
		Status:   1,
		SmsType:  SmsTypeRenewRemind,
	}

	start := time.Now().Add(time.Duration(days) * 24 * time.Hour)
	end := start.AddDate(0, 0, 1)

	var users []UserInfo
	err := orm.Eloquent.Table("user").Where("member_expire > ?", start).Where("member_expire < ?", end).
		Where("member_level in (?)", []uint32{2, 3, 4, 5}).Find(&users).Error
	if err != nil {
		logger.Error(err.Error())
		return
	}

	if len(users) == 0 {
		logger.Info("users is null")
		return
	}

	content := fmt.Sprintf("【明慧科技】温馨提示：您的go2ns租卡会员还有%d天将到期，请及时续费（如会员到期后仍有卡带未归还，将会收取滞纳金）", days)
	for i, _ := range users {
		if users[i].Tel == "" {
			continue
		}

		unreturned := &struct {
			Count int `json:"count"`
		}{}
		sql := fmt.Sprintf("SELECT COUNT(*) AS count FROM order_card WHERE uid = %d AND pay_status=2 AND card_status IN (1,2,3) ;", users[i].Uid)
		err = orm.Eloquent.Raw(sql).Scan(unreturned).Error
		if err != nil {
			logger.Error(err.Error())
			continue
		}
		fmt.Println("订单数量count:", unreturned.Count)
		if unreturned.Count == 0 {
			continue
		}
		//fmt.Println("content:", content)
		err = GtSendMessage([]string{users[i].Tel}, content)
		if err != nil {
			smsSend.Status = 2
			logger.Error(err.Error())
		}

		// 存记录
		smsSend.Tel = users[i].Tel
		smsSend.Message = content
		err = orm.Eloquent.Create(&smsSend).Error
		if err != nil {
			logger.Error("create expire member sms send err:", logger.Field("err", err))
		}
	}
}

// ExpireMemberSMSSend 用户过期如果一直不还卡，最多会收到12条短信，过期超过3个月就不会发送了
func ExpireMemberSMSSend() {
	nowTime := time.Now()
	days := []uint32{1, 2, 3, 4, 5, 6, 7, 14, 21, 28, 60, 90}
	for i, _ := range days {
		ExpireMemberSMSSendDay(days[i], nowTime)
	}
}

func ExpireMemberSMSSendDay(day uint32, nowTime time.Time) {
	smsSend := &ExpireMemberSmsSend{
		Status:  1,
		SmsType: SmsTypeReturnCard,
	}

	start := nowTime.AddDate(0, 0, int(day)*(-1))
	end := start.AddDate(0, 0, 1)

	var users []UserInfo
	err := orm.Eloquent.Table("user").Where("member_expire > ?", start).Where("member_expire < ?", end).
		Where("member_level = ?", MemberLevelUser).Find(&users).Error
	if err != nil {
		logger.Error(err.Error())
		return
	}

	if len(users) == 0 {
		logger.Info("users is null")
		return
	}

	for _, user := range users {
		if user.Tel == "" {
			continue
		}

		// 查询未归还卡带
		var cards []OrderCard
		err = orm.Eloquent.Table("order_card").
			Where("uid = ? AND pay_status = 2 AND card_status IN (1,2,3)", user.Uid).
			Find(&cards).Error
		if err != nil || len(cards) == 0 {
			logger.Error("Query order_card failed", logger.Field("err", err))
			continue
		}

		// 填充游戏信息
		cards = OrderCardListSetGameInfo(cards)

		// 提取游戏名称
		gameNames := make([]string, 0)
		for _, card := range cards {
			if card.GameName != "" {
				gameNames = append(gameNames, card.GameName)
			}
		}

		// 拼接短信内容
		cardNamesStr := strings.Join(gameNames, "、")
		smsSend.Message = fmt.Sprintf("【明慧科技】您的go2ns租卡会员已过期%d天，卡带（%s）未归还产生滞纳金%d元，请及时续费会员或归还卡带，以避免对您造成不必要的损失。", day, cardNamesStr, day*2)
		smsSend.Tel = user.Tel
		smsSend.SendTime = time.Now()

		// 发送短信
		err = GtSendMessage([]string{user.Tel}, smsSend.Message)
		if err != nil {
			smsSend.Status = 2
			logger.Error("sms send failed", logger.Field("err", err))
		}

		// 存记录
		err = orm.Eloquent.Create(&smsSend).Error
		if err != nil {
			logger.Error("create expire member sms send err:", logger.Field("err", err))
		}
	}
}

// ExpireMemberSMSSendDayOld 老版本
func ExpireMemberSMSSendDayOld(day uint32, nowTime time.Time) {
	smsSend := &ExpireMemberSmsSend{
		Message:  fmt.Sprintf("【明慧科技】您的go2ns租卡会员已过期%d天，卡带未归还产生滞纳金%d元，请及时续费会员或归还卡带，以避免对您造成不必要的损失。", day, day*2),
		SendTime: nowTime,
		Tel:      "",
		Status:   1,
	}
	start := nowTime.AddDate(0, 0, int(day)*(-1))
	end := start.AddDate(0, 0, 1)

	var users []UserInfo
	//err := orm.Eloquent.Table("user").Where("member_expire > ?", start).Where("member_expire < ?", end).
	//	Where("member_level in (?)", []uint32{2, 3, 4, 5}).Find(&users).Error
	err := orm.Eloquent.Table("user").Where("member_expire > ?", start).Where("member_expire < ?", end).
		Where("member_level = ?", MemberLevelUser).Find(&users).Error
	if err != nil {
		logger.Error(err.Error())
		return
	}

	if len(users) == 0 {
		logger.Info("users is null")
		return
	}

	for i, _ := range users {
		if users[i].Tel == "" {
			continue
		}

		smsSend.Tel = users[i].Tel
		exist, err := QueryRecordExist(fmt.Sprintf("SELECT * FROM order_card WHERE uid = %d AND pay_status=2 AND card_status IN (1,2,3) ", users[i].Uid))
		if err != nil || !exist {
			logger.Error("QueryRecordExist err", logger.Field("err", err), logger.Field("exists", exist))
			continue
		}
		err = GtSendMessage([]string{users[i].Tel}, smsSend.Message)
		if err != nil {
			smsSend.Status = 2
			logger.Error(err.Error())
		}

		err = orm.Eloquent.Create(&smsSend).Error
		if err != nil {
			logger.Error("create expire member sms send err:", logger.Field("err", err))
		}
	}
}

func GameCardStatusUpdate(card *GameCard) {
	var cardStocks []GameCardGoodsStock
	err := orm.Eloquent.Table("game_card_goods_stock").Where("game_card_id", card.ID).Find(&cardStocks).Error
	if err != nil {
		logger.Error(err.Error())
		return
	}
	//sql := "UPDATE game_card SET status = %d WHERE id = %d"
	if len(cardStocks) == 0 && card.Status == 1 {
		sql := fmt.Sprintf("UPDATE game_card SET status = %d WHERE id = %d", 2, card.ID)
		//fmt.Println("sql---1", sql)
		err := orm.Eloquent.Exec(sql).Error
		if err != nil {
			logger.Error(err.Error())
		}
		return
	}
	stocks := uint32(0)
	for i, _ := range cardStocks {
		stocks += cardStocks[i].StoreStock
	}
	if card.Status == 1 {
		if stocks <= 0 {
			fmt.Println("下架游戏:", card.ID, card.Name)
			sql := fmt.Sprintf("UPDATE game_card SET status = %d WHERE id = %d", 2, card.ID)
			fmt.Println("sql----2", sql)
			err := orm.Eloquent.Exec(sql).Error
			if err != nil {
				logger.Error(err.Error())
				return
			}
		}
	} else if card.Status == 2 {
		if stocks > 0 {
			fmt.Println("上架游戏:", card.ID, card.Name)
			sql := fmt.Sprintf("UPDATE game_card SET status = %d WHERE id = %d", 1, card.ID)
			//fmt.Println("sql----3", sql)
			err := orm.Eloquent.Exec(sql).Error
			if err != nil {
				logger.Error(err.Error())
				return
			}
		}
	}
	//Where("id IN (?)", gameIds)
}

type ExportGoods struct {
	GoodsName            string          `json:"goods_name"`
	CardPool             uint32          `json:"card_pool"`
	RentStock            uint32          `json:"rent_stock"`
	PlayerHold           uint32          `json:"player_hold"`
	OrderCount           uint32          `json:"order_count"`
	DelayDeliverGameCard uint32          `json:"delay_deliver_game_card"`
	Goods                []GameCardGoods `json:"goods"`
}

func ExportGoodsStock(storeId uint32) string {
	//var games []GameCard
	//err := orm.Eloquent.Table("game_card").Order("id DESC").Find(&games).Error
	//if err != nil {
	//	logger.Error(err.Error())
	//	return ""
	//}

	// 修改排序规则，按照商品名称的拼音字母进行排序
	var games []GameCard
	err := orm.Eloquent.Table("game_card").Order("CONVERT(name USING gbk) COLLATE gbk_chinese_ci ASC").Find(&games).Error
	if err != nil {
		logger.Error(err.Error())
		return ""
	}

	if storeId == 0 {
		allInfo, err := GoodsStockAllInfo(games)
		if err != nil {
			logger.Error(err.Error())
			return ""
		}
		return GoodsStockFile(allInfo, "全部门店")
	} else {
		var store Store
		err := orm.Eloquent.Table("store").Where("id", storeId).Order("id DESC").Find(&store).Error
		if err != nil {
			logger.Error(err.Error())
			return ""
		}

		storeInfo, err := GoodsStockStoreInfo(games, store)
		if err != nil {
			logger.Error(err.Error())
			return ""
		}
		return GoodsStockFile(storeInfo, store.Name)
	}
}

func GoodsStockAllInfo(gameCards []GameCard) ([]ExportGoods, error) {
	goodsData := make([]ExportGoods, 0, len(gameCards))

	cardStocks := make([]GameCardGoodsStock, 0)
	err := orm.Eloquent.Table("game_card_goods_stock").Order("id DESC").Find(&cardStocks).Error
	if err != nil {
		logger.Error(err.Error())
		return goodsData, err
	}
	cardStockMap := make(map[uint64][]GameCardGoodsStock, 0)
	for i, _ := range cardStocks {
		cardStockMap[cardStocks[i].GameCardId] = append(cardStockMap[cardStocks[i].GameCardId], cardStocks[i])
	}

	cardGoods := make([]GameCardGoods, 0)
	err = orm.Eloquent.Table("game_card_goods").Order("store_id DESC,id DESC").Find(&cardGoods).Error
	if err != nil {
		logger.Error(err.Error())
		return goodsData, err
	}
	storeIds := make([]uint32, 0)
	for i, _ := range cardGoods {
		storeIds = append(storeIds, uint32(cardGoods[i].StoreId))
	}
	storeMap := GetStoreMapByIds(storeIds)
	cardGoodsMap := make(map[uint64][]GameCardGoods, 0)

	for i, _ := range cardGoods {
		v, ok := storeMap[(cardGoods[i].StoreId)]
		if ok {
			cardGoods[i].Store = v
		}
		cardGoodsMap[cardGoods[i].GameCardId] = append(cardGoodsMap[cardGoods[i].GameCardId], cardGoods[i])
		storeIds = append(storeIds)
	}

	for _, game := range gameCards {
		cardStock, ok1 := cardStockMap[uint64(game.ID)]
		gameCardGoods, ok2 := cardGoodsMap[uint64(game.ID)]
		if !ok1 || !ok2 {
			continue
		}

		exportGoods := &ExportGoods{
			GoodsName: game.Name,
			Goods:     gameCardGoods,
		}

		for i, _ := range cardStock {
			exportGoods.RentStock += cardStock[i].RentStock
			exportGoods.OrderCount += cardStock[i].OrderCount
		}
		exportGoods.CardPool = uint32(len(gameCardGoods))
		for i, _ := range gameCardGoods {
			if gameCardGoods[i].Status == GameCardGoodsStatusCustomerHold {
				exportGoods.PlayerHold += 1
			}
		}
		exportGoods.DelayDeliverGameCard = uint32(len(gameCardGoods)) - exportGoods.RentStock - exportGoods.PlayerHold
		goodsData = append(goodsData, *exportGoods)
	}
	return goodsData, err
}

func GoodsStockStoreInfo(gameCards []GameCard, store Store) ([]ExportGoods, error) {
	goodsData := make([]ExportGoods, 0, len(gameCards))

	cardStocks := make([]GameCardGoodsStock, 0)
	err := orm.Eloquent.Table("game_card_goods_stock").Where("store_id", store.ID).Order("id DESC").Find(&cardStocks).Error
	if err != nil {
		logger.Error(err.Error())
		return goodsData, err
	}
	cardStockMap := make(map[uint64]GameCardGoodsStock, 0)
	for i, _ := range cardStocks {
		cardStockMap[cardStocks[i].GameCardId] = cardStocks[i]
	}

	cardGoods := make([]GameCardGoods, 0)
	err = orm.Eloquent.Table("game_card_goods").Where("store_id", store.ID).Order("id DESC").Find(&cardGoods).Error
	if err != nil {
		logger.Error(err.Error())
		return goodsData, err
	}
	cardGoodsMap := make(map[uint64][]GameCardGoods, 0)
	for i, _ := range cardGoods {
		cardGoods[i].Store = &store
		cardGoodsMap[cardGoods[i].GameCardId] = append(cardGoodsMap[cardGoods[i].GameCardId], cardGoods[i])
	}

	for _, game := range gameCards {
		cardStock, ok1 := cardStockMap[uint64(game.ID)]
		gameCardGoods, ok2 := cardGoodsMap[uint64(game.ID)]
		if !ok1 || !ok2 {
			continue
		}

		exportGoods := &ExportGoods{
			GoodsName: game.Name,
			//CardPool:  cardStock.StoreStock,
			RentStock:  cardStock.RentStock,
			OrderCount: cardStock.OrderCount,
			Goods:      gameCardGoods,
		}

		exportGoods.CardPool = uint32(len(gameCardGoods))
		for i, _ := range gameCardGoods {
			if gameCardGoods[i].Status == GameCardGoodsStatusCustomerHold {
				exportGoods.PlayerHold += 1
			}
		}
		if uint32(len(gameCardGoods)) > exportGoods.RentStock+exportGoods.PlayerHold {
			exportGoods.DelayDeliverGameCard = uint32(len(gameCardGoods)) - exportGoods.RentStock - exportGoods.PlayerHold
		}

		goodsData = append(goodsData, *exportGoods)
	}

	return goodsData, err
}

func GoodsStockFile(goodsData []ExportGoods, fileName string) string {
	file := excelize.NewFile()
	streamWriter, err := file.NewStreamWriter("Sheet1")
	if err != nil {
		fmt.Println(err)
	}

	//url := "http://39.108.188.218:8000/img/export/"
	fileName = time.Now().Format(TimeFormat) + fileName + ".xlsx"

	title := []interface{}{"商品名称", "卡池总数", "在库数量", "玩家持有数量", "锁定数量", "借出总数", "商品编号", "所在门店", "状态"}
	cell, _ := excelize.CoordinatesToCellName(1, 1)
	if err = streamWriter.SetRow(cell, title); err != nil {
		fmt.Println(err)
	}
	idx := 2
	var row []interface{}
	for rowId := 0; rowId < len(goodsData); rowId++ {
		row = []interface{}{goodsData[rowId].GoodsName, fmt.Sprintf("%d", goodsData[rowId].CardPool),
			fmt.Sprintf("%d", goodsData[rowId].RentStock),
			fmt.Sprintf("%d", goodsData[rowId].PlayerHold), fmt.Sprintf("%d", goodsData[rowId].DelayDeliverGameCard), fmt.Sprintf("%d", goodsData[rowId].OrderCount)}
		if len(goodsData[rowId].Goods) > 0 {
			storeName := ""
			if goodsData[rowId].Goods[0].Store != nil {
				storeName = goodsData[rowId].Goods[0].Store.Name
			}
			row = append(row, goodsData[rowId].Goods[0].SerialNumber, storeName, GoodsStatusStringByStatus(goodsData[rowId].Goods[0].Status))
		}

		cell, _ := excelize.CoordinatesToCellName(1, idx)
		if err := streamWriter.SetRow(cell, row); err != nil {
			fmt.Println(err)
		}
		idx++
		if len(goodsData[rowId].Goods) <= 1 {
			//continue
		} else {
			for _, cardGoods := range goodsData[rowId].Goods[1:] {
				recordGoods := make([]interface{}, 6)
				storeName := ""
				if cardGoods.Store != nil {
					storeName = cardGoods.Store.Name
				}

				recordGoods = append(recordGoods, cardGoods.SerialNumber, storeName, GoodsStatusStringByStatus(cardGoods.Status))

				cell, _ := excelize.CoordinatesToCellName(1, idx)
				if err := streamWriter.SetRow(cell, recordGoods); err != nil {
					fmt.Println(err)
				}
				idx++
			}
		}

	}
	if err := streamWriter.Flush(); err != nil {
		fmt.Println(err)
	}
	if err := file.SaveAs("/www/server/images/export/" + fileName); err != nil {
		//if err := file.SaveAs("./" + fileName); err != nil {
		fmt.Println(err)
	}

	return config.ExportConfig.Url + fileName
}

func GoodsStatusStringByStatus(status uint8) string {
	switch status {
	case 1:
		return "库存中"
	case 2:
		return "在途"
	case 3:
		return "客户持有"
	case 4:
		return "调拨中"
	}

	return ""
}

type CardPoolAnalysis struct {
	CardPool             uint32 `json:"card_pool"`
	RentStock            uint32 `json:"rent_stock"`
	PlayerHold           uint32 `json:"player_hold"`
	DelayDeliverGameCard uint32 `json:"delay_deliver_game_card"`
}

func CardPoolData(storeId uint32) (*CardPoolAnalysis, error) {
	poolAnalysis := new(CardPoolAnalysis)
	//var totalRentStock uint32
	//err := orm.Eloquent.Table("game_card_goods_stock").Pluck("SUM(rent_stock) AS total_rent_stock ", &totalRentStock).Error
	//if err != nil {
	//	logger.Error(err.Error())
	//	return poolAnalysis, err
	//}
	//poolAnalysis.RentStock = totalRentStock
	//fmt.Println("storeId:", storeId)

	qs := orm.Eloquent.Table("game_card_goods")
	if storeId != 0 {
		qs = qs.Where("store_id", storeId)
	}
	var total int64
	err := qs.Count(&total).Error
	if err != nil {
		logger.Error(err.Error())
		return poolAnalysis, err
	}

	var playerHold int64
	sqlPlayerHold := orm.Eloquent.Table("game_card_goods").Where("status = ?", GameCardGoodsStatusCustomerHold)
	if storeId != 0 {
		sqlPlayerHold = sqlPlayerHold.Where("store_id", storeId)
	}
	err = sqlPlayerHold.Count(&playerHold).Error
	if err != nil {
		logger.Error(err.Error())
		return poolAnalysis, err
	}
	//GameCardGoodsStock{} .Where("status = ?", GameCardGoodsStatusStock)
	var cardStocks []GameCardGoodsStock
	var rentStock uint32
	sqlRentStock := orm.Eloquent.Table("game_card_goods_stock")
	if storeId != 0 {
		sqlRentStock = sqlRentStock.Where("store_id", storeId)
	}
	err = sqlRentStock.Find(&cardStocks).Error
	if err != nil {
		logger.Error(err.Error())
		return poolAnalysis, err
	}
	for i, _ := range cardStocks {
		rentStock += cardStocks[i].RentStock
	}
	//fmt.Println("rentStock", rentStock)

	poolAnalysis.CardPool = uint32(total)
	poolAnalysis.PlayerHold = uint32(playerHold)
	poolAnalysis.RentStock = uint32(rentStock)
	poolAnalysis.DelayDeliverGameCard = uint32(total-playerHold) - rentStock

	//fmt.Println("CardPool:", poolAnalysis.CardPool)
	//fmt.Println("PlayerHold:", poolAnalysis.PlayerHold)
	//fmt.Println("RentStock:", poolAnalysis.RentStock)
	//fmt.Println("DelayDeliverGameCard:", poolAnalysis.DelayDeliverGameCard)
	return poolAnalysis, nil
}

type GameCardOrder struct {
	GameCardId uint32 `json:"game_card_id"`
	CountOrder uint32 `json:"count_order"`
}

func GameCardOrderRank(storeId uint32) ([]GameCard, error) {
	gameCards := make([]GameCard, 0)
	if storeId == 0 {
		err := orm.Eloquent.Table("game_card").Order("-order_count").Limit(10).Find(&gameCards).Error
		if err != nil {
			logger.Error(err.Error())
			return gameCards, err
		}
		return gameCards, nil
	}

	var gameCardOrders []GameCardOrder
	sql := fmt.Sprintf("SELECT * FROM (SELECT game_card_id,COUNT(id) AS count_order  FROM `order` WHERE 1 AND card_status=4 AND pay_status=2  AND store_id=%d GROUP BY game_card_id) a ORDER BY count_order DESC;", storeId)
	err := orm.Eloquent.Raw(sql).Scan(&gameCardOrders).Error
	if err != nil {
		logger.Error(err.Error())
		return gameCards, err
	}
	gameIds := make([]uint32, 0)
	for i, _ := range gameCardOrders {
		gameIds = append(gameIds, gameCardOrders[i].GameCardId)
	}
	if len(gameIds) == 0 {
		return gameCards, nil
	}
	var list []GameCard
	err = orm.Eloquent.Table("game_card").Where("id IN (?)", gameIds).Find(&list).Error
	if err != nil {
		logger.Error(err.Error())
		return gameCards, err
	}
	listMap := make(map[uint32]GameCard)
	for i, _ := range list {
		listMap[list[i].ID] = list[i]
	}
	for i, _ := range gameCardOrders {
		game, ok := listMap[gameCardOrders[i].GameCardId]
		if ok {
			game.OrderCount = gameCardOrders[i].CountOrder
			gameCards = append(gameCards, game)
		}
	}
	if len(gameCards) > 10 {
		gameCards = gameCards[:10]
	}
	return gameCards, nil
}

type GameCardStockListReq struct {
}

type GameCardStockListResp struct {
	List      []GameCardGoodsStock `json:"list"`
	Count     uint32               `json:"count"`
	PageIndex uint32               `json:"page_index"`

	CardTotalCount int `json:"card_total_count"`
	CardTotalStock int `json:"card_total_stock"`
	CardHoldCount  int `json:"card_hold_count"`
}

type CooperativeGameCardStockReq struct {
	SortType              uint32 `json:"sort_type"`      // 1-总库存 2-库存 3-用户持有 4-订单数量
	SortDirection         uint32 `json:"sort_direction"` // 1-升序 2-降序
	StoreId               uint32 `json:"store_id"`
	CooperativeBusinessId uint32 `json:"cooperative_business_id"`
	PageNum               uint32 `json:"pageIndex"`
	PageSize              uint32 `json:"page_size"`
	Name                  string `json:"name"`
}
type CooperativeGameCardStockResp struct {
	List      []GameCardGoodsStock `json:"list"`
	Count     uint32               `json:"count"`
	PageIndex uint32               `json:"page_index"`

	CardTotalCount int `json:"card_total_count"`
	CardTotalStock int `json:"card_total_stock"`
	CardHoldCount  int `json:"card_hold_count"`
}

func (m *CooperativeGameCardStockReq) List() (*CooperativeGameCardStockResp, error) {
	resp := &CooperativeGameCardStockResp{PageIndex: m.PageNum}
	type GameCardCount struct {
		CountGame uint32 `json:"count_game"`
	}
	var gameCardCount GameCardCount
	var goodsStocks []GameCardGoodsStock
	sqlOrder := ""
	switch m.SortType {
	case 1:
		sqlOrder = fmt.Sprintf(" ORDER BY total_stock ")
	case 2:
		sqlOrder = fmt.Sprintf(" ORDER BY rent_stock ")
	case 3:
		sqlOrder = fmt.Sprintf(" ORDER BY user_hold_stock ")
	case 4:
		sqlOrder = fmt.Sprintf(" ORDER BY order_count ")
	}

	if m.SortDirection == 1 {
		sqlOrder += " DESC"
	} else if m.SortDirection == 2 {
		sqlOrder += " ASC"
	}
	sqlStore := ""
	if m.StoreId != 0 {
		sqlStore = fmt.Sprintf(" AND store_id = %d", m.StoreId)
	} else {
		storeIds, err := GetStoreIdsByCooperativeBusinessId(m.CooperativeBusinessId)
		if err != nil {
			logger.Error("get store ids err:", logger.Field("err", err))
			return resp, err
		}
		idString := ""
		for i, _ := range storeIds {
			idString += fmt.Sprintf("%d,", storeIds[i])
		}
		sqlStore = fmt.Sprintf(" AND store_id in (%s) ", idString[:len(idString)-1])
	}
	if m.Name != "" {
		var gameCards []GameCard
		sqlName := "SELECT * FROM game_card WHERE `name` LIKE '%" + m.Name + "%';"
		fmt.Println("sqlName:", sqlName)
		err := orm.Eloquent.Raw(sqlName).Scan(&gameCards).Error
		//err := orm.Eloquent.Exec(sqlName).Find(&gameCards).Error
		if err != nil {
			return resp, err
		}
		fmt.Println("--sqlName:", sqlName)
		gameIds := make([]string, 0)
		for i, _ := range gameCards {
			gameIds = append(gameIds, fmt.Sprintf("%d", gameCards[i].ID))
		}

		fmt.Println("--gameIds:", gameIds)
		if len(gameIds) > 0 {
			sqlStore += fmt.Sprintf(" AND game_card_id IN (%s)", strings.Join(gameIds, ","))
		}
	}

	//var countGame int64
	sqlCount := fmt.Sprintf("SELECT COUNT(*) AS count_game FROM (SELECT SUM(total_stock) AS total_stock,SUM(order_count) AS order_count,SUM(user_hold_stock) AS user_hold_stock,SUM(rent_stock) AS rent_stock FROM game_card_goods_stock WHERE 1 %s GROUP BY game_card_id) a ;", sqlStore)
	fmt.Println("sqlCount:", sqlCount)
	err := orm.Eloquent.Raw(sqlCount).Scan(&gameCardCount).Error
	if err != nil {
		logger.Error("sqlCount  err:", logger.Field("err", err))
		return resp, err
	}
	fmt.Println("countGame:", gameCardCount.CountGame)
	resp.Count = gameCardCount.CountGame
	page := m.PageNum - 1
	if page < 0 {
		page = 0
	}
	if m.PageSize == 0 {
		m.PageSize = 10
	}

	sql := fmt.Sprintf("SELECT * FROM (SELECT SUM(total_stock) AS total_stock,SUM(order_count) AS order_count,SUM(user_hold_stock) AS user_hold_stock,SUM(rent_stock) AS rent_stock,game_card_id FROM game_card_goods_stock WHERE 1 %s GROUP BY game_card_id) a  %s  LIMIT %d,%d;", sqlStore, sqlOrder, page*m.PageSize, m.PageSize)
	fmt.Println("sql:", sql)
	err = orm.Eloquent.Raw(sql).Scan(&goodsStocks).Error
	if err != nil {
		logger.Error(err.Error())
		return resp, err
	}

	if len(goodsStocks) == 0 {
		return resp, nil
	}

	gameIds := make([]uint32, 0, len(goodsStocks))
	for i, _ := range goodsStocks {
		gameIds = append(gameIds, uint32(goodsStocks[i].GameCardId))
	}
	fmt.Println("gameIds:", gameIds)
	var games []GameCard
	err = orm.Eloquent.Table("game_card").Where("id IN (?)", gameIds).Find(&games).Error
	if err != nil {
		logger.Error(err.Error())
		return resp, err
	}
	gameMap := make(map[uint32]GameCard, 0)
	for i, _ := range games {
		gameMap[games[i].ID] = games[i]
	}
	//fmt.Println("games:", games)
	for i, _ := range goodsStocks {
		game, ok := gameMap[uint32(goodsStocks[i].GameCardId)]
		if ok {
			goodsStocks[i].Name = game.Name
			goodsStocks[i].CoverImg = game.CoverImg
		}
	}
	resp.List = goodsStocks

	var cardHoldCount int64
	holdQs := orm.Eloquent.Table("game_card_goods").Where("status", GameCardGoodsStatusCustomerHold)
	if m.StoreId != 0 {
		holdQs = holdQs.Where("store_id", m.StoreId)
	}
	err = holdQs.Count(&cardHoldCount).Error
	if err != nil {
		logger.Errorf(err.Error())
		return resp, err
	}
	resp.CardHoldCount = int(cardHoldCount)

	var (
		rentStock  uint32
		totalCount int64
		cardStocks []GameCardGoodsStock
	)

	if m.StoreId != 0 {
		err = orm.Eloquent.Table("game_card_goods_stock").Where("store_id", m.StoreId).Find(&cardStocks).Error
	} else {
		err = orm.Eloquent.Table("game_card_goods_stock").Find(&cardStocks).Error
	}
	if err != nil {
		logger.Errorf(err.Error())
		return resp, err
	}
	for i, _ := range cardStocks {
		rentStock += cardStocks[i].RentStock
	}
	//var game GameCardGoods
	if m.StoreId != 0 {
		err = orm.Eloquent.Table("game_card_goods").Where("store_id", m.StoreId).
			Where("status in (?)", []uint32{1, 2, 3, 4}).Count(&totalCount).Error
	} else {
		err = orm.Eloquent.Table("game_card_goods").
			Where("status in (?)", []uint32{1, 2, 3, 4}).Count(&totalCount).Error
	}

	if err != nil {
		logger.Errorf(err.Error())
		return resp, err
	}

	resp.CardTotalStock = int(rentStock)
	resp.CardTotalCount = int(totalCount)

	return resp, nil
}

func GameCardStockList(name string, sortType, sortDirection, storeId, pageNum, pageSize uint32, c *gin.Context) (*GameCardStockListResp, error) {
	resp := &GameCardStockListResp{PageIndex: pageNum}
	type GameCardCount struct {
		CountGame uint32 `json:"count_game"`
	}
	var gameCardCount GameCardCount
	var goodsStocks []GameCardGoodsStock
	sqlOrder := ""
	switch sortType {
	case 1:
		sqlOrder = fmt.Sprintf(" ORDER BY total_stock ")
	case 2:
		sqlOrder = fmt.Sprintf(" ORDER BY rent_stock ")
	case 3:
		sqlOrder = fmt.Sprintf(" ORDER BY user_hold_stock ")
	case 4:
		sqlOrder = fmt.Sprintf(" ORDER BY order_count ")
	}

	if sortDirection == 1 {
		sqlOrder += " DESC"
	} else if sortDirection == 2 {
		sqlOrder += " ASC"
	}
	sqlStore := ""
	if storeId != 0 {
		sqlStore = fmt.Sprintf(" AND store_id = %d", storeId)
	}

	if name != "" {
		var gameCards []GameCard
		sqlName := "SELECT * FROM game_card WHERE `name` LIKE '%" + name + "%';"
		err := orm.Eloquent.Raw(sqlName).Scan(&gameCards).Error
		//err := orm.Eloquent.Exec(sqlName).Find(&gameCards).Error
		if err != nil {
			return resp, err
		}
		fmt.Println("--sqlName:", sqlName)
		gameIds := make([]string, 0)
		for i, _ := range gameCards {
			gameIds = append(gameIds, fmt.Sprintf("%d", gameCards[i].ID))
		}

		fmt.Println("--gameIds:", gameIds)
		sqlStore += fmt.Sprintf(" AND game_card_id IN (%s)", strings.Join(gameIds, ","))
	}

	//var countGame int64
	sqlCount := fmt.Sprintf("SELECT COUNT(*) AS count_game FROM (SELECT SUM(total_stock) AS total_stock,SUM(order_count) AS order_count,SUM(user_hold_stock) AS user_hold_stock,SUM(rent_stock) AS rent_stock FROM game_card_goods_stock WHERE 1 %s GROUP BY game_card_id) a ;", sqlStore)
	fmt.Println("sqlCount:", sqlCount)
	err := orm.Eloquent.Raw(sqlCount).Scan(&gameCardCount).Error
	if err != nil {
		logger.Error("sqlCount  err:", logger.Field("err", err))
		return resp, err
	}
	fmt.Println("countGame:", gameCardCount.CountGame)
	resp.Count = gameCardCount.CountGame
	page := pageNum - 1
	if page < 0 {
		page = 0
	}
	if pageSize == 0 {
		pageSize = 10
	}

	sql := fmt.Sprintf("SELECT * FROM (SELECT SUM(total_stock) AS total_stock,SUM(order_count) AS order_count,SUM(user_hold_stock) AS user_hold_stock,SUM(rent_stock) AS rent_stock,game_card_id FROM game_card_goods_stock WHERE 1 %s GROUP BY game_card_id) a  %s  LIMIT %d,%d;", sqlStore, sqlOrder, page*pageSize, pageSize)
	fmt.Println("sql:", sql)
	err = orm.Eloquent.Raw(sql).Scan(&goodsStocks).Error
	if err != nil {
		logger.Error(err.Error())
		return resp, err
	}

	if len(goodsStocks) == 0 {
		return resp, nil
	}

	gameIds := make([]uint32, 0, len(goodsStocks))
	for i, _ := range goodsStocks {
		gameIds = append(gameIds, uint32(goodsStocks[i].GameCardId))
	}
	fmt.Println("gameIds:", gameIds)
	var games []GameCard
	err = orm.Eloquent.Table("game_card").Where("id IN (?)", gameIds).Find(&games).Error
	if err != nil {
		logger.Error(err.Error())
		return resp, err
	}
	gameMap := make(map[uint32]GameCard, 0)
	for i, _ := range games {
		gameMap[games[i].ID] = games[i]
	}
	//fmt.Println("games:", games)
	for i, _ := range goodsStocks {
		game, ok := gameMap[uint32(goodsStocks[i].GameCardId)]
		if ok {
			goodsStocks[i].Name = game.Name
			goodsStocks[i].CoverImg = game.CoverImg
		}
	}
	resp.List = goodsStocks

	//userHoldMap := make(map[uint64]uint32)
	//totalCountMap := make(map[uint64]uint32)
	//for i, _ := range userHold {
	//	userHoldMap[userHold[i].GameCardId] = userHold[i].CardCount
	//	resp.CardHoldCount += int(userHold[i].CardCount)
	//}
	//var gameCardGoods []GameCardGoods
	var cardHoldCount int64
	holdQs := orm.Eloquent.Table("game_card_goods").Where("status", GameCardGoodsStatusCustomerHold)
	if storeId != 0 {
		holdQs = holdQs.Where("store_id", storeId)
	}
	err = holdQs.Count(&cardHoldCount).Error
	if err != nil {
		logger.Errorf(err.Error())
		return resp, err
	}
	resp.CardHoldCount = int(cardHoldCount)
	//err = orm.Eloquent.Table("game_card_goods").Where("store_id", m.StoreId).Find(&gameCardGoods).Error
	//if err != nil {
	//	logger.Errorf(err.Error())
	//	return resp, err
	//}
	//for i, _ := range gameCardGoods {
	//	if gameCardGoods[i].Status == GameCardGoodsStatusCustomerHold {
	//		userHoldMap[gameCardGoods[i].GameCardId] += 1
	//		resp.CardHoldCount += 1
	//	}
	//	//if gameCardGoods[i].Status != GameCardGoodsStatusReceivingCard && gameCardGoods[i].Status != GameCardGoodsStatusReceivedCard {
	//	//	totalCountMap[gameCardGoods[i].GameCardId] += 1
	//	//}
	//}

	//for i, _ := range goodsStocks {
	//	////game, ok := gameMap[uint32(stocks[i].GameCardId)]
	//	//if ok {
	//	//	if v, ok := userHoldMap[stocks[i].GameCardId]; ok {
	//	//		stocks[i].UserHoldStock = v
	//	//	}
	//	//	if v, ok := totalCountMap[stocks[i].GameCardId]; ok {
	//	//		stocks[i].TotalStock = v
	//	//	}
	//	//	//resp.List = append(resp.List, stocks[i].ToInfo(&game))
	//	//}
	//	if v, ok := userHoldMap[goodsStocks[i].GameCardId]; ok {
	//		goodsStocks[i].UserHoldStock = v
	//	}
	//	if v, ok := totalCountMap[goodsStocks[i].GameCardId]; ok {
	//		goodsStocks[i].TotalStock = v
	//	}
	//}

	var (
		rentStock  uint32
		totalCount int64
		cardStocks []GameCardGoodsStock
	)

	if storeId != 0 {
		err = orm.Eloquent.Table("game_card_goods_stock").Where("store_id", storeId).Find(&cardStocks).Error
	} else {
		err = orm.Eloquent.Table("game_card_goods_stock").Find(&cardStocks).Error
	}
	if err != nil {
		logger.Errorf(err.Error())
		return resp, err
	}
	for i, _ := range cardStocks {
		rentStock += cardStocks[i].RentStock
	}
	//var game GameCardGoods
	if storeId != 0 {
		err = orm.Eloquent.Table("game_card_goods").Where("store_id", storeId).
			Where("status in (?)", []uint32{1, 2, 3, 4}).Count(&totalCount).Error
	} else {
		err = orm.Eloquent.Table("game_card_goods").
			Where("status in (?)", []uint32{1, 2, 3, 4}).Count(&totalCount).Error
	}

	if err != nil {
		logger.Errorf(err.Error())
		return resp, err
	}

	resp.CardTotalStock = int(rentStock)
	resp.CardTotalCount = int(totalCount)

	return resp, nil
}

const (
	CannibalizeTaskStatusNotImportGoods  = 1 // 1-待填调拨卡
	CannibalizeTaskStatusNotDeliverGoods = 2 // 2-待发货
	CannibalizeTaskStatusDeliveredGoods  = 3 // 3-已发货
	CannibalizeTaskStatusInStorage       = 4 // 4-已入库
	CannibalizeTaskStatusDel             = 5 // 4-已删除
)

type CannibalizeStockTask struct {
	Model
	FromStoreId   uint32    `json:"from_store_id"`            //
	ToStoreId     uint32    `json:"to_store_id"`              //
	TaskId        uint32    `json:"task_id"`                  // 时间戳
	Count         uint32    `json:"count"`                    // 总数量
	Status        uint8     `json:"status"`                   // 1-待填调拨卡 2-待发货 3-已发货 4-已入库
	DeliveryTime  time.Time `json:"delivery_time"`            //
	InStorageTime time.Time `json:"in_storage_time"`          //
	MakerId       uint32    `json:"maker_id" gorm:"index"`    // 制单人id
	MakerName     string    `json:"maker_name"`               // 制单人名称
	FromStoreName string    `json:"from_store_name" gorm:"-"` //
	ToStoreName   string    `json:"to_store_name" gorm:"-"`   //

	//GameCardId  uint32 `json:"game_card_id"` // 游戏卡id
	//CannibalizeStockTask int `json:"cannibalize_stock_task" gorm:"-"`
}

type CannibalizeGameCardGoods struct {
	Model

	CannibalizeStockTaskId uint32 `json:"cannibalize_stock_task_id"`
	GameCardId             uint32 `json:"game_card_id"`               // 游戏卡id
	SerialNumber           string `json:"serial_number" gorm:"index"` // 编号

	GameCardName string `json:"game_card_name" gorm:"–"`
	//CannibalizeGameCardGoods int `json:"cannibalize_game_card_goods" gorm:"-"`
}

type CannibalizeTaskListReq struct {
	PageNum  int    `json:"pageIndex"`
	PageSize int    `json:"pageSize"`
	StoreId  uint64 `json:"store_id" ` // 门店id
	Status   uint8  `json:"status"`
}
type CannibalizeTaskListResp struct {
	PageSize  int                    `json:"pageSize"`
	List      []CannibalizeStockTask `json:"list"`
	Count     int                    `json:"count"`
	PageIndex int                    `json:"pageIndex"`
	TotalPage int                    `json:"total_page"`
}

func (m *CannibalizeTaskListReq) GetCannibalizeTaskList(c *gin.Context) (*CannibalizeTaskListResp, error) {
	resp := &CannibalizeTaskListResp{
		PageIndex: m.PageNum,
		PageSize:  m.PageSize,
	}
	qs := orm.Eloquent.Table("cannibalize_stock_task")
	// 非管理员才判断所属门店
	if !(tools.GetRoleName(c) == "admin" || tools.GetRoleName(c) == "系统管理员") {
		sysUser, err := GetSysUserByCtx(c)
		if err != nil {
			return nil, err
		}

		// 返回sysUser未过期的门店id列表
		storeList := GetValidStoreIDs(sysUser.StoreData)
		if m.StoreId != 0 {
			if !Contains(storeList, uint32(m.StoreId)) {
				return nil, errors.New("您没有该门店权限")
			}
		} else {
			if len(storeList) > 0 {
				if len(storeList) == 1 {
					qs = qs.Where("from_store_id = ?", storeList[0]).Or("to_store_id = ?", storeList[0])
				} else {
					qs = qs.Where("from_store_id IN (?)", storeList).Or("to_store_id IN (?)", storeList)
				}
			} else {
				return nil, errors.New("用户未绑定门店")
			}
		}
	}

	if m.StoreId != 0 {
		qs = qs.Where("from_store_id = ?", m.StoreId).Or("to_store_id = ?", m.StoreId)
	}
	if m.Status != 0 {
		qs = qs.Where("status = ?", m.Status)
	}
	page := m.PageNum - 1
	if page < 0 {
		page = 0
	}
	if m.PageSize == 0 {
		m.PageSize = 10
	}
	var (
		count int64
		tasks []CannibalizeStockTask
	)

	err := qs.Count(&count).Offset(page * m.PageSize).Limit(m.PageSize).Order("id DESC").Find(&tasks).Error
	if err != nil && err != RecordNotFound {
		logger.Error(err.Error())
		return resp, err
	}

	resp.Count = int(count)
	resp.List = CannibalizeStockTaskListSetInfo(tasks)

	return resp, nil
}

type CannibalizeTaskDetailReq struct {
	TaskId           uint32   `json:"task_id"`            // 任务ID
	DeliverStoreId   []uint32 `json:"deliver_store_id"`   // 调出门店id
	ReceiveStoreId   []uint32 `json:"receive_store_id"`   // 调入门店id
	GameCardId       []uint32 `json:"game_card_id"`       // 游戏卡id
	SerialNumber     string   `json:"serial_number"`      // 游戏卡串码
	State            uint32   `json:"state"`              // 调拨状态：1-调拨中 2-已完成
	SendTimeStart    string   `json:"send_time_start"`    // 调出开始时间
	SendTimeEnd      string   `json:"send_time_end"`      // 调出结束时间
	ReceiveTimeStart string   `json:"receive_time_start"` // 调入开始时间
	ReceiveTimeEnd   string   `json:"receive_time_end"`   // 调入结束时间
	IsExport         uint32   `json:"is_export"`          // 1-导出
	PageIndex        int      `json:"pageIndex"`          // 页码
	PageSize         int      `json:"pageSize"`           // 页面条数
}

type CannibalizeTaskDetailResp struct {
	Total     int64                     `json:"total"`      // 总条数/记录数
	PageIndex int                       `json:"pageIndex"`  // 页码
	PageSize  int                       `json:"pageSize"`   // 页面条数
	ExportUrl string                    `json:"export_url"` // 导出excel路径
	List      []GameCardAllotDetailData `json:"list"`       //
}

// GameCardAllotDetailData 租赁卡带库存调拨明细数据
type GameCardAllotDetailData struct {
	TaskId           uint32     `json:"task_id"`            // 任务ID
	DeliverStoreId   uint32     `json:"deliver_store_id"`   // 调出门店id
	DeliverStoreName string     `json:"deliver_store_name"` // 调出门店名称
	ReceiveStoreId   uint32     `json:"receive_store_id"`   // 调入门店id
	ReceiveStoreName string     `json:"receive_store_name"` // 调入门店名称
	MakerId          uint32     `json:"maker_id"`           // 制单人id
	MakerName        string     `json:"maker_name"`         // 制单人名称
	MakerTime        *time.Time `json:"maker_time"`         // 制单时间/发起时间
	SendTime         *time.Time `json:"send_time"`          // 发货时间/调出时间
	ReceiveTime      *time.Time `json:"receive_time"`       // 收货时间/调入时间
	State            uint32     `json:"state"`              // 调拨状态：1-调拨中 2-已完成
	GameCardId       uint32     `json:"game_card_id"`       // 游戏卡id
	SerialNumber     string     `json:"serial_number"`      // 游戏卡串码
	GameCardName     string     `json:"game_card_name"`     // 游戏卡名称
}

func (m *CannibalizeTaskDetailReq) GetCannibalizeTaskDetail(c *gin.Context) (*CannibalizeTaskDetailResp, error) {
	// 用户权限校验：非管理员仅能查看自己门店的数据
	if !(tools.GetRoleName(c) == "admin" || tools.GetRoleName(c) == "系统管理员") {
		sysUser, err := GetSysUserByCtx(c)
		if err != nil {
			return nil, errors.New("操作失败: " + err.Error())
		}

		// 获取用户绑定门店
		storeList := GetValidStoreIDs(sysUser.StoreData)
		if len(storeList) > 0 {
			m.DeliverStoreId = CompareLists(storeList, m.DeliverStoreId)
			m.ReceiveStoreId = CompareLists(storeList, m.ReceiveStoreId)
			if len(m.DeliverStoreId) == 0 && len(m.ReceiveStoreId) == 0 {
				return &CannibalizeTaskDetailResp{}, nil
			}
		} else {
			return nil, errors.New("用户未绑定门店")
		}
	}

	resp := &CannibalizeTaskDetailResp{
		PageIndex: m.PageIndex,
		PageSize:  m.PageSize,
	}
	page := m.PageIndex - 1
	if page < 0 {
		page = 0
	}
	if m.PageSize == 0 {
		m.PageSize = 10
	}

	// 构建查询 CannibalizeStockTask 与 CannibalizeGameCardGoods 的 JOIN 语句
	qs := orm.Eloquent.Debug().Table("cannibalize_stock_task").
		Select("cannibalize_stock_task.id as task_id, "+
			"cannibalize_stock_task.from_store_id as deliver_store_id, "+
			"cannibalize_stock_task.to_store_id as receive_store_id, "+
			"cannibalize_stock_task.maker_id, "+
			"cannibalize_stock_task.maker_name, "+
			"cannibalize_stock_task.created_at as maker_time, "+
			"cannibalize_stock_task.delivery_time as send_time, "+
			"cannibalize_stock_task.in_storage_time as receive_time, "+
			"CASE "+
			"WHEN cannibalize_stock_task.status IN (2, 3) THEN 1 "+
			"WHEN cannibalize_stock_task.status = 4 THEN 2 "+
			"ELSE cannibalize_stock_task.status "+
			"END AS state, "+
			"cannibalize_game_card_goods.game_card_id, "+
			"cannibalize_game_card_goods.serial_number").
		Joins("JOIN cannibalize_game_card_goods ON cannibalize_game_card_goods.cannibalize_stock_task_id "+
								"= cannibalize_stock_task.id").
		Where("cannibalize_stock_task.status <> ?", 1) // 1 表示未审核/无效任务等

	// Count 查询
	countQuery := orm.Eloquent.Table("cannibalize_stock_task").
		Joins("JOIN cannibalize_game_card_goods ON cannibalize_game_card_goods.cannibalize_stock_task_id "+
			"= cannibalize_stock_task.id").
		Where("cannibalize_stock_task.status <> ?", 1)

	if m.TaskId != 0 {
		qs = qs.Where("cannibalize_stock_task.id = ?", m.TaskId)
		countQuery = countQuery.Where("cannibalize_stock_task.id = ?", m.TaskId)
	}

	if len(m.DeliverStoreId) > 0 {
		qs = qs.Where("cannibalize_stock_task.from_store_id IN ?", m.DeliverStoreId)
		countQuery = countQuery.Where("cannibalize_stock_task.from_store_id IN ?", m.DeliverStoreId)
	}

	if len(m.ReceiveStoreId) > 0 {
		qs = qs.Where("cannibalize_stock_task.to_store_id IN ?", m.ReceiveStoreId)
		countQuery = countQuery.Where("cannibalize_stock_task.to_store_id IN ?", m.ReceiveStoreId)
	}

	if len(m.GameCardId) != 0 {
		qs = qs.Where("cannibalize_game_card_goods.game_card_id IN ?", m.GameCardId)
		countQuery = countQuery.Where("cannibalize_game_card_goods.game_card_id IN ?", m.GameCardId)
	}

	if m.SerialNumber != "" {
		qs = qs.Where("cannibalize_game_card_goods.serial_number = ?", m.SerialNumber)
		countQuery = countQuery.Where("cannibalize_game_card_goods.serial_number = ?", m.SerialNumber)
	}

	if m.State != 0 {
		switch m.State {
		case 1: // 调拨中
			qs = qs.Where("cannibalize_stock_task.status IN (?)",
				[]uint32{ErpInventoryAllotOrderWaitSend, ErpInventoryAllotOrderWaitReceive})
			countQuery = countQuery.Where("cannibalize_stock_task.status IN (?)",
				[]uint32{ErpInventoryAllotOrderWaitSend, ErpInventoryAllotOrderWaitReceive})
		case 2: // 已完成
			qs = qs.Where("cannibalize_stock_task.status = ?", ErpInventoryAllotOrderFinished)
			countQuery = countQuery.Where("cannibalize_stock_task.status = ?", ErpInventoryAllotOrderFinished)
		}
	}

	if m.SendTimeStart != "" {
		startTime, err := time.Parse(QueryTimeFormat, m.SendTimeStart)
		if err != nil {
			return nil, err
		}
		qs = qs.Where("cannibalize_stock_task.delivery_time >= ?", startTime)
		countQuery = countQuery.Where("cannibalize_stock_task.delivery_time >= ?", startTime)
	}
	if m.SendTimeEnd != "" {
		endTime, err := time.Parse(QueryTimeFormat, m.SendTimeEnd)
		if err != nil {
			return nil, err
		}
		qs = qs.Where("cannibalize_stock_task.delivery_time <= ?", endTime)
		countQuery = countQuery.Where("cannibalize_stock_task.delivery_time <= ?", endTime)
	}
	if m.ReceiveTimeStart != "" {
		startTime, err := time.Parse(QueryTimeFormat, m.ReceiveTimeStart)
		if err != nil {
			return nil, err
		}
		qs = qs.Where("cannibalize_stock_task.in_storage_time >= ?", startTime)
		countQuery = countQuery.Where("cannibalize_stock_task.in_storage_time >= ?", startTime)
	}
	if m.ReceiveTimeEnd != "" {
		endTime, err := time.Parse(QueryTimeFormat, m.ReceiveTimeEnd)
		if err != nil {
			return nil, err
		}
		qs = qs.Where("cannibalize_stock_task.in_storage_time <= ?", endTime)
		countQuery = countQuery.Where("cannibalize_stock_task.in_storage_time <= ?", endTime)
	}

	var count int64
	err := countQuery.Count(&count).Error
	if err != nil {
		return nil, err
	}
	resp.Total = count

	var list []GameCardAllotDetailData
	if m.IsExport == 1 {
		err = qs.Order("cannibalize_stock_task.created_at DESC").Find(&list).Error
	} else {
		err = qs.Order("cannibalize_stock_task.created_at DESC").
			Offset(page * m.PageSize).Limit(m.PageSize).Find(&list).Error
	}
	if err != nil {
		return nil, err
	}

	storeMap, err := GetAllStoreData()
	if err != nil {
		return nil, err
	}

	// 1. 将 list 转换为 CannibalizeGameCardGoods 切片
	goodsList := make([]CannibalizeGameCardGoods, len(list))
	for i, item := range list {
		list[i].DeliverStoreName = storeMap[item.DeliverStoreId].Name
		list[i].ReceiveStoreName = storeMap[item.ReceiveStoreId].Name

		goodsList[i].GameCardId = list[i].GameCardId
	}

	// 2. 调用补全游戏名称的方法
	goodsList = CannibalizeGameCardGoodsSetInfo(goodsList)

	// 3. 把补全的 GameCardName 写回 list
	for i := range list {
		list[i].GameCardName = goodsList[i].GameCardName
	}

	resp.List = list

	if m.IsExport == 1 {
		resp.ExportUrl, err = exportCannibalizeTaskDetail(resp.List)
		if err != nil {
			return nil, err
		}
		resp.List = []GameCardAllotDetailData{}
	}

	return resp, nil
}

// exportCannibalizeTaskDetail 游戏卡带库存调拨明细导出
func exportCannibalizeTaskDetail(dataList []GameCardAllotDetailData) (string, error) {
	file := excelize.NewFile()
	sheet := "Sheet1"
	fileName := time.Now().Format("2006-01-02_15-04-05") + "_卡带调拨明细.xlsx"
	savePath := config.ExportConfig.Path + fileName
	url := config.ExportConfig.Url + fileName

	// 标题栏
	headers := []string{
		"任务ID", "游戏卡串码", "游戏卡名称", "制单人", "制单时间", "调出门店", "调出时间",
		"调入门店", "调入时间", "调拨状态",
	}

	// 设置标题栏
	for i, header := range headers {
		cell, _ := excelize.CoordinatesToCellName(i+1, 1)
		_ = file.SetCellValue(sheet, cell, header)
	}

	// 填充数据
	for rowIndex, item := range dataList {
		row := rowIndex + 2 // 从第二行开始填充数据

		var makerTime, sendTime, receiveTime string
		if item.MakerTime != nil {
			makerTime = item.MakerTime.Format("2006-01-02")
		}
		if item.SendTime != nil {
			sendTime = item.SendTime.Format("2006-01-02 15:04:05")
		}
		if item.ReceiveTime != nil {
			receiveTime = item.ReceiveTime.Format("2006-01-02 15:04:05")
		}

		var stateStr string
		switch item.State {
		case 1:
			stateStr = "调拨中"
		case 2:
			stateStr = "已完成"
		default:
			stateStr = "未知"
		}

		values := []interface{}{
			item.TaskId,
			item.SerialNumber,
			item.GameCardName,
			item.MakerName,
			makerTime,
			item.DeliverStoreName,
			sendTime,
			item.ReceiveStoreName,
			receiveTime,
			stateStr,
		}

		for colIndex, val := range values {
			cell, _ := excelize.CoordinatesToCellName(colIndex+1, row)
			_ = file.SetCellValue(sheet, cell, val)
		}
	}

	// 设置样式
	style, _ := file.NewStyle(`{
		"alignment":{"horizontal":"center","vertical":"center"},
		"border":[
			{"type":"left","color":"000000","style":1},
			{"type":"top","color":"000000","style":1},
			{"type":"right","color":"000000","style":1},
			{"type":"bottom","color":"000000","style":1}
		]
	}`)

	lastRow := len(dataList) + 1
	endCell := fmt.Sprintf("J%d", lastRow)
	_ = file.SetCellStyle(sheet, "A1", endCell, style)
	_ = file.SetRowHeight(sheet, 1, 20)
	file.SetColWidth("Sheet1", "B", "B", 15)
	file.SetColWidth("Sheet1", "C", "C", 25)
	file.SetColWidth("Sheet1", "D", "D", 12)
	file.SetColWidth("Sheet1", "E", "E", 12)
	file.SetColWidth("Sheet1", "F", "F", 25)
	file.SetColWidth("Sheet1", "G", "G", 20)
	file.SetColWidth("Sheet1", "H", "H", 25)
	file.SetColWidth("Sheet1", "I", "I", 20)

	// 保存文件
	if err := file.SaveAs(savePath); err != nil {
		logger.Error("保存Excel文件失败", logger.Field("err", err))
		return "", err
	}

	return url, nil
}

type CooperativeCannibalizeTaskReq struct {
	CooperativeBusinessId uint32 `json:"cooperative_business_id"`
	StoreId               uint64 `json:"store_id" ` // 门店id
	Status                uint8  `json:"status"`
	PageNum               int    `json:"pageIndex"`
	PageSize              int    `json:"pageSize"`
}
type CooperativeCannibalizeTaskResp struct {
	PageSize  int                    `json:"pageSize"`
	List      []CannibalizeStockTask `json:"list"`
	Count     int                    `json:"count"`
	PageIndex int                    `json:"pageIndex"`
	TotalPage int                    `json:"total_page"`
}

func (m *CooperativeCannibalizeTaskReq) List() (*CooperativeCannibalizeTaskResp, error) {
	resp := &CooperativeCannibalizeTaskResp{
		PageIndex: m.PageNum,
		PageSize:  m.PageSize,
	}
	qs := orm.Eloquent.Table("cannibalize_stock_task")
	if m.StoreId != 0 {
		qs = qs.Where("from_store_id = ?", m.StoreId).Or("to_store_id = ?", m.StoreId)
	} else {
		storeIds, err := GetStoreIdsByCooperativeBusinessId(m.CooperativeBusinessId)
		if err != nil {
			logger.Error("get store ids err:", logger.Field("err", err))
			return resp, err
		}
		qs = qs.Where("from_store_id in (?)", storeIds).Or("to_store_id in (?)", storeIds)
	}
	if m.Status != 0 {
		qs = qs.Where("status = ?", m.Status)
	}
	page := m.PageNum - 1
	if page < 0 {
		page = 0
	}
	if m.PageSize == 0 {
		m.PageSize = 10
	}
	var (
		count int64
		tasks []CannibalizeStockTask
	)

	err := qs.Count(&count).Offset(page * m.PageSize).Limit(m.PageSize).Order("id DESC").Find(&tasks).Error
	if err != nil && err != RecordNotFound {
		logger.Error(err.Error())
		return resp, err
	}

	resp.Count = int(count)
	resp.List = CannibalizeStockTaskListSetInfo(tasks)

	return resp, nil
}

func CannibalizeStockTaskListSetInfo(tasks []CannibalizeStockTask) []CannibalizeStockTask {
	if len(tasks) == 0 {
		return tasks
	}
	storeMap := GetStoreMap()
	for i, _ := range tasks {
		toStore, ok1 := storeMap[tasks[i].ToStoreId]
		if ok1 {
			tasks[i].ToStoreName = toStore.Name
		}
		fromStore, ok2 := storeMap[tasks[i].FromStoreId]
		if ok2 {
			tasks[i].FromStoreName = fromStore.Name
		}
	}

	return tasks
}

func GetStoreMap() map[uint32]Store {
	storeMap := make(map[uint32]Store, 0)
	var stores []Store
	err := orm.Eloquent.Table("store").Find(&stores).Error
	if err != nil {
		logger.Error(err.Error())
		return storeMap
	}
	for i, _ := range stores {
		storeMap[stores[i].ID] = stores[i]
	}

	return storeMap
}

func CannibalizeTaskImportGoods(taskId uint32, serials []string) (uint32, error) {
	if taskId == 0 || len(serials) == 0 {
		return 0, errors.New("para err")
	}
	var cannibalizeTask CannibalizeStockTask
	err := orm.Eloquent.Table("cannibalize_stock_task").Where("id = ?", taskId).Find(&cannibalizeTask).Error
	if err != nil {
		logger.Error("cannibalize task err:", logger.Field("err", err))
		return 0, err
	}
	if cannibalizeTask.Status != CannibalizeTaskStatusNotImportGoods &&
		cannibalizeTask.Status != CannibalizeTaskStatusNotDeliverGoods {
		logger.Error("cannibalize status err:", logger.Field("err", err))
		return 0, err
	}

	var cannibalizeGoodses []CannibalizeGameCardGoods
	err = orm.Eloquent.Table("cannibalize_game_card_goods").Where("cannibalize_stock_task_id = ?", taskId).Find(&cannibalizeGoodses).Error
	if err != nil && err != RecordNotFound {
		logger.Error("cannibalize goods err:", logger.Field("err", err))
		return 0, err
	}
	impotentSerialMap := make(map[string]uint32, 0)
	if len(cannibalizeGoodses) > 0 {
		for i, _ := range cannibalizeGoodses {
			impotentSerialMap[cannibalizeGoodses[i].SerialNumber] = cannibalizeGoodses[i].GameCardId
		}
	}

	serialNumberSql := ""
	for i, _ := range serials {
		serialNumberSql += "'" + serials[i] + "',"
	}
	serialNumberSql = serialNumberSql[:len(serialNumberSql)-1]
	// 这些卡已在调拨任务中
	var cannibalizeInGoodses []CannibalizeGameCardGoods
	sql := fmt.Sprintf("SELECT cannibalize_game_card_goods.* FROM cannibalize_game_card_goods LEFT JOIN cannibalize_stock_task ON cannibalize_stock_task.id = cannibalize_game_card_goods.cannibalize_stock_task_id WHERE  serial_number IN (%s) AND cannibalize_stock_task.status  IN (1,2,3) ;", serialNumberSql)
	err = orm.Eloquent.Raw(sql).Scan(&cannibalizeInGoodses).Error
	if err != nil {
		logger.Error("cannibalize in goods err:", logger.Field("err", err))
		return 0, err
	}
	cannibalizeInGoodsMap := make(map[string]uint32, 0)
	if len(cannibalizeInGoodses) > 0 {
		for i, _ := range cannibalizeInGoodses {
			cannibalizeInGoodsMap[cannibalizeInGoodses[i].SerialNumber] = cannibalizeInGoodses[i].GameCardId
		}
	}

	//orm.Eloquent.Table("cannibalize_game_card_goods").Where("serial_number in (?)", serials).Where("")

	list := make([]GameCardGoods, 0)
	err = orm.Eloquent.Table("game_card_goods").Where("serial_number in (?)", serials).Find(&list).Error
	if err != nil {
		logger.Error(err.Error())
		return 0, err
	}
	unImpotentCount := 0
	impotentCount := 0
	for i, _ := range list {
		if list[i].Status != 1 {
			unImpotentCount++
			//fmt.Println("1", list[i].Status)
			continue
		}
		_, ok := impotentSerialMap[list[i].SerialNumber]
		if ok {
			unImpotentCount++
			//fmt.Println("2", list[i].SerialNumber)
			continue
		}
		if uint32(list[i].StoreId) != cannibalizeTask.FromStoreId {
			//fmt.Println("3", list[i].StoreId)
			continue
		}
		_, ok2 := cannibalizeInGoodsMap[list[i].SerialNumber]
		if ok2 {
			unImpotentCount++
			//fmt.Println("4", list[i].SerialNumber)
			continue
		}

		//begin := orm.Eloquent.Begin()
		//err := orm.Eloquent.Table("game_card_goods").Where("serial_number", list[i].SerialNumber).Delete(&list[i]).Error
		//if err != nil {
		//	begin.Rollback()
		//	logger.Error(err.Error())
		//	continue
		//}
		//
		//sql := fmt.Sprintf("UPDATE game_card_goods_stock SET rent_stock= rent_stock-1,store_stock=store_stock-1,total_stock=total_stock-1 WHERE store_id=%d AND game_card_id=%d;", list[i].StoreId, list[i].GameCardId)
		//fmt.Println("sql:", sql)
		//err = begin.Exec(sql).Error
		//if err != nil {
		//	begin.Rollback()
		//	logger.Errorf(err.Error())
		//	continue
		//}
		//
		//err = begin.Commit().Error
		//if err != nil {
		//	begin.Rollback()
		//	logger.Error("commit err:", err)
		//	continue
		//}

		cardGoods := &CannibalizeGameCardGoods{
			CannibalizeStockTaskId: taskId,
			GameCardId:             uint32(list[i].GameCardId),
			SerialNumber:           list[i].SerialNumber,
		}
		err := orm.Eloquent.Create(cardGoods).Error
		if err != nil {
			logger.Error(err.Error())
			unImpotentCount++
			continue
		}
		impotentCount++
	}

	if cannibalizeTask.Status == CannibalizeTaskStatusNotImportGoods && impotentCount > 0 {
		sql := fmt.Sprintf("UPDATE cannibalize_stock_task SET status = 2 WHERE id = %d", taskId)
		err = orm.Eloquent.Exec(sql).Error
		if err != nil {
			logger.Error("update status err", logger.Field("err", err))
		}
	}

	return uint32(unImpotentCount), nil
}

func CannibalizeDeliverGoods(taskId uint32) error {
	var cannibalizeTask CannibalizeStockTask
	err := orm.Eloquent.Table("cannibalize_stock_task").Where("id = ?", taskId).Find(&cannibalizeTask).Error
	if err != nil {
		logger.Error("cannibalize task err:", logger.Field("err", err))
		return err
	}
	if cannibalizeTask.Status != CannibalizeTaskStatusNotDeliverGoods {
		return errors.New("cannibalize task status err")
	}
	var cannibalizeGoodses []CannibalizeGameCardGoods
	err = orm.Eloquent.Table("cannibalize_game_card_goods").Where("cannibalize_stock_task_id = ?", taskId).
		Find(&cannibalizeGoodses).Error
	if err != nil && err != RecordNotFound {
		logger.Error("cannibalize goods err:", logger.Field("err", err))
		return err
	}
	serials := make([]string, 0, len(cannibalizeGoodses))
	serialMap := make(map[string]int, 0)
	for i, _ := range cannibalizeGoodses {
		serials = append(serials, cannibalizeGoodses[i].SerialNumber)
		serialMap[cannibalizeGoodses[i].SerialNumber] = i
	}
	list := make([]GameCardGoods, 0)
	err = orm.Eloquent.Table("game_card_goods").Where("serial_number in (?)", serials).Find(&list).Error
	if err != nil {
		logger.Error(err.Error())
		return err
	}

	for i, _ := range list {
		if list[i].Status != 1 {
			//fmt.Println("--------list[i]", list[i])
			err = orm.Eloquent.Unscoped().Table("cannibalize_game_card_goods").Where("serial_number",
				list[i].SerialNumber).Delete(&CannibalizeGameCardGoods{}).Error
			if err != nil {
				logger.Error("delete card goods err:", logger.Field("err", err))
			}
			continue
		}
		begin := orm.Eloquent.Begin()
		//err := orm.Eloquent.Table("game_card_goods").Where("serial_number", list[i].SerialNumber).Delete(&list[i]).Error
		//if err != nil {
		//	begin.Rollback()
		//	logger.Error(err.Error())
		//	continue
		//}
		sqlStatus := fmt.Sprintf("UPDATE game_card_goods SET status = 4 WHERE id = %d;", list[i].ID)
		err = begin.Exec(sqlStatus).Error
		if err != nil {
			begin.Rollback()
			logger.Errorf(err.Error())
			continue
		}

		//sql := fmt.Sprintf("UPDATE game_card_goods_stock SET rent_stock= rent_stock-1,store_stock=store_stock-1,total_stock=total_stock-1 WHERE store_id=%d AND game_card_id=%d;", list[i].StoreId, list[i].GameCardId)
		sql := fmt.Sprintf(
			"UPDATE game_card_goods_stock SET rent_stock= rent_stock-1,total_stock=total_stock-1 WHERE store_id=%d AND game_card_id=%d;",
			list[i].StoreId, list[i].GameCardId)
		fmt.Println("sql:", sql)
		err = begin.Exec(sql).Error
		if err != nil {
			begin.Rollback()
			logger.Error(err.Error())
			continue
		}

		err = begin.Commit().Error
		if err != nil {
			begin.Rollback()
			logger.Error("commit err:", logger.Field("err", err))
			continue
		}
		delete(serialMap, list[i].SerialNumber)

	}

	// 没有更新库存的卡
	if len(serialMap) > 0 {
		for k, _ := range serialMap {
			//fmt.Println("--------k", k)
			err = orm.Eloquent.Unscoped().Table("cannibalize_game_card_goods").Where("serial_number=?", k).Delete(&CannibalizeGameCardGoods{}).Error
			if err != nil {
				logger.Error("delete card goods err:", logger.Field("err", err))
			}
		}
	}

	if cannibalizeTask.Status == CannibalizeTaskStatusNotDeliverGoods {
		sql := fmt.Sprintf("UPDATE cannibalize_stock_task SET status = 3,delivery_time=? WHERE id = %d", taskId)
		err = orm.Eloquent.Exec(sql, time.Now()).Error
		if err != nil {
			logger.Error("update status err", logger.Field("err", err))
		}
	}

	return nil
}

func CannibalizePutInStorage(taskId uint32) error {
	var cannibalizeTask CannibalizeStockTask
	err := orm.Eloquent.Table("cannibalize_stock_task").Where("id = ?", taskId).Find(&cannibalizeTask).Error
	if err != nil {
		logger.Error("cannibalize task err:", logger.Field("err", err))
		return err
	}
	if cannibalizeTask.Status != CannibalizeTaskStatusDeliveredGoods {
		return errors.New("cannibalize task status err")
	}
	var cannibalizeGoodses []CannibalizeGameCardGoods
	err = orm.Eloquent.Table("cannibalize_game_card_goods").Where("cannibalize_stock_task_id = ?", taskId).
		Find(&cannibalizeGoodses).Error
	if err != nil && err != RecordNotFound {
		logger.Error("cannibalize goods err:", logger.Field("err", err))
		return err
	}
	serials := make([]string, 0, len(cannibalizeGoodses))
	for i, _ := range cannibalizeGoodses {
		serials = append(serials, cannibalizeGoodses[i].SerialNumber)
	}
	list := make([]GameCardGoods, 0)
	err = orm.Eloquent.Table("game_card_goods").Where("serial_number in (?)", serials).Find(&list).Error
	if err != nil {
		logger.Error(err.Error())
		return err
	}
	for i, _ := range list {
		if list[i].Status != 4 {
			continue
		}
		//if CannibalizeUserShareCardRetrieve(cannibalizeTask.ToStoreId, list[i]) {
		//	continue
		//}
		var count int64
		err = orm.Eloquent.Table("game_card_goods_stock").Where("store_id = ?", cannibalizeTask.ToStoreId).
			Where("game_card_id = ?", list[i].GameCardId).Count(&count).Error
		if err != nil {
			logger.Error(err.Error())
			continue
		}

		begin := orm.Eloquent.Begin()
		sqlStatus := fmt.Sprintf("UPDATE game_card_goods SET status = 1,store_id=%d,stock_time='%s' WHERE id = %d;",
			cannibalizeTask.ToStoreId, time.Now().Format(TimeFormat), list[i].ID)
		err = begin.Exec(sqlStatus).Error
		if err != nil {
			begin.Rollback()
			logger.Errorf(err.Error())
			continue
		}

		if count > 0 {
			sql := fmt.Sprintf("UPDATE game_card_goods_stock SET rent_stock= rent_stock+1,store_stock=store_stock+1,total_stock=total_stock+1 WHERE store_id=%d AND game_card_id=%d;", cannibalizeTask.ToStoreId, list[i].GameCardId)
			fmt.Println("sql:", sql)
			err = begin.Exec(sql).Error
			if err != nil {
				begin.Rollback()
				logger.Errorf(err.Error())
				continue
			}
		} else {
			cardGoodsStock := &GameCardGoodsStock{
				StoreId:       uint64(cannibalizeTask.ToStoreId),
				GameCardId:    list[i].GameCardId,
				StoreStock:    1,
				RentStock:     1,
				UserHoldStock: 0,
				OrderCount:    0,
				TotalStock:    1,
			}
			err := begin.Create(cardGoodsStock).Error
			if err != nil {
				begin.Rollback()
				logger.Errorf(err.Error())
				continue
			}
		}

		err = begin.Commit().Error
		if err != nil {
			begin.Rollback()
			logger.Error("commit err:", logger.Field("err", err))
			continue
		}
	}

	if cannibalizeTask.Status == CannibalizeTaskStatusDeliveredGoods {
		sql := fmt.Sprintf("UPDATE cannibalize_stock_task SET status = 4,in_storage_time=? WHERE id = %d", taskId)
		err = orm.Eloquent.Exec(sql, time.Now()).Error
		if err != nil {
			logger.Error("update status err", logger.Field("err", err))
		}
	}

	return nil
}

//func CannibalizeUserShareCardRetrieve(storeId uint32, cardGoods GameCardGoods) bool {
//	var retrieveCard ShareCardRetrieveCard
//	err := orm.Eloquent.Table("share_card_retrieve_card").Where("game_card_id=?", cardGoods.GameCardId).
//		Where("store_id=?", storeId).Where("state", RetrieveStateOutStock).Order("id DESC").
//		Limit(1).Find(&retrieveCard).Error
//	if err != nil {
//		logger.Error("share card retrieve card err:", err)
//		return false
//	}
//	//var outStockCount int64
//	//err = orm.Eloquent.Table("share_card_retrieve_card").Where("share_card_retrieve_id=?", retrieveCard.ShareCardRetrieveId).
//	//	Where("id!=?", retrieveCard.ID).Where("state", RetrieveStateOutStock).Total(&outStockCount).Error
//	//if err != nil {
//	//	logger.Error("out stock count err:", err)
//	//	return false
//	//}
//	var retrieveCardList []ShareCardRetrieveCard
//	err = orm.Eloquent.Table("share_card_retrieve_card").
//		Where("share_card_retrieve_id=?", retrieveCard.ShareCardRetrieveId).Find(&retrieveCardList).Error
//	if err != nil {
//		logger.Error("share card retrieve cards err:", err)
//		return false
//	}
//	isHaveOutStock := 1
//	for i, _ := range retrieveCardList {
//		if retrieveCardList[i].ID != retrieveCard.ID && retrieveCardList[i].State == RetrieveStateOutStock {
//			isHaveOutStock = 2
//		}
//	}
//	begin := orm.Eloquent.Begin()
//	err = begin.Table("game_card_goods").Where("id=?)", cardGoods.ID).Updates(map[string]interface{}{
//		"status": 5,
//	}).Error
//	if err != nil {
//		begin.Rollback()
//		logger.Error("update share card retrieve card err:", err)
//		return false
//	}
//	err = begin.Table("share_card_retrieve_card").Where("id=?", retrieveCard.ID).Updates(map[string]interface{}{
//		//"state":                       RetrieveStateInSendCard,
//		"state":                       RetrieveStateInReceiveCard,
//		"retrieve_serial_number":      cardGoods.SerialNumber,
//		"retrieve_game_card_goods_id": cardGoods.ID,
//	}).Error
//	if err != nil {
//		begin.Rollback()
//		logger.Error("update share card retrieve err:", err)
//		return false
//	}
//
//	err = begin.Table("user_share_card").Where("id=?", retrieveCard.UserShareCardId).Updates(map[string]interface{}{
//		"state":                       ShareCardBillStateReceivedCard,
//		"retrieve_serial_number":      cardGoods.SerialNumber,
//		"retrieve_game_card_goods_id": cardGoods.ID,
//	}).Error
//	if err != nil {
//		begin.Rollback()
//		logger.Error("update share card retrieve err:", err)
//		return false
//	}
//	if isHaveOutStock == 2 {
//		err = begin.Table("share_card_retrieve").Where("id=?", retrieveCard.ShareCardRetrieveId).Updates(map[string]interface{}{
//			//"state": RetrieveStateInSendCard,
//			"state": RetrieveStateInReceiveCard,
//		}).Error
//		if err != nil {
//			begin.Rollback()
//			logger.Error("update share card retrieve card err:", err)
//			return false
//		}
//	}
//	err = begin.Commit().Error
//	if err != nil {
//		begin.Rollback()
//		logger.Error("commit err:", err)
//		return false
//	}
//	return true
//}

type CannibalizeTaskGameCardGoodsListReq struct {
	PageNum                int    `json:"pageIndex"`
	PageSize               int    `json:"pageSize"`
	CannibalizeStockTaskId uint32 `json:"cannibalize_stock_task_id"`
}
type CannibalizeTaskGameCardGoodsListResp struct {
	PageSize  int                        `json:"pageSize"`
	List      []CannibalizeGameCardGoods `json:"list"`
	Count     int                        `json:"count"`
	PageIndex int                        `json:"pageIndex"`
	TotalPage int                        `json:"total_page"`
}

func (m *CannibalizeTaskGameCardGoodsListReq) GetCannibalizeTaskGameCardGoodsList() (*CannibalizeTaskGameCardGoodsListResp, error) {
	resp := &CannibalizeTaskGameCardGoodsListResp{
		PageIndex: m.PageNum,
		PageSize:  m.PageSize,
	}
	qs := orm.Eloquent.Table("cannibalize_game_card_goods").Where("cannibalize_stock_task_id = ?", m.CannibalizeStockTaskId)

	page := m.PageNum - 1
	if page < 0 {
		page = 0
	}
	if m.PageSize == 0 {
		m.PageSize = 10
	}
	var (
		count              int64
		cannibalizeGoodses []CannibalizeGameCardGoods
	)
	//CannibalizeGameCardGoods int `json:"cannibalize_game_card_goods" gorm:"-"`
	err := qs.Count(&count).Offset(page * m.PageSize).Limit(m.PageSize).Order("id DESC").Find(&cannibalizeGoodses).Error
	if err != nil && err != RecordNotFound {
		logger.Error(err.Error())
		return resp, err
	}

	resp.Count = int(count)
	resp.List = CannibalizeGameCardGoodsSetInfo(cannibalizeGoodses)

	return resp, nil
}

func CannibalizeGameCardGoodsSetInfo(goodses []CannibalizeGameCardGoods) []CannibalizeGameCardGoods {
	if len(goodses) == 0 {
		return goodses
	}
	ids := make([]uint32, 0)
	for i, _ := range goodses {
		ids = append(ids, goodses[i].GameCardId)
	}
	var gameCards []GameCard
	err := orm.Eloquent.Table("game_card").Where("id IN (?)", ids).Find(&gameCards).Error
	if err != nil {
		logger.Error(err.Error())
		return goodses
	}
	gameCardMap := make(map[uint32]GameCard, 0)
	for i, _ := range gameCards {
		gameCardMap[gameCards[i].ID] = gameCards[i]
	}

	for i, _ := range goodses {
		v, ok := gameCardMap[goodses[i].GameCardId]
		if ok {
			goodses[i].GameCardName = v.Name
		}
	}

	return goodses
}

func CannibalizeTaskDel(taskId uint32) error {
	var cannibalizeTask CannibalizeStockTask
	err := orm.Eloquent.Table("cannibalize_stock_task").Where("id = ?", taskId).Find(&cannibalizeTask).Error
	if err != nil {
		logger.Error("cannibalize task err:", logger.Field("err", err))
		return err
	}

	if cannibalizeTask.Status != CannibalizeTaskStatusNotImportGoods && cannibalizeTask.Status != CannibalizeTaskStatusNotDeliverGoods {
		return errors.New("status err")
	}
	sql := fmt.Sprintf("UPDATE cannibalize_stock_task SET status = 5 WHERE id = %d", taskId)
	err = orm.Eloquent.Exec(sql).Error
	if err != nil {
		logger.Error("update status err:", logger.Field("err", err))
	}
	return nil
}

func (m *GameCardGoodsStock) AddStock(begin *gorm.DB) error {
	if begin == nil {
		begin = orm.Eloquent
	}
	sql := fmt.Sprintf("UPDATE game_card_goods_stock SET rent_stock= rent_stock+1,total_stock=total_stock+1 WHERE store_id=%d AND game_card_id=%d;", m.StoreId, m.GameCardId)
	fmt.Println("sql:", sql)
	err := begin.Exec(sql).Error
	if err != nil {
		begin.Rollback()
		logger.Errorf(err.Error())
		return err
	}

	return nil
}

func (m *GameCardGoodsStock) SubStock(begin *gorm.DB) error {
	if begin == nil {
		begin = orm.Eloquent
	}
	sql := fmt.Sprintf("UPDATE game_card_goods_stock SET rent_stock= rent_stock-1,total_stock=total_stock-1 WHERE store_id=%d AND game_card_id=%d;", m.StoreId, m.GameCardId)
	fmt.Println("sql:", sql)
	err := begin.Exec(sql).Error
	if err != nil {
		begin.Rollback()
		logger.Errorf(err.Error())
		return err
	}

	return nil
}

func CooperativeExportGoodsStock(storeIds []uint32, business CooperativeBusiness) string {
	var games []GameCard
	err := orm.Eloquent.Table("game_card").Order("id DESC").Find(&games).Error
	if err != nil {
		logger.Error(err.Error())
		return ""
	}
	fileName := business.Name
	if len(storeIds) == 1 {
		var store Store
		err = orm.Eloquent.Table("store").Where("id", storeIds[0]).Order("id DESC").Find(&store).Error
		if err != nil {
			logger.Error(err.Error())
			return ""
		}
		fileName = store.Name
	}

	storeInfo, err := CooperativeGoodsStockStoreInfo(games, storeIds)
	if err != nil {
		logger.Error(err.Error())
		return ""
	}
	return GoodsStockFile(storeInfo, fileName)
}

func CooperativeGoodsStockStoreInfo(gameCards []GameCard, storeIds []uint32) ([]ExportGoods, error) {
	goodsData := make([]ExportGoods, 0, len(gameCards))

	cardStocks := make([]GameCardGoodsStock, 0)
	err := orm.Eloquent.Table("game_card_goods_stock").Where("store_id in (?)", storeIds).Order("id DESC").Find(&cardStocks).Error
	if err != nil {
		logger.Error(err.Error())
		return goodsData, err
	}
	cardStockMap := make(map[uint64]GameCardGoodsStock, 0)
	for i, _ := range cardStocks {
		cardStockMap[cardStocks[i].GameCardId] = cardStocks[i]
	}

	cardGoods := make([]GameCardGoods, 0)
	err = orm.Eloquent.Table("game_card_goods").Where("store_id in (?)", storeIds).Order("id DESC").Find(&cardGoods).Error
	if err != nil {
		logger.Error(err.Error())
		return goodsData, err
	}
	cardGoodsMap := make(map[uint64][]GameCardGoods, 0)
	for i, _ := range cardGoods {
		cardGoodsMap[cardGoods[i].GameCardId] = append(cardGoodsMap[cardGoods[i].GameCardId], cardGoods[i])
	}

	for _, game := range gameCards {
		cardStock, ok1 := cardStockMap[uint64(game.ID)]
		gameCardGoods, ok2 := cardGoodsMap[uint64(game.ID)]
		if !ok1 || !ok2 {
			continue
		}

		exportGoods := &ExportGoods{
			GoodsName: game.Name,
			//CardPool:  cardStock.StoreStock,
			RentStock:  cardStock.RentStock,
			OrderCount: cardStock.OrderCount,
			Goods:      gameCardGoods,
		}

		exportGoods.CardPool = uint32(len(gameCardGoods))
		for i, _ := range gameCardGoods {
			if gameCardGoods[i].Status == GameCardGoodsStatusCustomerHold {
				exportGoods.PlayerHold += 1
			}
		}
		if uint32(len(gameCardGoods)) > exportGoods.RentStock+exportGoods.PlayerHold {
			exportGoods.DelayDeliverGameCard = uint32(len(gameCardGoods)) - exportGoods.RentStock - exportGoods.PlayerHold
		}

		goodsData = append(goodsData, *exportGoods)
	}

	return goodsData, err
}

type CooperativeExportMemberPromotionReq struct {
	CooperativeBusinessId uint32 `json:"cooperative_business_id"`
	StoreId               uint32 `json:"store_id"`
	Date                  string `json:"date"`
}

func (r *CooperativeExportMemberPromotionReq) Export() string {
	storeIds := []uint32{r.StoreId}
	fileName := ""
	if r.StoreId == 0 {
		ids, err := GetStoreIdsByCooperativeBusinessId(r.CooperativeBusinessId)
		if err != nil {
			logger.Error("get store ids err:", logger.Field("err", err))
			return ""
		}

		var cooperativeBusiness CooperativeBusiness
		err = orm.Eloquent.Table("cooperative_business").Where("id=?", r.CooperativeBusinessId).
			Find(&cooperativeBusiness).Error
		if err != nil {
			logger.Error("cooperative business err:", logger.Field("err", err))
			return ""
		}
		fileName = cooperativeBusiness.Name
		storeIds = ids
	}

	var memberReports []InviteMemberReport
	err := orm.Eloquent.Table("invite_member_report").Where("store_id in (?)", storeIds).
		Where("date=?", r.Date).Order("store_id DESC").Find(&memberReports).Error
	if err != nil && err != RecordNotFound {
		logger.Error("invite member report err:", logger.Field("err", err))
		return ""
	}

	var assistants []UserInfo
	err = orm.Eloquent.Table("user").Where("store_id in (?)", storeIds).
		Order("store_id DESC").Find(&assistants).Error
	if err != nil && err != RecordNotFound {
		logger.Error("invite member report err:", logger.Field("err", err))
		return ""
	}
	//assistantsMap := make(map[uint32]*UserInfo, 0)
	//for i, _ := range assistants {
	//	assistantsMap[assistants[i].Uid] = &assistants[i]
	//}

	memberReportMap := make(map[uint32]*InviteMemberReport, 0)
	for i, _ := range memberReports {
		memberReportMap[memberReports[i].Uid] = &memberReports[i]
	}

	list := make([]InviteMemberReport, 0, len(assistants))
	for i, _ := range assistants {
		v, ok := memberReportMap[assistants[i].Uid]
		if ok {
			list = append(list, *v)
		} else {
			list = append(list, InviteMemberReport{
				Uid:     assistants[i].Uid,
				StoreId: uint32(assistants[i].StoreId),
			})
		}
	}

	//list = InviteMemberReportListSetUser(list)
	//list = InviteMemberReportListSetStore(list)

	//if len(storeIds) == 1 {
	//	var store Store
	//	err = orm.Eloquent.Table("store").Where("id", storeIds[0]).Order("id DESC").Find(&store).Error
	//	if err != nil {
	//		logger.Error(err.Error())
	//		return ""
	//	}
	//	fileName = store.Name
	//}
	//
	//storeInfo, err := CooperativeGoodsStockStoreInfo(games, storeIds)
	//if err != nil {
	//	logger.Error(err.Error())
	//	return ""
	//}

	return MemberReportFile(list, fileName)
}

func MemberReportFile(memberReports []InviteMemberReport, fileName string) string {
	file := excelize.NewFile()
	streamWriter, err := file.NewStreamWriter("Sheet1")
	if err != nil {
		fmt.Println(err)
	}

	//url := "http://39.108.188.218:8000/img/export/"
	fileName = time.Now().Format(TimeFormat) + fileName + ".xlsx"

	title := []interface{}{"门店id", "门店名称", "店员id", "店员名称", "黄金会员数量", "白金会员数量", "黑金会员数量"}
	cell, _ := excelize.CoordinatesToCellName(1, 1)
	if err = streamWriter.SetRow(cell, title); err != nil {
		fmt.Println(err)
	}
	var row []interface{}
	for rowId := 0; rowId < len(memberReports); rowId++ {
		row = []interface{}{fmt.Sprintf("%d", memberReports[rowId].SystemUser.StoreList[0].StoreID), memberReports[rowId].SystemUser.StoreList[0].StoreName,
			fmt.Sprintf("%d", memberReports[rowId].SystemUser.Uid), memberReports[rowId].SystemUser.NickName,
			fmt.Sprintf("%d", memberReports[rowId].GoldCount), fmt.Sprintf("%d", memberReports[rowId].PlatinumCount),
			fmt.Sprintf("%d", memberReports[rowId].BlackGoldCount)}

		cell, _ := excelize.CoordinatesToCellName(1, rowId+2)
		if err := streamWriter.SetRow(cell, row); err != nil {
			fmt.Println(err)
		}
	}
	if err := streamWriter.Flush(); err != nil {
		fmt.Println(err)
	}
	if err := file.SaveAs("/www/server/images/export/" + fileName); err != nil {
		//if err := file.SaveAs("./" + fileName); err != nil {
		fmt.Println(err)
	}

	return config.ExportConfig.Url + fileName
}

type CooperativeSetPayInfoReq struct {
	CooperativeBusinessId uint32 `json:"cooperative_business_id"`             // 合作商id
	UnionPayMerchantId    string `json:"name" binding:"required"`             // 聚合支付平台商户号
	WxAppId               string `json:"wx_app_id"`                           // 微信小程序AppID
	WxAppMchId            string `json:"wx_app_mchId" binding:"required"`     // 微信支付商户号
	WxAppMchSecret        string `json:"wx_app_mchSecret" binding:"required"` // 微信支付商户密钥
}

type CooperativeGetPayInfoReq struct {
	CooperativeBusinessId uint32 `json:"cooperative_business_id"` // 合作商id
}

// GameCardOutRecord 租赁卡出库明细表
type GameCardOutRecord struct {
	Model
	SerialNumber   string     `json:"serial_number" gorm:"index"` // 游戏卡串码
	StoreId        uint64     `json:"store_id"`                   // 门店id
	StoreName      string     `json:"store_name"`                 // 门店名称
	GameCardId     uint64     `json:"game_card_id"`               // 游戏卡id
	GameCardName   string     `json:"game_card_name"`             // 游戏名称
	FirstStockTime *time.Time `json:"first_stock_time"`           // 首次入库时间
	StockTime      *time.Time `json:"stock_time"`                 // 入库时间
	OutStockTime   *time.Time `json:"out_stock_time"`             // 出库时间
	MakerId        uint32     `json:"maker_id" gorm:"index"`      // 出库人id
	MakerName      string     `json:"maker_name"`                 // 出库人名称
}

// GameCardGoodsStockOutInfoListReq 出库明细-入参
type GameCardGoodsStockOutInfoListReq struct {
	StoreId           []uint32 `json:"store_id"`             // 门店id
	GameCardId        uint64   `json:"game_card_id"`         // 游戏卡id
	SerialNumber      string   `json:"serial_number"`        // 游戏卡串码
	OutStockTimeStart string   `json:"out_stock_time_start"` // 出库开始时间
	OutStockTimeEnd   string   `json:"out_stock_time_end"`   // 出库结束时间
	PageIndex         int      `json:"pageIndex"`            // 页码
	PageSize          int      `json:"pageSize"`             // 页面条数
	IsExport          uint32   `json:"is_export"`            // 1-导出
}

// GameCardGoodsStockOutInfoListResp 出库明细-出参
type GameCardGoodsStockOutInfoListResp struct {
	List      []GameCardOutRecord `json:"list"`
	Total     int                 `json:"total"`     // 总条数
	PageIndex int                 `json:"pageIndex"` // 页码
	PageSize  int                 `json:"pageSize"`  // 每页展示条数
	ExportUrl string              `json:"export_url"`
}

// List 租卡系统-库存管理-出库明细
func (m *GameCardGoodsStockOutInfoListReq) List(c *gin.Context) (*GameCardGoodsStockOutInfoListResp, error) {
	resp := &GameCardGoodsStockOutInfoListResp{
		PageIndex: m.PageIndex,
		PageSize:  m.PageSize,
	}

	// 构造基础查询，针对出库记录表
	db := orm.Eloquent.Table("game_card_out_record")

	// 根据门店ID数组进行过滤
	if len(m.StoreId) > 0 {
		db = db.Where("store_id IN (?)", m.StoreId)
	}
	// 根据游戏卡ID过滤
	if m.GameCardId > 0 {
		db = db.Where("game_card_id = ?", m.GameCardId)
	}
	// 根据游戏卡串码模糊查询
	if m.SerialNumber != "" {
		db = db.Where("serial_number LIKE ?", "%"+m.SerialNumber+"%")
	}
	// 根据出库时间范围查询
	if m.OutStockTimeStart != "" && m.OutStockTimeEnd != "" {
		db = db.Where("out_stock_time BETWEEN ? AND ?", m.OutStockTimeStart, m.OutStockTimeEnd)
	}

	// 获取总记录数
	var total int64
	if err := db.Count(&total).Error; err != nil {
		return nil, err
	}
	resp.Total = int(total)

	// 连表查询：左联查store表和game_card表，分别获取门店名称和游戏名称
	// 注意：这里将门店名称别名为store_name，将游戏名称别名为game_card_name，分别对应GameCardOutRecord中的StoreName和GameCardName字段
	db = db.Joins("LEFT JOIN store ON store.id = game_card_out_record.store_id").
		Joins("LEFT JOIN game_card ON game_card.id = game_card_out_record.game_card_id").
		Select("game_card_out_record.*, store.name as store_name, game_card.name as game_card_name")

	// 如果不是导出，则进行分页查询
	if m.IsExport != 1 {
		offset := (m.PageIndex - 1) * m.PageSize
		db = db.Offset(offset).Limit(m.PageSize)
	}

	// 查询数据，按id倒序排序
	var list []GameCardOutRecord
	if err := db.Order("game_card_out_record.id DESC").Find(&list).Error; err != nil {
		return nil, err
	}

	resp.List = list

	if m.IsExport == 1 { // 导出excel
		excelPath, err := exportStockOutDetailExcel(resp)
		if err != nil {
			return nil, err
		}

		resp.ExportUrl = excelPath
		resp.List = nil
	}

	return resp, nil
}

func exportStockOutDetailExcel(resp *GameCardGoodsStockOutInfoListResp) (string, error) {
	// 1. 收集所有需要查询的门店和游戏卡ID，去重处理
	storeIDSet := make(map[uint64]struct{})
	gameCardIDSet := make(map[uint64]struct{})
	for _, record := range resp.List {
		storeIDSet[record.StoreId] = struct{}{}
		gameCardIDSet[record.GameCardId] = struct{}{}
	}
	storeIDs := make([]uint64, 0, len(storeIDSet))
	for id := range storeIDSet {
		storeIDs = append(storeIDs, id)
	}
	gameCardIDs := make([]uint64, 0, len(gameCardIDSet))
	for id := range gameCardIDSet {
		gameCardIDs = append(gameCardIDs, id)
	}

	// 2. 查询门店名称
	var stores []Store
	if err := orm.Eloquent.Table("store").Where("id IN (?)", storeIDs).Find(&stores).Error; err != nil {
		logger.Error("查询门店名称错误", logger.Field("err", err))
		return "", err
	}
	storeMap := make(map[uint64]string)
	// 注意：假设 Store 结构体内 Model 包含 ID 字段
	for _, s := range stores {
		storeMap[uint64(s.ID)] = s.Name
	}

	// 3. 查询游戏卡名称
	var gameCards []GameCard
	if err := orm.Eloquent.Table("game_card").Where("id IN (?)", gameCardIDs).Find(&gameCards).Error; err != nil {
		logger.Error("查询游戏卡名称错误", logger.Field("err", err))
		return "", err
	}
	gameCardMap := make(map[uint64]string)
	for _, g := range gameCards {
		gameCardMap[uint64(g.ID)] = g.Name
	}

	// 4. 将查询到的名称填充到每个记录中
	for i, record := range resp.List {
		if name, ok := storeMap[record.StoreId]; ok {
			resp.List[i].StoreName = name
		}
		if name, ok := gameCardMap[record.GameCardId]; ok {
			resp.List[i].GameCardName = name
		}
	}

	// 5. 生成 Excel 文件
	file := excelize.NewFile()
	fSheet := "Sheet1"
	url := config.ExportConfig.Url
	fileName := time.Now().Format(TimeFormat) + "出库明细" + ".xlsx"
	fmt.Println("save fileName:", url+fileName)

	// 设置标题行
	title := []interface{}{"游戏卡串码", "门店名称", "游戏名称", "首次入库时间", "入库时间", "出库时间", "出库人"}
	for i, v := range title {
		cell, _ := excelize.CoordinatesToCellName(i+1, 1)
		if err := file.SetCellValue(fSheet, cell, v); err != nil {
			logger.Error("设置标题值错误", logger.Field("err", err))
		}
	}

	// 循环写入每条出库记录
	rowIndex := 0
	for _, record := range resp.List {
		var firstStockTime, stockTime, outStockTime string
		if record.FirstStockTime != nil {
			firstStockTime = record.FirstStockTime.Format("2006-01-02 15:04:05")
		}
		if record.StockTime != nil {
			stockTime = record.StockTime.Format("2006-01-02 15:04:05")
		}
		if record.OutStockTime != nil {
			outStockTime = record.OutStockTime.Format("2006-01-02 15:04:05")
		}

		rowData := []interface{}{
			record.SerialNumber, // 游戏卡串码
			record.StoreName,    // 门店名称
			record.GameCardName, // 游戏名称
			firstStockTime,      // 首次入库时间
			stockTime,           // 入库时间
			outStockTime,        // 出库时间
			record.MakerName,    // 出库人
		}

		for j, v := range rowData {
			cell, _ := excelize.CoordinatesToCellName(j+1, rowIndex+2)
			if err := file.SetCellValue(fSheet, cell, v); err != nil {
				logger.Error("写入单元格值错误", logger.Field("err", err))
			}
		}
		rowIndex++
	}

	// 写入统计行（例如记录总数）
	totalData := "记录数:" + strconv.Itoa(resp.Total)
	summary := []interface{}{totalData, "", "", "", "", "", ""}
	for i, v := range summary {
		cell, _ := excelize.CoordinatesToCellName(i+1, rowIndex+2)
		if err := file.SetCellValue(fSheet, cell, v); err != nil {
			logger.Error("写入统计数据错误", logger.Field("err", err))
		}
	}

	// 设置样式：居中、加边框
	style, _ := file.NewStyle(`{"alignment":{"horizontal":"center","vertical":"center"},
		"border":[{"type":"left","color":"000000","style":1},
				  {"type":"top","color":"000000","style":1},
				  {"type":"right","color":"000000","style":1},
				  {"type":"bottom","color":"000000","style":1}]}`)
	_ = file.SetRowHeight(fSheet, 1, 20)
	_ = file.SetColWidth(fSheet, "A", "A", 20)
	_ = file.SetColWidth(fSheet, "B", "B", 20)
	_ = file.SetColWidth(fSheet, "C", "C", 20)
	_ = file.SetColWidth(fSheet, "D", "D", 25)
	_ = file.SetColWidth(fSheet, "E", "E", 25)
	_ = file.SetColWidth(fSheet, "F", "F", 25)
	_ = file.SetColWidth(fSheet, "G", "G", 15)

	endRow, _ := excelize.CoordinatesToCellName(7, rowIndex+2)
	_ = file.SetCellStyle(fSheet, "A1", endRow, style)

	// 保存文件
	if err := file.SaveAs(config.ExportConfig.Path + fileName); err != nil {
		logger.Error("保存文件错误", logger.Field("err", err))
		return "", err
	}

	return url + fileName, nil
}

// BatchRevertCard 批量归还卡带
func BatchRevertCard() {
	//type CardUserInfo struct {
	//	CreatedAt    time.Time
	//	UpdatedAt    time.Time
	//	OrderID      uint64
	//	Uid          uint64
	//	Tel          string
	//	MemberLevel  uint8
	//	Deposit      uint32
	//	MemberExpire time.Time
	//	GameCardId   uint64
	//	SerialNumber string
	//	StoreId      uint64
	//}
	//
	//var list []CardUserInfo
	//
	//// 查询符合条件的记录
	//err := orm.Eloquent.Table("order_card AS oc").
	//	Select("oc.created_at, oc.updated_at, oc.order_id, oc.uid, u.tel, u.member_level, u.deposit, u.member_expire, oc.game_card_id, oc.serial_number, oc.store_id").
	//	Joins("JOIN user AS u ON oc.uid = u.uid").
	//	Where("oc.card_status IN (2, 3)").
	//	Where("u.member_level NOT IN (2, 3, 4, 5)").
	//	Where("u.member_expire < ?", "2024-04-01 00:00:00").
	//	Find(&list).Error
	//if err != nil {
	//	fmt.Printf("BatchRevertCard query error: %v", err)
	//	return
	//}
	//
	//if len(list) == 0 {
	//	fmt.Println("BatchRevertCard: no records to process")
	//	return
	//}
	//
	//for _, info := range list {
	//	order := &Order{
	//		Model:                Model{ID: uint32(info.OrderID)},
	//		GameCardSerialNumber: info.SerialNumber,
	//		RevertStoreId:        25,
	//		RevertShopperCode:    "833998",
	//		PhoneExt:             getPhoneExt(info.Tel),
	//	}
	//
	//	err = order.Revert()
	//	if err != nil {
	//		errStr := fmt.Sprintf("BatchRevertCard revert error, orderID: %d, serialNumber: %s", info.OrderID, info.SerialNumber)
	//		logger.Error("*****err*****", logger.Field("err", errStr))
	//		// 如果需要可以继续处理其他订单，不 return
	//		continue
	//	}
	//	fmt.Printf("BatchRevertCard success, orderID: %d, serialNumber: %s", info.OrderID, info.SerialNumber)
	//}
}

// 截取手机号后四位
func getPhoneExt(phone string) string {
	if len(phone) >= 4 {
		return phone[len(phone)-4:]
	}
	return ""
}
