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
			}

			// Get Rate
			ratePtsPerCent, _ := s.CentsToPoints(ctx, 1)
			if ratePtsPerCent <= 0 {
				ratePtsPerCent = 1
			}
			pointsToRefund := order.PointsAmount * ratePtsPerCent

			// 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. 更新订单状态
		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
}
