package user

import (
	"context"
	"errors"
	"time"

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

	"gorm.io/gorm/clause"
)

// CancelOrder 取消订单
func (s *service) CancelOrder(ctx context.Context, userID int64, orderID int64, reason string) (*model.Orders, error) {
	var updatedOrder *model.Orders
	err := s.writeDB.Transaction(func(tx *dao.Query) error {
		// 1. 查询订单
		order, err := tx.Orders.WithContext(ctx).Clauses(clause.Locking{Strength: "UPDATE"}).Where(tx.Orders.ID.Eq(orderID), tx.Orders.UserID.Eq(userID)).First()
		if err != nil {
			return err
		}
		if order == nil {
			return errors.New("order not found")
		}

		// 2. 校验状态
		if order.Status != 1 {
			return errors.New("order cannot be cancelled")
		}

		// 3. 退还积分
		if order.PointsAmount > 0 {
			refundReason := "cancel_order"
			if reason != "" {
				refundReason = refundReason + ":" + reason
			}

			// order.PointsAmount 已经是分单位，直接退还
			pointsToRefund := order.PointsAmount

			// Update User Points
			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: pointsToRefund}); 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 + pointsToRefund}); err != nil {
					return err
				}
			}
			// Log
			led := &model.UserPointsLedger{UserID: userID, Action: "refund_points", Points: pointsToRefund, RefTable: "orders", RefID: order.OrderNo, Remark: refundReason}
			if err := tx.UserPointsLedger.WithContext(ctx).Create(led); err != nil {
				return err
			}
		}

		// 4. 退还优惠券（恢复预扣的余额和状态）
		if order.CouponID > 0 {
			// 查询订单使用的优惠券及扣减金额
			type couponRow struct {
				AppliedAmount int64
				DiscountType  int32
			}
			var cr couponRow
			_ = tx.OrderCoupons.WithContext(ctx).UnderlyingDB().Raw(`
				SELECT oc.applied_amount AS applied_amount, sc.discount_type AS 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 = ?
			`, order.ID, order.CouponID).Scan(&cr)

			if cr.AppliedAmount > 0 {
				if cr.DiscountType == 1 { // 金额券：恢复余额
					res := tx.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, order.CouponID)

					if res.RowsAffected > 0 {
						// 记录退还流水
						_ = tx.UserCouponLedger.WithContext(ctx).Create(&model.UserCouponLedger{
							UserID:       userID,
							UserCouponID: order.CouponID,
							ChangeAmount: cr.AppliedAmount,
							BalanceAfter: 0, // 简化处理，后续可查询精确值
							OrderID:      order.ID,
							Action:       "refund",
							CreatedAt:    time.Now(),
						})
					}
				} else { // 满减/折扣券：恢复状态
					tx.UserCoupons.WithContext(ctx).UnderlyingDB().Exec(`
						UPDATE user_coupons 
						SET status = 1,
							used_order_id = NULL,
							used_at = NULL
						WHERE id = ? AND status = 4
					`, order.CouponID)
				}
			}
		}

		// 5. 更新订单状态
		updates := map[string]any{
			tx.Orders.Status.ColumnName().String():      3,
			tx.Orders.CancelledAt.ColumnName().String(): time.Now(),
		}
		if _, err := tx.Orders.WithContext(ctx).Where(tx.Orders.ID.Eq(order.ID)).Updates(updates); err != nil {
			return err
		}

		updatedOrder = order
		updatedOrder.Status = 3
		return nil
	})

	if err != nil {
		return nil, err
	}
	return updatedOrder, nil
}
