package user

import (
	"context"

	"bindbox-game/internal/repository/mysql/model"
)

type ItemCardWithTemplate struct {
	*model.UserItemCards
	Name             string `json:"name"`
	CardType         int32  `json:"card_type"`
	ScopeType        int32  `json:"scope_type"`
	EffectType       int32  `json:"effect_type"`
	StackingStrategy int32  `json:"stacking_strategy"`
	Remark           string `json:"remark"`
	Count            int64  `json:"count"`
	UsedActivityName string `json:"used_activity_name"`
	UsedIssueNumber  string `json:"used_issue_number"`
	UsedRewardName   string `json:"used_reward_name"`
}

// ListAggregatedUserItemCards 获取聚合后的用户道具卡列表（按卡种分组）
func (s *service) ListAggregatedUserItemCards(ctx context.Context, userID int64, status int32, page, pageSize int) (items []*ItemCardWithTemplate, total int64, err error) {
	// 1. 计算分组总数 (Using UnderlyingDB for raw SQL flexibility)
	var countResult []struct {
		CardID int64
		Total  int64
	}

	tx := s.readDB.UserItemCards.WithContext(ctx).ReadDB().UnderlyingDB().
		Model(&model.UserItemCards{}).
		Where("user_id = ? AND status = ?", userID, status)

	// Count Distinct CardID
	err = tx.Distinct("card_id").Count(&total).Error
	if err != nil {
		return nil, 0, err
	}

	if page <= 0 {
		page = 1
	}
	if pageSize <= 0 {
		pageSize = 20
	}

	// 2. 分页查询分组数据
	err = tx.Select("card_id, count(*) as total").
		Group("card_id").
		Order("card_id desc").
		Offset((page - 1) * pageSize).
		Limit(pageSize).
		Scan(&countResult).Error
	if err != nil {
		return nil, 0, err
	}

	if len(countResult) == 0 {
		return []*ItemCardWithTemplate{}, 0, nil
	}

	// 3. 获取每组的一个实例（用于获取有效期等信息）和模板信息
	cardIDs := make([]int64, 0, len(countResult))
	for _, r := range countResult {
		cardIDs = append(cardIDs, r.CardID)
	}

	// 获取模板信息
	tpls := map[int64]*model.SystemItemCards{}
	// Using GEN helpers for simple queries
	tplList, err := s.readDB.SystemItemCards.WithContext(ctx).ReadDB().Where(s.readDB.SystemItemCards.ID.In(cardIDs...)).Find()
	if err != nil {
		return nil, 0, err
	}
	for _, t := range tplList {
		tpls[t.ID] = t
	}

	items = make([]*ItemCardWithTemplate, 0, len(countResult))
	for _, r := range countResult {
		// Find latest instance using GEN helpers
		instance, _ := s.readDB.UserItemCards.WithContext(ctx).ReadDB().
			Where(s.readDB.UserItemCards.UserID.Eq(userID), s.readDB.UserItemCards.Status.Eq(status), s.readDB.UserItemCards.CardID.Eq(r.CardID)).
			Order(s.readDB.UserItemCards.ID.Desc()).
			First()

		if instance == nil {
			instance = &model.UserItemCards{UserID: userID, CardID: r.CardID, Status: status}
		}

		tpl := tpls[r.CardID]
		var name, remark string
		var cardType, scopeType, effectType, stacking int32

		if tpl != nil {
			name = tpl.Name
			cardType = tpl.CardType
			scopeType = tpl.ScopeType
			effectType = tpl.EffectType
			stacking = tpl.StackingStrategy
			remark = tpl.Remark
		}

		items = append(items, &ItemCardWithTemplate{
			UserItemCards:    instance,
			Name:             name,
			CardType:         cardType,
			ScopeType:        scopeType,
			EffectType:       effectType,
			StackingStrategy: stacking,
			Remark:           remark,
			Count:            r.Total,
		})
	}

	return items, total, nil
}

