package user

import (
    "context"
    "errors"
    "time"

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

	"gorm.io/gorm/clause"
)

// ConsumePoints 扣减用户积分用于订单支付，按有效期优先扣减，返回扣减流水ID
func (s *service) ConsumePoints(ctx context.Context, userID int64, points int64, orderNo string) (int64, error) {
	if points <= 0 {
		return 0, nil
	}
	var ledgerID int64
	err := s.writeDB.Transaction(func(tx *dao.Query) error {
		rows, err := tx.UserPoints.WithContext(ctx).Clauses(clause.Locking{Strength: "UPDATE"}).Where(tx.UserPoints.UserID.Eq(userID)).Order(tx.UserPoints.ValidEnd.Asc()).Find()
		if err != nil {
			return err
		}
		remain := points
        now := time.Now()
        for _, r := range rows {
            if !r.ValidEnd.IsZero() && r.ValidEnd.Before(now) {
                continue
            }
            if remain <= 0 {
                break
            }
            use := r.Points
            if use > remain {
                use = remain
            }
            _, err := tx.UserPoints.WithContext(ctx).Where(tx.UserPoints.ID.Eq(r.ID)).Updates(map[string]any{"points": r.Points - use})
            if err != nil {
                return err
            }
            remain -= use
        }
        if remain > 0 {
            return errors.New("insufficient_points")
        }
        // 记录扣减流水（负数）
        led := &model.UserPointsLedger{UserID: userID, Action: "consume_order", Points: -points, RefTable: "orders", RefID: orderNo, Remark: "consume by lottery"}
        if err := tx.UserPointsLedger.WithContext(ctx).Create(led); err != nil {
            return err
        }
        ledgerID = led.ID
        return nil
    })
    return ledgerID, err
}

// RefundPoints 退款积分（退回扣减），返回退款流水ID
func (s *service) RefundPoints(ctx context.Context, userID int64, points int64, orderNo string, reason string) (int64, error) {
    var ledgerID int64
    err := s.writeDB.Transaction(func(tx *dao.Query) error {
		// 累加到默认积分条目
		existing, _ := tx.UserPoints.WithContext(ctx).Clauses(clause.Locking{Strength: "UPDATE"}).Where(tx.UserPoints.UserID.Eq(userID)).First()
		if existing == nil {
			if err := tx.UserPoints.WithContext(ctx).Omit(tx.UserPoints.ValidEnd).Create(&model.UserPoints{UserID: userID, Points: points}); err != nil {
				return err
			}
        } else {
            if _, err := tx.UserPoints.WithContext(ctx).Where(tx.UserPoints.ID.Eq(existing.ID)).Updates(map[string]any{"points": existing.Points + points}); err != nil {
                return err
            }
        }
        led := &model.UserPointsLedger{UserID: userID, Action: "refund_points", Points: points, RefTable: "orders", RefID: orderNo, Remark: reason}
        if err := tx.UserPointsLedger.WithContext(ctx).Create(led); err != nil {
            return err
        }
        ledgerID = led.ID
        return nil
    })
    return ledgerID, err
}
