package user

import (
	"context"
	"fmt"
	"time"

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

	"gorm.io/gorm/clause"
)

// StartOrderTimeoutTask 启动订单超时清理任务（每分钟执行）
func (s *service) StartOrderTimeoutTask(ctx context.Context) {
	ticker := time.NewTicker(1 * time.Minute)
	defer ticker.Stop()

	for {
		select {
		case <-ctx.Done():
			return
		case <-ticker.C:
			s.cleanupExpiredOrders()
		}
	}
}

// cleanupExpiredOrders 清理超时未支付的订单
// 规则：待支付订单超过30分钟自动取消，并恢复已预扣的优惠券
func (s *service) cleanupExpiredOrders() {
	ctx := context.Background()
	cutoff := time.Now().Add(-30 * time.Minute)

	// 查找所有超时的待支付订单（排除一番赏订单，因为有专门的清理任务）
	var expiredOrders []struct {
		ID           int64
		UserID       int64
		CouponID     int64
		OrderNo      string
		PointsAmount int64
	}

	err := s.readDB.Orders.WithContext(ctx).UnderlyingDB().Raw(`
		SELECT id, user_id, coupon_id, order_no, points_amount
		FROM orders
		WHERE status = 1 AND created_at < ? AND source_type != 3
		LIMIT 100
	`, cutoff).Scan(&expiredOrders).Error

	if err != nil {
		fmt.Printf("OrderTimeoutTask: 查询超时订单失败: %v\n", err)
		return
	}

	for _, order := range expiredOrders {
		s.cancelExpiredOrder(ctx, order.ID, order.UserID, order.CouponID, order.PointsAmount)
	}

	if len(expiredOrders) > 0 {
		fmt.Printf("OrderTimeoutTask: 已处理 %d 个超时订单\n", len(expiredOrders))
	}
}

// cancelExpiredOrder 取消超时订单并恢复优惠券
func (s *service) cancelExpiredOrder(ctx context.Context, orderID int64, userID int64, couponID int64, pointsAmount int64) {
	// 1. 恢复优惠券
	if couponID > 0 {
		type couponRow struct {
			AppliedAmount int64
			DiscountType  int32
		}
		var cr couponRow
		s.readDB.OrderCoupons.WithContext(ctx).UnderlyingDB().Raw(`
			SELECT oc.applied_amount, sc.discount_type
			FROM order_coupons oc
			JOIN user_coupons uc ON uc.id = oc.user_coupon_id
			JOIN system_coupons sc ON sc.id = uc.coupon_id
			WHERE oc.order_id = ? AND oc.user_coupon_id = ?
		`, orderID, couponID).Scan(&cr)

		if cr.AppliedAmount > 0 {
			if cr.DiscountType == 1 {
				// 金额券：恢复余额
				// 此时 coupon 可能 status=1 (Active) 或 2 (Used/Exhausted)
				// 不需要 status=4 限制，因为下单时已直接扣减
				res := s.writeDB.UserCoupons.WithContext(ctx).UnderlyingDB().Exec(`
					UPDATE user_coupons 
					SET balance_amount = balance_amount + ?,
						status = 1,
						used_order_id = NULL,
						used_at = NULL
					WHERE id = ?
				`, cr.AppliedAmount, couponID)

				if res.RowsAffected > 0 {
					// 记录流水
					s.writeDB.UserCouponLedger.WithContext(ctx).Create(&model.UserCouponLedger{
						UserID:       userID,
						UserCouponID: couponID,
						ChangeAmount: cr.AppliedAmount,
						OrderID:      orderID,
						Action:       "timeout_refund",
						CreatedAt:    time.Now(),
					})
				}
			} else {
				// 满减/折扣券：恢复状态
				s.writeDB.UserCoupons.WithContext(ctx).UnderlyingDB().Exec(`
					UPDATE user_coupons 
					SET status = 1,
						used_order_id = NULL,
						used_at = NULL
					WHERE id = ? AND status = 4
				`, couponID)
			}
		}
	}

	// 2. 退还积分（如有）
	if pointsAmount > 0 {
		existing, _ := s.writeDB.UserPoints.WithContext(ctx).
			Clauses(clause.Locking{Strength: "UPDATE"}).
			Where(s.writeDB.UserPoints.UserID.Eq(userID)).First()

		if existing != nil {
			s.writeDB.UserPoints.WithContext(ctx).
				Where(s.writeDB.UserPoints.ID.Eq(existing.ID)).
				Updates(map[string]any{"points": existing.Points + pointsAmount})
		} else {
			s.writeDB.UserPoints.WithContext(ctx).
				Omit(s.writeDB.UserPoints.ValidEnd).
				Create(&model.UserPoints{UserID: userID, Points: pointsAmount})
		}

		s.writeDB.UserPointsLedger.WithContext(ctx).Create(&model.UserPointsLedger{
			UserID:   userID,
			Action:   "timeout_refund",
			Points:   pointsAmount,
			RefTable: "orders",
			RefID:    fmt.Sprintf("%d", orderID),
			Remark:   "order_timeout",
		})
	}

	// 3. 更新订单状态为已取消
	res := s.writeDB.Orders.WithContext(ctx).UnderlyingDB().Exec(`
		UPDATE orders SET status = 3, cancelled_at = NOW() WHERE id = ? AND status = 1
	`, orderID)

	if res.RowsAffected > 0 {
		fmt.Printf("OrderTimeoutTask: 订单 %d 已超时取消\n", orderID)
	}
}