// ListUserItemCards 获取用户道具卡列表
// 功能描述：
//   - 查询指定用户的道具卡列表
//   - 支持分页查询，默认每页20条，最大100条
//   - 按创建时间倒序排列
//
// 参数说明：
//   - ctx: 上下文
//   - userID: 用户ID
//   - page: 页码，从1开始，小于1时自动设为1
//   - pageSize: 每页条数，小于1时设为20，大于100时设为100
//
// 返回说明：
//   - items: 道具卡列表
//   - total: 总记录数
//   - err: 错误信息
func (s *service) ListUserItemCards(ctx context.Context, userID int64, page, pageSize int) (items []*model.UserItemCards, total int64, err error) {
	q := s.readDB.UserItemCards.WithContext(ctx).ReadDB().Where(s.readDB.UserItemCards.UserID.Eq(userID))
	total, err = q.Count()
	if err != nil {
		return nil, 0, err
	}
	if page <= 0 {
		page = 1
	}
	if pageSize <= 0 {
		pageSize = 20
	}
	if pageSize > 100 {
		pageSize = 100
	}
	items, err = q.Order(s.readDB.UserItemCards.ID.Desc()).Offset((page - 1) * pageSize).Limit(pageSize).Find()
	if err != nil {
		return nil, 0, err
	}
	return items, total, nil
}

func (s *service) ListUserItemCardsWithTemplate(ctx context.Context, userID int64, page, pageSize int) (items []*ItemCardWithTemplate, total int64, err error) {
	q := s.readDB.UserItemCards.WithContext(ctx).ReadDB().Where(s.readDB.UserItemCards.UserID.Eq(userID))
	total, err = q.Count()
	if err != nil {
		return nil, 0, err
	}
	if page <= 0 {
		page = 1
	}
	if pageSize <= 0 {
		pageSize = 20
	}
	if pageSize > 100 {
		pageSize = 100
	}
	rows, err := q.Order(s.readDB.UserItemCards.ID.Desc()).Offset((page - 1) * pageSize).Limit(pageSize).Find()
	if err != nil {
		return nil, 0, err
	}
	cidMap := make(map[int64]struct{})
	for _, r := range rows {
		if r.CardID > 0 {
			cidMap[r.CardID] = struct{}{}
		}
	}
	tpls := map[int64]*model.SystemItemCards{}
	if len(cidMap) > 0 {
		ids := make([]int64, 0, len(cidMap))
		for id := range cidMap {
			ids = append(ids, id)
		}
		list, err := s.readDB.SystemItemCards.WithContext(ctx).ReadDB().Where(s.readDB.SystemItemCards.ID.In(ids...)).Find()
		if err != nil {
			return nil, 0, err
		}
		for _, it := range list {
			tpls[it.ID] = it
		}
	}
	items = make([]*ItemCardWithTemplate, len(rows))
	for i, r := range rows {
		tpl := tpls[r.CardID]
		var name string
		var cardType, scopeType, effectType, stacking int32
		var remark string
		if tpl != nil {
			name = tpl.Name
			cardType = tpl.CardType
			scopeType = tpl.ScopeType
			effectType = tpl.EffectType
			stacking = tpl.StackingStrategy
			remark = tpl.Remark
		}
		items[i] = &ItemCardWithTemplate{
			UserItemCards:    r,
			Name:             name,
			CardType:         cardType,
			ScopeType:        scopeType,
			EffectType:       effectType,
			StackingStrategy: stacking,
			Remark:           remark,
			Count:            1, // Individual record
		}
	}
	return items, total, nil
}

