package user

import (
	"context"
	"fmt"

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

// BatchRewardItem 批量发放的单个奖励项
type BatchRewardItem struct {
	ProductID  int64
	RewardID   *int64 // 可选，一番赏模式需要传入以扣减库存
	ActivityID int64
	Remark     string
}

// BatchGrantRewardsToOrder 批量发放奖励到订单（单事务处理）
// 相比循环调用 GrantRewardToOrder，此方法在单个事务内批量插入所有记录，大幅提升性能
func (s *service) BatchGrantRewardsToOrder(ctx context.Context, userID int64, orderID int64, items []BatchRewardItem) ([]int64, error) {
	if len(items) == 0 {
		return nil, nil
	}

	var inventoryIDs []int64

	err := s.writeDB.Transaction(func(tx *dao.Query) error {
		// 1. 验证订单
		order, err := tx.Orders.WithContext(ctx).Where(
			tx.Orders.ID.Eq(orderID),
			tx.Orders.UserID.Eq(userID),
		).First()
		if err != nil || order == nil {
			return fmt.Errorf("订单不存在或不属于该用户")
		}
		if order.Status != 2 {
			return fmt.Errorf("订单未支付或状态异常(status=%d)", order.Status)
		}

		// 2. 预加载所有需要的商品信息（避免循环内查询）
		productIDs := make([]int64, 0, len(items))
		for _, item := range items {
			productIDs = append(productIDs, item.ProductID)
		}
		// 去重
		productIDSet := make(map[int64]bool)
		uniqueProductIDs := make([]int64, 0)
		for _, pid := range productIDs {
			if !productIDSet[pid] {
				productIDSet[pid] = true
				uniqueProductIDs = append(uniqueProductIDs, pid)
			}
		}
		products, err := tx.Products.WithContext(ctx).Where(tx.Products.ID.In(uniqueProductIDs...)).Find()
		if err != nil {
			return fmt.Errorf("查询商品失败: %w", err)
		}
		productMap := make(map[int64]*model.Products)
		for _, p := range products {
			productMap[p.ID] = p
		}

		// 3. 批量创建订单项和库存记录
		var orderItems []*model.OrderItems
		var inventories []*model.UserInventory

		for _, item := range items {
			product := productMap[item.ProductID]
			if product == nil {
				continue // 跳过无效商品
			}

			orderItems = append(orderItems, &model.OrderItems{
				OrderID:       orderID,
				ProductID:     item.ProductID,
				Title:         product.Name,
				Quantity:      1,
				Price:         0,
				TotalAmount:   0,
				ProductImages: product.ImagesJSON,
				Status:        1,
			})

			inventories = append(inventories, &model.UserInventory{
				UserID:     userID,
				ProductID:  item.ProductID,
				OrderID:    orderID,
				ActivityID: item.ActivityID,
				RewardID: func() int64 {
					if item.RewardID != nil {
						return *item.RewardID
					}
					return 0
				}(),
				Status: 1,
				Remark: func() string {
					if item.Remark != "" {
						return item.Remark
					}
					return product.Name
				}(),
			})
		}

		// 4. 批量插入（一次数据库操作）
		if len(orderItems) > 0 {
			if err := tx.OrderItems.WithContext(ctx).CreateInBatches(orderItems, 100); err != nil {
				return fmt.Errorf("批量创建订单项失败: %w", err)
			}
		}
		if len(inventories) > 0 {
			if err := tx.UserInventory.WithContext(ctx).CreateInBatches(inventories, 100); err != nil {
				return fmt.Errorf("批量创建库存记录失败: %w", err)
			}
			for _, inv := range inventories {
				inventoryIDs = append(inventoryIDs, inv.ID)
			}
		}

		// 5. 处理一番赏库存扣减（按RewardID聚合后批量更新）
		rewardDeductMap := make(map[int64]int64)
		for _, item := range items {
			if item.RewardID != nil {
				rewardDeductMap[*item.RewardID]++
			}
		}
		for rewardID, count := range rewardDeductMap {
			result, err := tx.ActivityRewardSettings.WithContext(ctx).Where(
				tx.ActivityRewardSettings.ID.Eq(rewardID),
				tx.ActivityRewardSettings.Quantity.Gte(count),
			).UpdateSimple(tx.ActivityRewardSettings.Quantity.Add(-count))
			if err != nil {
				return fmt.Errorf("扣减奖品库存失败: %w", err)
			}
			if result.RowsAffected == 0 {
				return fmt.Errorf("奖品ID=%d库存不足", rewardID)
			}
		}

		return nil
	})

	if err != nil {
		return nil, err
	}

	return inventoryIDs, nil
}