func (s *service) ListUserItemCardsWithTemplateUsable(ctx context.Context, userID int64, page, pageSize int) (items []*ItemCardWithTemplate, total int64, err error) {
	q := s.readDB.UserItemCards.WithContext(ctx).ReadDB().Where(
		s.readDB.UserItemCards.UserID.Eq(userID),
		s.readDB.UserItemCards.Status.Eq(1),
	)
	total, err = q.Count()
	if err != nil {
		return nil, 0, err
	}
	if page <= 0 {
		page = 1
	}
	if pageSize <= 0 {
		pageSize = 20
	}
	if pageSize > 100 {
		pageSize = 100
	}
	rows, err := q.Order(s.readDB.UserItemCards.ID.Desc()).Offset((page - 1) * pageSize).Limit(pageSize).Find()
	if err != nil {
		return nil, 0, err
	}
	cidMap := make(map[int64]struct{})
	for _, r := range rows {
		if r.CardID > 0 {
			cidMap[r.CardID] = struct{}{}
		}
	}
	tpls := map[int64]*model.SystemItemCards{}
	if len(cidMap) > 0 {
		ids := make([]int64, 0, len(cidMap))
		for id := range cidMap {
			ids = append(ids, id)
		}
		list, err := s.readDB.SystemItemCards.WithContext(ctx).ReadDB().Where(s.readDB.SystemItemCards.ID.In(ids...)).Find()
		if err != nil {
			return nil, 0, err
		}
		for _, it := range list {
			tpls[it.ID] = it
		}
	}
	items = make([]*ItemCardWithTemplate, len(rows))
	for i, r := range rows {
		tpl := tpls[r.CardID]
		var name string
		var cardType, scopeType, effectType, stacking int32
		var remark string
		if tpl != nil {
			name = tpl.Name
			cardType = tpl.CardType
			scopeType = tpl.ScopeType
			effectType = tpl.EffectType
			stacking = tpl.StackingStrategy
			remark = tpl.Remark
		}
		items[i] = &ItemCardWithTemplate{
			UserItemCards:    r,
			Name:             name,
			CardType:         cardType,
			ScopeType:        scopeType,
			EffectType:       effectType,
			StackingStrategy: stacking,
			Remark:           remark,
			Count:            1,
		}
	}
	return items, total, nil
}

// ListUserItemCardsWithTemplateByStatus 按状态获取用户道具卡列表
func (s *service) ListUserItemCardsWithTemplateByStatus(ctx context.Context, userID int64, status int32, page, pageSize int) (items []*ItemCardWithTemplate, total int64, err error) {
	q := s.readDB.UserItemCards.WithContext(ctx).ReadDB().Where(
		s.readDB.UserItemCards.UserID.Eq(userID),
		s.readDB.UserItemCards.Status.Eq(status),
	)
	total, err = q.Count()
	if err != nil {
		return nil, 0, err
	}
	if page <= 0 {
		page = 1
	}
	if pageSize <= 0 {
		pageSize = 20
	}
	if pageSize > 100 {
		pageSize = 100
	}
	rows, err := q.Order(s.readDB.UserItemCards.ID.Desc()).Offset((page - 1) * pageSize).Limit(pageSize).Find()
	if err != nil {
		return nil, 0, err
	}
	cidMap := make(map[int64]struct{})
	for _, r := range rows {
		if r.CardID > 0 {
			cidMap[r.CardID] = struct{}{}
		}
	}
	tpls := map[int64]*model.SystemItemCards{}
	if len(cidMap) > 0 {
		ids := make([]int64, 0, len(cidMap))
		for id := range cidMap {
			ids = append(ids, id)
		}
		list, err := s.readDB.SystemItemCards.WithContext(ctx).ReadDB().Where(s.readDB.SystemItemCards.ID.In(ids...)).Find()
		if err != nil {
			return nil, 0, err
		}
		for _, it := range list {
			tpls[it.ID] = it
		}
	}

	// Data collection for batch fetching
	var usedActivityIDs []int64
	var usedIssueIDs []int64
	var usedDrawLogIDs []int64

	for _, r := range rows {
		if status == 2 { // ONLY for Used status
			if r.UsedActivityID > 0 {
				usedActivityIDs = append(usedActivityIDs, r.UsedActivityID)
			}
			if r.UsedIssueID > 0 {
				usedIssueIDs = append(usedIssueIDs, r.UsedIssueID)
			}
			if r.UsedDrawLogID > 0 {
				usedDrawLogIDs = append(usedDrawLogIDs, r.UsedDrawLogID)
			}
		}
	}

	// Maps for enrichment
	activityNameMap := make(map[int64]string)
	issueNumberMap := make(map[int64]string)
	rewardNameMap := make(map[int64]string)

	if len(usedActivityIDs) > 0 {
		var err error
		var acts []*model.Activities
		if acts, err = s.readDB.Activities.WithContext(ctx).ReadDB().Select(s.readDB.Activities.ID, s.readDB.Activities.Name).Where(s.readDB.Activities.ID.In(usedActivityIDs...)).Find(); err == nil {
			for _, a := range acts {
				activityNameMap[a.ID] = a.Name
			}
		}
	}

	if len(usedIssueIDs) > 0 {
		var err error
		var issues []*model.ActivityIssues
		if issues, err = s.readDB.ActivityIssues.WithContext(ctx).ReadDB().Select(s.readDB.ActivityIssues.ID, s.readDB.ActivityIssues.IssueNumber).Where(s.readDB.ActivityIssues.ID.In(usedIssueIDs...)).Find(); err == nil {
			for _, i := range issues {
				issueNumberMap[i.ID] = i.IssueNumber
			}
		}
	}

	if len(usedDrawLogIDs) > 0 {
		var err error
		var logs []*model.ActivityDrawLogs
		// join reward settings to get name
		if logs, err = s.readDB.ActivityDrawLogs.WithContext(ctx).ReadDB().Select(s.readDB.ActivityDrawLogs.ID, s.readDB.ActivityDrawLogs.RewardID).Where(s.readDB.ActivityDrawLogs.ID.In(usedDrawLogIDs...)).Find(); err == nil {
			var rewardIDs []int64
			logToRewardID := make(map[int64]int64)
			for _, l := range logs {
				if l.RewardID > 0 {
					rewardIDs = append(rewardIDs, l.RewardID)
					logToRewardID[l.ID] = l.RewardID
				}
			}

			if len(rewardIDs) > 0 {
				var rewards []*model.ActivityRewardSettings
				if rewards, err = s.readDB.ActivityRewardSettings.WithContext(ctx).ReadDB().Select(s.readDB.ActivityRewardSettings.ID, s.readDB.ActivityRewardSettings.ProductID).Where(s.readDB.ActivityRewardSettings.ID.In(rewardIDs...)).Find(); err == nil {
					// 批量获取商品信息，通过 ProductID 关联查询名称
					productIDs := make([]int64, 0, len(rewards))
					for _, r := range rewards {
						if r.ProductID > 0 {
							productIDs = append(productIDs, r.ProductID)
						}
					}
					productNameMap := make(map[int64]string)
					if len(productIDs) > 0 {
						if products, err := s.readDB.Products.WithContext(ctx).ReadDB().Select(s.readDB.Products.ID, s.readDB.Products.Name).Where(s.readDB.Products.ID.In(productIDs...)).Find(); err == nil {
							for _, p := range products {
								productNameMap[p.ID] = p.Name
							}
						}
					}
					rewardNameMapByID := make(map[int64]string)
					for _, r := range rewards {
						// 只使用商品名称
						if r.ProductID > 0 {
							if pn, ok := productNameMap[r.ProductID]; ok {
								rewardNameMapByID[r.ID] = pn
							}
						}
					}
					// Map log ID back to reward name
					for logID, rewardID := range logToRewardID {
						if name, ok := rewardNameMapByID[rewardID]; ok {
							rewardNameMap[logID] = name
						}
					}
				}
			}
		}
	}

	items = make([]*ItemCardWithTemplate, len(rows))
	for i, r := range rows {
		tpl := tpls[r.CardID]
		var name string
		var cardType, scopeType, effectType, stacking int32
		var remark string
		if tpl != nil {
			name = tpl.Name
			cardType = tpl.CardType
			scopeType = tpl.ScopeType
			effectType = tpl.EffectType
			stacking = tpl.StackingStrategy
			remark = tpl.Remark
		}
		item := &ItemCardWithTemplate{
			UserItemCards:    r,
			Name:             name,
			CardType:         cardType,
			ScopeType:        scopeType,
			EffectType:       effectType,
			StackingStrategy: stacking,
			Remark:           remark,
			Count:            1, // Individual record
		}

		// Fill enrichment data
		if r.UsedActivityID > 0 {
			item.UsedActivityName = activityNameMap[r.UsedActivityID]
		}
		if r.UsedIssueID > 0 {
			item.UsedIssueNumber = issueNumberMap[r.UsedIssueID]
		}
		if r.UsedDrawLogID > 0 {
			item.UsedRewardName = rewardNameMap[r.UsedDrawLogID]
		}

		items[i] = item
	}
	return items, total, nil
}
