package order

import (
	"context"
	"crypto/sha256"
	"encoding/binary"
	"fmt"
	"sort"
	"strconv"
	"strings"
	"time"

	cardObservationApp "github.com/break/junhong_cmp_fiber/internal/application/cardobservation"
	walletapp "github.com/break/junhong_cmp_fiber/internal/application/wallet"
	packagedomain "github.com/break/junhong_cmp_fiber/internal/domain/package"
	"github.com/break/junhong_cmp_fiber/internal/model"
	"github.com/break/junhong_cmp_fiber/internal/model/dto"
	packagepkg "github.com/break/junhong_cmp_fiber/internal/service/package"
	"github.com/break/junhong_cmp_fiber/internal/service/packageprice"
	"github.com/break/junhong_cmp_fiber/internal/service/purchase_validation"
	"github.com/break/junhong_cmp_fiber/internal/store"
	"github.com/break/junhong_cmp_fiber/internal/store/postgres"
	"github.com/break/junhong_cmp_fiber/pkg/constants"
	"github.com/break/junhong_cmp_fiber/pkg/errors"
	"github.com/break/junhong_cmp_fiber/pkg/fuiou"
	"github.com/break/junhong_cmp_fiber/pkg/middleware"
	"github.com/break/junhong_cmp_fiber/pkg/payment"
	"github.com/break/junhong_cmp_fiber/pkg/queue"
	"github.com/break/junhong_cmp_fiber/pkg/wechat"
	"github.com/google/uuid"
	"github.com/redis/go-redis/v9"
	"go.uber.org/zap"
	"gorm.io/gorm"
	"gorm.io/gorm/clause"
)

// WechatConfigServiceInterface 支付配置服务接口
// 用于查询当前生效的支付配置
type WechatConfigServiceInterface interface {
	GetActiveConfig(ctx context.Context) (*model.WechatConfig, error)
}

type Service struct {
	db                         *gorm.DB
	redis                      *redis.Client
	orderStore                 *postgres.OrderStore
	orderItemStore             *postgres.OrderItemStore
	agentWalletStore           *postgres.AgentWalletStore
	assetWalletStore           *postgres.AssetWalletStore
	paymentStore               *postgres.PaymentStore
	purchaseValidationService  *purchase_validation.Service
	shopPackageAllocationStore *postgres.ShopPackageAllocationStore
	shopSeriesAllocationStore  *postgres.ShopSeriesAllocationStore
	iotCardStore               *postgres.IotCardStore
	deviceStore                *postgres.DeviceStore
	packageSeriesStore         *postgres.PackageSeriesStore
	packageUsageStore          *postgres.PackageUsageStore
	packageStore               *postgres.PackageStore
	wechatConfigService        WechatConfigServiceInterface
	wechatPayment              wechat.PaymentServiceInterface
	paymentLoader              payment.PaymentConfigLoader
	queueClient                *queue.Client
	logger                     *zap.Logger
	resumeCallback             packagepkg.ResumeCallback
	assetIdentifierStore       *postgres.AssetIdentifierStore
	personalCustomerStore      *postgres.PersonalCustomerStore
	personalCustomerPhoneStore *postgres.PersonalCustomerPhoneStore
	agentWalletDebit           *walletapp.DebitService
	agentWalletReservation     *walletapp.ReservationService
	observationSeriesEvents    cardObservationApp.SeriesEventWriter
}

// SetObservationSeriesEventWriter 注入购包成功观测序列 Outbox Writer。
func (s *Service) SetObservationSeriesEventWriter(writer cardObservationApp.SeriesEventWriter) {
	s.observationSeriesEvents = writer
}

// SetAgentWalletDebitService 注入代理主钱包统一扣款用例。
func (s *Service) SetAgentWalletDebitService(service *walletapp.DebitService) {
	s.agentWalletDebit = service
}

// SetAgentWalletReservationService 注入代理主钱包统一预占用例。
func (s *Service) SetAgentWalletReservationService(service *walletapp.ReservationService) {
	s.agentWalletReservation = service
}

func New(
	db *gorm.DB,
	redisClient *redis.Client,
	orderStore *postgres.OrderStore,
	orderItemStore *postgres.OrderItemStore,
	agentWalletStore *postgres.AgentWalletStore,
	assetWalletStore *postgres.AssetWalletStore,
	paymentStore *postgres.PaymentStore,
	purchaseValidationService *purchase_validation.Service,
	shopPackageAllocationStore *postgres.ShopPackageAllocationStore,
	shopSeriesAllocationStore *postgres.ShopSeriesAllocationStore,
	iotCardStore *postgres.IotCardStore,
	deviceStore *postgres.DeviceStore,
	packageSeriesStore *postgres.PackageSeriesStore,
	packageUsageStore *postgres.PackageUsageStore,
	packageStore *postgres.PackageStore,
	wechatConfigService WechatConfigServiceInterface,
	wechatPayment wechat.PaymentServiceInterface,
	paymentLoader payment.PaymentConfigLoader,
	queueClient *queue.Client,
	logger *zap.Logger,
	assetIdentifierStore *postgres.AssetIdentifierStore,
	personalCustomerStore *postgres.PersonalCustomerStore,
	personalCustomerPhoneStore *postgres.PersonalCustomerPhoneStore,
) *Service {
	return &Service{
		db:                         db,
		redis:                      redisClient,
		orderStore:                 orderStore,
		orderItemStore:             orderItemStore,
		agentWalletStore:           agentWalletStore,
		assetWalletStore:           assetWalletStore,
		paymentStore:               paymentStore,
		purchaseValidationService:  purchaseValidationService,
		shopPackageAllocationStore: shopPackageAllocationStore,
		shopSeriesAllocationStore:  shopSeriesAllocationStore,
		iotCardStore:               iotCardStore,
		deviceStore:                deviceStore,
		packageSeriesStore:         packageSeriesStore,
		packageUsageStore:          packageUsageStore,
		packageStore:               packageStore,
		wechatConfigService:        wechatConfigService,
		wechatPayment:              wechatPayment,
		paymentLoader:              paymentLoader,
		queueClient:                queueClient,
		logger:                     logger,
		assetIdentifierStore:       assetIdentifierStore,
		personalCustomerStore:      personalCustomerStore,
		personalCustomerPhoneStore: personalCustomerPhoneStore,
	}
}

// SetResumeCallback 设置复机回调，支付成功激活套餐后触发自动复机
func (s *Service) SetResumeCallback(callback packagepkg.ResumeCallback) {
	s.resumeCallback = callback
}

// CreateAdminOrder 后台订单创建（仅支持 wallet/offline，立即扣款或激活）
// 与 CreateH5Order 的核心区别：后台订单不创建待支付状态，wallet 立即扣款，offline 立即激活
// POST /api/admin/orders
func (s *Service) CreateAdminOrder(ctx context.Context, req *dto.CreateAdminOrderRequest, buyerType string, buyerID uint) (*dto.OrderResponse, error) {
	resolvedCard, resolvedDevice, resolveErr := s.resolveAssetByIdentifier(ctx, req.Identifier)
	if resolveErr != nil {
		return nil, resolveErr
	}

	var orderType string
	var iotCardID *uint
	var deviceID *uint
	var resourceShopID *uint
	if resolvedCard != nil {
		orderType = model.OrderTypeSingleCard
		iotCardID = &resolvedCard.ID
		resourceShopID = resolvedCard.ShopID
	} else {
		orderType = model.OrderTypeDevice
		deviceID = &resolvedDevice.ID
		resourceShopID = resolvedDevice.ShopID
	}

	var validationResult *purchase_validation.PurchaseValidationResult
	var err error
	operatorUserType := middleware.GetUserTypeFromContext(ctx)
	validationCtx := ctx
	if req.PaymentMethod == model.PaymentMethodOffline && (operatorUserType == constants.UserTypeSuperAdmin || operatorUserType == constants.UserTypePlatform) {
		validationCtx = purchase_validation.WithAllowGiftPackages(ctx)
	}

	if req.PaymentMethod == model.PaymentMethodOffline {
		if resolvedCard != nil {
			validationResult, err = s.purchaseValidationService.ValidateAdminOfflineCardPurchase(validationCtx, resolvedCard.ID, req.PackageIDs)
		} else {
			validationResult, err = s.purchaseValidationService.ValidateAdminOfflineDevicePurchase(validationCtx, resolvedDevice.ID, req.PackageIDs)
		}
	} else {
		if resolvedCard != nil {
			validationResult, err = s.purchaseValidationService.ValidateCardPurchase(validationCtx, resolvedCard.ID, req.PackageIDs)
		} else {
			validationResult, err = s.purchaseValidationService.ValidateDevicePurchase(validationCtx, resolvedDevice.ID, req.PackageIDs)
		}
	}

	if err != nil {
		return nil, rewriteAdminAgentPackageOffShelfError(err, resourceShopID, req.PaymentMethod != model.PaymentMethodOffline)
	}

	if err := validatePackageTypeMixFromPackages(validationResult.Packages); err != nil {
		return nil, err
	}
	containsGift := packageprice.ContainsGiftPackage(validationResult.Packages)
	if containsGift {
		if operatorUserType != constants.UserTypeSuperAdmin && operatorUserType != constants.UserTypePlatform {
			return nil, errors.New(errors.CodeForbidden, "仅平台侧可发放赠送套餐")
		}
		if req.PaymentMethod != model.PaymentMethodOffline {
			return nil, errors.New(errors.CodeInvalidParam, "赠送套餐仅支持后台线下发放")
		}
		if err := packageprice.ValidateGiftAdminOrder(validationResult.Packages); err != nil {
			return nil, err
		}
	}
	if req.PaymentMethod == model.PaymentMethodOffline && len(req.PaymentVoucherKey) == 0 {
		return nil, errors.New(errors.CodeInvalidParam, "线下支付必须上传支付凭证")
	}

	carrierType, carrierID := resolveAdminCarrierInfoFromVars(orderType, iotCardID, deviceID)
	existingOrderID, lockToken, err := s.checkOrderIdempotency(ctx, buyerType, buyerID, orderType, carrierType, carrierID, req.PackageIDs)
	lockKey := constants.RedisOrderCreateLockKey(carrierType, carrierID)
	if lockToken != "" {
		defer s.releaseOrderCreateLock(ctx, lockKey, lockToken)
	}
	if err != nil {
		return nil, err
	}
	if existingOrderID > 0 {
		return s.Get(ctx, existingOrderID)
	}

	// offline 订单不检查强充：平台直接操作，不涉及消费者支付门槛，不产生一次性佣金触发条件
	if req.PaymentMethod != model.PaymentMethodOffline {
		forceRechargeCheck := s.checkForceRechargeRequirement(ctx, validationResult)
		if forceRechargeCheck.NeedForceRecharge && validationResult.TotalPrice < forceRechargeCheck.ForceRechargeAmount {
			return nil, errors.New(errors.CodeForceRechargeRequired, "首次购买需满足最低充值要求")
		}
	}

	userID := middleware.GetUserIDFromContext(ctx)
	operatorAccountID, operatorAccountType, operatorAccountName := s.buildAccountOperatorSnapshot(ctx, userID, operatorUserType)

	// 提取资源所属店铺ID
	var seriesID *uint
	if validationResult.Card != nil {
		seriesID = validationResult.Card.SeriesID
	} else if validationResult.Device != nil {
		seriesID = validationResult.Device.SeriesID
	}

	// 先按零售价构建明细价格快照，后续在代购/成本价场景覆盖
	// offline 场景先使用平台零售价，避免在平台代购场景下提前依赖代理分配记录
	sellerShopIDValue := uint(0)
	if req.PaymentMethod != model.PaymentMethodOffline && resourceShopID != nil {
		sellerShopIDValue = *resourceShopID
	}
	itemUnitPriceMap, retailTotalAmount, err := s.buildRetailPriceMap(ctx, validationResult.Packages, sellerShopIDValue)
	if err != nil {
		return nil, rewriteAdminAgentPackageOffShelfError(err, resourceShopID, sellerShopIDValue > 0)
	}

	// 初始化订单字段
	orderBuyerType := buyerType
	orderBuyerID := buyerID
	totalAmount := retailTotalAmount
	paymentMethod := req.PaymentMethod
	paymentStatus := model.PaymentStatusPaid
	var paidAt *time.Time
	now := time.Now()
	isPurchaseOnBehalf := false
	var operatorID *uint
	operatorType := ""
	var actualPaidAmount *int64
	purchaseRole := ""
	var sellerShopID *uint = resourceShopID
	var sellerCostPrice int64
	var itemCostPriceMap map[uint]int64 // 各套餐成本单价映射，用于 OrderItem.CostPrice 字段

	// 根据支付方式分别处理
	if req.PaymentMethod == model.PaymentMethodOffline {
		// ==== 场景 1：offline（线下支付）====
		if containsGift {
			orderBuyerType = model.BuyerTypePersonal
			orderBuyerID = 0
			paymentMethod = model.PaymentMethodOffline
			paymentStatus = model.PaymentStatusPaid
			paidAt = &now
			isPurchaseOnBehalf = false
			sellerShopID = nil
			sellerCostPrice = 0
			operatorID = nil
			operatorType = constants.OwnerTypePlatform
			actualPaidAmountVal := int64(0)
			actualPaidAmount = &actualPaidAmountVal
			purchaseRole = model.PurchaseRoleSelfPurchase
		} else {
			isPlatformOwned := resourceShopID == nil || *resourceShopID == 0

			if isPlatformOwned {
				// ==== 子场景 1.1：平台自营（资源未分配给代理商）====
				// 平台直接销售给终端用户，无代理商参与，使用零售价，无需查询分配配置
				orderBuyerType = model.BuyerTypePersonal
				orderBuyerID = 0
				paymentMethod = model.PaymentMethodOffline
				paymentStatus = model.PaymentStatusPaid
				paidAt = &now
				isPurchaseOnBehalf = false
				sellerCostPrice = 0
				operatorID = nil
				operatorType = constants.OwnerTypePlatform
				purchaseRole = model.PurchaseRoleSelfPurchase
				actualPaidAmount = nil
			} else {
				// ==== 子场景 1.2：平台代购（资源属于代理商，平台代为购买）====
				purchaseBuyerID, buyerCostPriceMap, buyerTotalCost, purchasePaidAt, err := s.resolvePurchaseOnBehalfInfo(ctx, validationResult)
				if err != nil {
					return nil, err
				}
				orderBuyerType = model.BuyerTypeAgent
				orderBuyerID = purchaseBuyerID
				itemCostPriceMap = buyerCostPriceMap
				paymentMethod = model.PaymentMethodOffline
				paymentStatus = model.PaymentStatusPaid
				paidAt = purchasePaidAt
				isPurchaseOnBehalf = true
				sellerCostPrice = buyerTotalCost

				// 设置操作者信息（平台代购）
				operatorID = nil
				operatorType = constants.OwnerTypePlatform
				purchaseRole = model.PurchaseRolePurchasedByPlatform
				actualPaidAmount = &buyerTotalCost
			}
		}

	} else if req.PaymentMethod == model.PaymentMethodWallet {
		// ==== 场景 2：代理钱包支付（wallet）====
		if resourceShopID == nil || *resourceShopID == 0 {
			return nil, errors.New(errors.CodeInvalidParam, "资源未分配给代理商，无法使用代理钱包支付")
		}

		if buyerType == model.BuyerTypeAgent {
			operatorShopID := buyerID

			if *resourceShopID == operatorShopID {
				// ==== 子场景 2.1：代理自购 ====
				operatorCostPriceMap, operatorTotalCost, err := s.buildCostPriceMap(ctx, validationResult.Packages, operatorShopID)
				if err != nil {
					return nil, err
				}

				orderBuyerType = model.BuyerTypeAgent
				orderBuyerID = operatorShopID
				itemCostPriceMap = operatorCostPriceMap
				paymentMethod = model.PaymentMethodWallet
				paymentStatus = model.PaymentStatusPaid
				paidAt = &now
				isPurchaseOnBehalf = false

				operatorID = &operatorShopID
				operatorType = "agent"
				actualPaidAmountVal := operatorTotalCost
				actualPaidAmount = &actualPaidAmountVal
				purchaseRole = model.PurchaseRoleSelfPurchase
				sellerCostPrice = operatorTotalCost

			} else {
				// ==== 子场景 2.2：代理代购（给下级购买）====
				// 获取买家成本价（买家的价格映射用于 CostPrice 快照，总价不再使用）
				buyerCostPriceMap, _, err := s.buildCostPriceMap(ctx, validationResult.Packages, *resourceShopID)
				if err != nil {
					return nil, err
				}

				// 获取操作者成本价（操作方实际扣款金额和佣金基准）
				_, operatorTotalCost, err := s.buildCostPriceMap(ctx, validationResult.Packages, operatorShopID)
				if err != nil {
					return nil, err
				}

				orderBuyerType = model.BuyerTypeAgent
				orderBuyerID = *resourceShopID
				itemCostPriceMap = buyerCostPriceMap
				paymentMethod = model.PaymentMethodWallet
				paymentStatus = model.PaymentStatusPaid
				paidAt = &now
				isPurchaseOnBehalf = true

				operatorID = &operatorShopID
				operatorType = "agent"
				actualPaidAmountVal := operatorTotalCost
				actualPaidAmount = &actualPaidAmountVal
				purchaseRole = model.PurchaseRolePurchaseForSubordinate
				// 代理代购下级时，佣金差额基准应是操作方（代理自己）的成本价，而非下级的成本价
				sellerCostPrice = operatorTotalCost
			}
		} else {
			// ==== 子场景 2.3：平台/超管代扣目标代理钱包 ====
			targetShopID := *resourceShopID
			targetCostPriceMap, targetTotalCost, err := s.buildCostPriceMap(ctx, validationResult.Packages, targetShopID)
			if err != nil {
				return nil, err
			}

			orderBuyerType = model.BuyerTypeAgent
			orderBuyerID = targetShopID
			itemCostPriceMap = targetCostPriceMap
			paymentMethod = model.PaymentMethodWallet
			paymentStatus = model.PaymentStatusPaid
			paidAt = &now
			isPurchaseOnBehalf = false

			operatorID = nil
			operatorType = constants.OwnerTypePlatform
			actualPaidAmountVal := targetTotalCost
			actualPaidAmount = &actualPaidAmountVal
			purchaseRole = model.PurchaseRoleSelfPurchase
			sellerCostPrice = targetTotalCost
		}
	} else {
		// 兜底检查：后台不支持其他支付方式（DTO 验证已拒绝，此为防御性编程）
		return nil, errors.New(errors.CodeInvalidParam, "后台仅支持钱包支付或线下支付")
	}

	if paymentStatus == model.PaymentStatusPaid && actualPaidAmount == nil {
		actualPaidAmountSnapshot := totalAmount
		actualPaidAmount = &actualPaidAmountSnapshot
	}

	// 查询当前生效的支付配置
	var paymentConfigID *uint
	if req.PaymentMethod == model.PaymentMethodWechat || req.PaymentMethod == model.PaymentMethodAlipay {
		activeConfig, err := s.wechatConfigService.GetActiveConfig(ctx)
		if err != nil {
			s.logger.Warn("查询生效支付配置失败", zap.Error(err))
		}
		if activeConfig != nil {
			paymentConfigID = &activeConfig.ID
		}
	}

	// 从资产获取当前 generation（用于订单快照）
	var assetGeneration int
	if validationResult.Card != nil {
		assetGeneration = validationResult.Card.Generation
	} else if validationResult.Device != nil {
		assetGeneration = validationResult.Device.Generation
	}
	if assetGeneration == 0 {
		assetGeneration = 1
	}

	order := &model.Order{
		BaseModel: model.BaseModel{
			Creator: userID,
			Updater: userID,
		},
		OrderNo:                 s.orderStore.GenerateOrderNo(),
		OrderType:               orderType,
		Source:                  constants.OrderSourceAdmin,
		Generation:              assetGeneration,
		BuyerType:               orderBuyerType,
		BuyerID:                 orderBuyerID,
		IotCardID:               iotCardID,
		DeviceID:                deviceID,
		AssetIdentifier:         req.Identifier,
		TotalAmount:             totalAmount,
		PaymentMethod:           paymentMethod,
		PaymentStatus:           paymentStatus,
		PaidAt:                  paidAt,
		CommissionStatus:        model.CommissionStatusPending,
		CommissionConfigVersion: 0,
		SeriesID:                seriesID,
		SellerShopID:            sellerShopID,
		SellerCostPrice:         sellerCostPrice,
		IsPurchaseOnBehalf:      isPurchaseOnBehalf,
		OperatorAccountID:       operatorAccountID,
		OperatorAccountType:     operatorAccountType,
		OperatorAccountName:     operatorAccountName,
		OperatorID:              operatorID,
		OperatorType:            operatorType,
		ActualPaidAmount:        actualPaidAmount,
		PurchaseRole:            purchaseRole,
		PaymentConfigID:         paymentConfigID,
	}

	// 线下支付订单写入支付凭证 file_key 列表
	if req.PaymentMethod == model.PaymentMethodOffline {
		order.PaymentVoucherKey = model.StringJSONBArray(req.PaymentVoucherKey)
	}

	if orderBuyerType == model.BuyerTypePersonal {
		order.BuyerPhone, order.BuyerNickname = s.fetchBuyerSnapshot(ctx, orderBuyerID)
	}

	items := s.buildOrderItems(userID, validationResult.Packages, itemUnitPriceMap, itemCostPriceMap)

	idempotencyKey := buildOrderIdempotencyKey(buyerType, buyerID, orderType, carrierType, carrierID, req.PackageIDs)

	// 根据支付方式选择创建订单的方式
	if req.PaymentMethod == model.PaymentMethodOffline {
		// 平台代购：创建订单并立即激活套餐
		if err := s.createOrderWithActivation(ctx, order, items); err != nil {
			return nil, err
		}
		if !containsGift {
			s.enqueueCommissionCalculation(ctx, order.ID)
		}
		s.markOrderCreated(ctx, idempotencyKey, order.ID)
		return s.buildOrderResponse(ctx, order, items), nil

	} else if req.PaymentMethod == model.PaymentMethodWallet {
		// 钱包支付：创建订单、扣款、激活套餐（在事务中完成）
		operatorShopID := orderBuyerID
		if operatorID != nil {
			operatorShopID = *operatorID
		}
		buyerShopID := orderBuyerID
		order.IdempotencyKey = orderIdempotencyDigest(idempotencyKey)

		existingOrderID, err := s.createOrderWithWalletPayment(ctx, order, items, operatorShopID, buyerShopID)
		if err != nil {
			return nil, err
		}
		if existingOrderID > 0 {
			s.markOrderCreated(ctx, idempotencyKey, existingOrderID)
			return s.Get(ctx, existingOrderID)
		}
		s.markOrderCreated(ctx, idempotencyKey, order.ID)
		return s.buildOrderResponse(ctx, order, items), nil

	} else {
		// 不应该到这里（DTO 验证已拒绝其他支付方式）
		return nil, errors.New(errors.CodeInvalidParam, "后台仅支持钱包支付或线下支付")
	}
}

func rewriteAdminAgentPackageOffShelfError(err error, resourceShopID *uint, shouldRewrite bool) error {
	if err == nil || !shouldRewrite || resourceShopID == nil || *resourceShopID == 0 {
		return err
	}

	appErr, ok := err.(*errors.AppError)
	if !ok {
		return err
	}

	if appErr.Code == errors.CodeInvalidParam && appErr.Message == "套餐已下架" {
		return errors.New(errors.CodeInvalidParam, "该代理已经下架该套餐,让代理上架该套餐后购买")
	}

	return err
}

// CreateH5Order H5 端订单创建（支持 wallet/wechat/alipay，支持待支付状态）
// 保留原 Create() 方法的完整逻辑，H5 端行为不变
// POST /api/h5/orders
func (s *Service) CreateH5Order(ctx context.Context, req *dto.CreateOrderRequest, buyerType string, buyerID uint) (*dto.OrderResponse, error) {
	var validationResult *purchase_validation.PurchaseValidationResult
	var err error

	if req.OrderType == model.OrderTypeSingleCard {
		if req.IotCardID == nil {
			return nil, errors.New(errors.CodeInvalidParam, "单卡购买必须指定IoT卡ID")
		}
		validationResult, err = s.purchaseValidationService.ValidateCardPurchase(ctx, *req.IotCardID, req.PackageIDs)
	} else if req.OrderType == model.OrderTypeDevice {
		if req.DeviceID == nil {
			return nil, errors.New(errors.CodeInvalidParam, "设备购买必须指定设备ID")
		}
		validationResult, err = s.purchaseValidationService.ValidateDevicePurchase(ctx, *req.DeviceID, req.PackageIDs)
	} else {
		return nil, errors.New(errors.CodeInvalidParam, "无效的订单类型")
	}

	if err != nil {
		return nil, err
	}

	// 下单阶段校验混买限制：禁止同一订单同时包含正式套餐和加油包
	if err := validatePackageTypeMixFromPackages(validationResult.Packages); err != nil {
		return nil, err
	}

	// 幂等性检查：防止同一买家对同一载体短时间内重复下单
	carrierType, carrierID := resolveCarrierInfo(req)
	existingOrderID, lockToken, err := s.checkOrderIdempotency(ctx, buyerType, buyerID, req.OrderType, carrierType, carrierID, req.PackageIDs)
	lockKey := constants.RedisOrderCreateLockKey(carrierType, carrierID)
	if lockToken != "" {
		defer s.releaseOrderCreateLock(ctx, lockKey, lockToken)
	}
	if err != nil {
		return nil, err
	}
	if existingOrderID > 0 {
		return s.Get(ctx, existingOrderID)
	}

	forceRechargeCheck := s.checkForceRechargeRequirement(ctx, validationResult)
	if forceRechargeCheck.NeedForceRecharge && validationResult.TotalPrice < forceRechargeCheck.ForceRechargeAmount {
		return nil, errors.New(errors.CodeForceRechargeRequired, "首次购买需满足最低充值要求")
	}

	userID := middleware.GetUserIDFromContext(ctx)
	operatorUserType := middleware.GetUserTypeFromContext(ctx)
	operatorAccountID, operatorAccountType, operatorAccountName := s.buildAccountOperatorSnapshot(ctx, userID, operatorUserType)

	// 提取资源所属店铺ID
	var resourceShopID *uint
	var seriesID *uint
	if validationResult.Card != nil {
		resourceShopID = validationResult.Card.ShopID
		seriesID = validationResult.Card.SeriesID
	} else if validationResult.Device != nil {
		resourceShopID = validationResult.Device.ShopID
		seriesID = validationResult.Device.SeriesID
	}

	// 先按零售价构建明细价格快照，后续在代购/成本价场景覆盖
	sellerShopIDValue := uint(0)
	if resourceShopID != nil {
		sellerShopIDValue = *resourceShopID
	}
	itemUnitPriceMap, retailTotalAmount, err := s.buildRetailPriceMap(ctx, validationResult.Packages, sellerShopIDValue)
	if err != nil {
		return nil, err
	}

	// 初始化订单字段
	orderBuyerType := buyerType
	orderBuyerID := buyerID
	totalAmount := retailTotalAmount
	paymentMethod := req.PaymentMethod
	paymentStatus := model.PaymentStatusPending
	var paidAt *time.Time
	now := time.Now()
	isPurchaseOnBehalf := false
	var operatorID *uint
	operatorType := ""
	var actualPaidAmount *int64
	purchaseRole := ""
	var sellerShopID *uint = resourceShopID
	var sellerCostPrice int64
	var expiresAt *time.Time            // 待支付订单设置过期时间，立即支付的订单为 nil
	var itemCostPriceMap map[uint]int64 // 各套餐成本单价映射，用于 OrderItem.CostPrice 字段

	// 场景判断：offline（平台代购）、wallet（代理钱包支付）、其他（待支付）
	if req.PaymentMethod == model.PaymentMethodOffline {
		// ==== 场景 1：平台代购（offline）====
		purchaseBuyerID, buyerCostPriceMap, buyerTotalCost, purchasePaidAt, err := s.resolvePurchaseOnBehalfInfo(ctx, validationResult)
		if err != nil {
			return nil, err
		}
		orderBuyerType = model.BuyerTypeAgent
		orderBuyerID = purchaseBuyerID
		itemCostPriceMap = buyerCostPriceMap
		paymentMethod = model.PaymentMethodOffline
		paymentStatus = model.PaymentStatusPaid
		paidAt = purchasePaidAt
		isPurchaseOnBehalf = true
		sellerCostPrice = buyerTotalCost

		// 设置操作者信息（平台代购）
		operatorID = nil
		operatorType = constants.OwnerTypePlatform
		purchaseRole = model.PurchaseRolePurchasedByPlatform
		actualPaidAmount = &buyerTotalCost

	} else if req.PaymentMethod == model.PaymentMethodWallet {
		// ==== 场景 2：代理钱包支付（wallet）====
		// 只有代理账号可以使用钱包支付
		if buyerType != model.BuyerTypeAgent {
			return nil, errors.New(errors.CodeInvalidParam, "只有代理账号可以使用钱包支付")
		}
		operatorShopID := buyerID

		// 判断资源是否属于操作者
		if resourceShopID == nil {
			return nil, errors.New(errors.CodeInternalError, "资源店铺ID为空")
		}

		if *resourceShopID == operatorShopID {
			// ==== 子场景 2.1：代理自购 ====
			operatorCostPriceMap, operatorTotalCost, err := s.buildCostPriceMap(ctx, validationResult.Packages, operatorShopID)
			if err != nil {
				return nil, err
			}

			orderBuyerType = model.BuyerTypeAgent
			orderBuyerID = operatorShopID
			itemCostPriceMap = operatorCostPriceMap
			paymentMethod = model.PaymentMethodWallet
			paymentStatus = model.PaymentStatusPaid
			paidAt = &now
			isPurchaseOnBehalf = false

			operatorID = &operatorShopID
			operatorType = "agent"
			actualPaidAmountVal := operatorTotalCost
			actualPaidAmount = &actualPaidAmountVal
			purchaseRole = model.PurchaseRoleSelfPurchase
			sellerCostPrice = operatorTotalCost

		} else {
			// ==== 子场景 2.2：代理代购（给下级购买）====
			// 获取买家成本价（价格映射用于 CostPrice 快照，总价不再使用）
			buyerCostPriceMap, _, err := s.buildCostPriceMap(ctx, validationResult.Packages, *resourceShopID)
			if err != nil {
				return nil, err
			}

			// 获取操作者成本价（操作方实际扣款金额和佣金基准）
			_, operatorTotalCost, err := s.buildCostPriceMap(ctx, validationResult.Packages, operatorShopID)
			if err != nil {
				return nil, err
			}

			orderBuyerType = model.BuyerTypeAgent
			orderBuyerID = *resourceShopID
			itemCostPriceMap = buyerCostPriceMap
			paymentMethod = model.PaymentMethodWallet
			paymentStatus = model.PaymentStatusPaid
			paidAt = &now
			isPurchaseOnBehalf = true

			operatorID = &operatorShopID
			operatorType = "agent"
			actualPaidAmountVal := operatorTotalCost
			actualPaidAmount = &actualPaidAmountVal
			purchaseRole = model.PurchaseRolePurchaseForSubordinate
			// 代理代购下级时，佣金差额基准应是操作方（代理自己）的成本价，而非下级的成本价
			sellerCostPrice = operatorTotalCost
		}
	}

	if paymentStatus == model.PaymentStatusPaid && actualPaidAmount == nil {
		actualPaidAmountSnapshot := totalAmount
		actualPaidAmount = &actualPaidAmountSnapshot
	}

	// 查询当前生效的支付配置
	var h5PaymentConfigID *uint
	if req.PaymentMethod == model.PaymentMethodWechat || req.PaymentMethod == model.PaymentMethodAlipay {
		activeConfig, err := s.wechatConfigService.GetActiveConfig(ctx)
		if err != nil {
			s.logger.Warn("查询生效支付配置失败", zap.Error(err))
		}
		if activeConfig != nil {
			h5PaymentConfigID = &activeConfig.ID
		}
	}

	order := &model.Order{
		BaseModel: model.BaseModel{
			Creator: userID,
			Updater: userID,
		},
		OrderNo:                 s.orderStore.GenerateOrderNo(),
		OrderType:               req.OrderType,
		BuyerType:               orderBuyerType,
		BuyerID:                 orderBuyerID,
		IotCardID:               req.IotCardID,
		DeviceID:                req.DeviceID,
		AssetIdentifier:         buildOrderAssetIdentifier(validationResult),
		TotalAmount:             totalAmount,
		PaymentMethod:           paymentMethod,
		PaymentStatus:           paymentStatus,
		PaidAt:                  paidAt,
		CommissionStatus:        model.CommissionStatusPending,
		CommissionConfigVersion: 0,
		SeriesID:                seriesID,
		SellerShopID:            sellerShopID,
		SellerCostPrice:         sellerCostPrice,
		IsPurchaseOnBehalf:      isPurchaseOnBehalf,
		OperatorAccountID:       operatorAccountID,
		OperatorAccountType:     operatorAccountType,
		OperatorAccountName:     operatorAccountName,
		OperatorID:              operatorID,
		OperatorType:            operatorType,
		ActualPaidAmount:        actualPaidAmount,
		PurchaseRole:            purchaseRole,
		ExpiresAt:               expiresAt,
		PaymentConfigID:         h5PaymentConfigID,
	}

	items := s.buildOrderItems(userID, validationResult.Packages, itemUnitPriceMap, itemCostPriceMap)

	idempotencyKey := buildOrderIdempotencyKey(buyerType, buyerID, req.OrderType, carrierType, carrierID, req.PackageIDs)

	// 根据支付方式选择创建订单的方式
	if req.PaymentMethod == model.PaymentMethodOffline {
		// 平台代购：创建订单并立即激活套餐
		if err := s.createOrderWithActivation(ctx, order, items); err != nil {
			return nil, err
		}
		s.enqueueCommissionCalculation(ctx, order.ID)
		s.markOrderCreated(ctx, idempotencyKey, order.ID)
		return s.buildOrderResponse(ctx, order, items), nil

	} else if req.PaymentMethod == model.PaymentMethodWallet {
		// 钱包支付：创建订单、扣款、激活套餐（在事务中完成）
		if operatorID == nil {
			return nil, errors.New(errors.CodeInternalError, "钱包支付场景下 operatorID 不能为空")
		}
		operatorShopID := *operatorID
		buyerShopID := orderBuyerID
		order.IdempotencyKey = orderIdempotencyDigest(idempotencyKey)

		existingOrderID, err := s.createOrderWithWalletPayment(ctx, order, items, operatorShopID, buyerShopID)
		if err != nil {
			return nil, err
		}
		if existingOrderID > 0 {
			s.markOrderCreated(ctx, idempotencyKey, existingOrderID)
			return s.Get(ctx, existingOrderID)
		}
		s.markOrderCreated(ctx, idempotencyKey, order.ID)
		return s.buildOrderResponse(ctx, order, items), nil

	} else {
		// 其他支付方式：创建待支付订单（H5 端支持 wechat/alipay）
		// 待支付订单设置过期时间，超过 30 分钟未支付则自动取消
		expireTime := now.Add(constants.OrderExpireTimeout)
		order.ExpiresAt = &expireTime
		if err := s.orderStore.Create(ctx, order, items); err != nil {
			return nil, err
		}
		s.markOrderCreated(ctx, idempotencyKey, order.ID)
		return s.buildOrderResponse(ctx, order, items), nil
	}
}

func (s *Service) resolvePurchaseOnBehalfInfo(ctx context.Context, result *purchase_validation.PurchaseValidationResult) (uint, map[uint]int64, int64, *time.Time, error) {
	var resourceShopID *uint
	var seriesID *uint

	if result.Card != nil {
		resourceShopID = result.Card.ShopID
		seriesID = result.Card.SeriesID
	} else if result.Device != nil {
		resourceShopID = result.Device.ShopID
		seriesID = result.Device.SeriesID
	}

	if resourceShopID == nil || *resourceShopID == 0 {
		return 0, nil, 0, nil, errors.New(errors.CodeInvalidParam, "资源未分配给代理商，无法代购")
	}

	if seriesID == nil || *seriesID == 0 {
		return 0, nil, 0, nil, errors.New(errors.CodeInvalidParam, "资源未关联套餐系列")
	}

	if len(result.Packages) == 0 {
		return 0, nil, 0, nil, errors.New(errors.CodeInvalidParam, "订单中没有套餐")
	}

	buyerCostPriceMap, buyerTotalCost, err := s.buildCostPriceMap(ctx, result.Packages, *resourceShopID)
	if err != nil {
		return 0, nil, 0, nil, err
	}

	now := time.Now()
	return *resourceShopID, buyerCostPriceMap, buyerTotalCost, &now, nil
}

// buildOrderItems 构建订单明细列表
// retailPriceMap: 零售单价映射（UnitPrice），costPriceMap: 成本单价映射（CostPrice，无成本价时传 nil）
func (s *Service) buildOrderItems(operatorID uint, packages []*model.Package, retailPriceMap map[uint]int64, costPriceMap map[uint]int64) []*model.OrderItem {
	items := make([]*model.OrderItem, 0, len(packages))
	for _, pkg := range packages {
		if pkg == nil {
			continue
		}

		unitPrice := packageprice.PackageEffectiveRetailPrice(pkg)
		if price, ok := retailPriceMap[pkg.ID]; ok {
			unitPrice = price
		}

		var costPrice int64
		if costPriceMap != nil {
			costPrice = costPriceMap[pkg.ID]
		}

		item := &model.OrderItem{
			BaseModel: model.BaseModel{
				Creator: operatorID,
				Updater: operatorID,
			},
			PackageID:                pkg.ID,
			PackageName:              pkg.PackageName,
			PackageType:              &pkg.PackageType,
			Quantity:                 1,
			UnitPrice:                unitPrice,
			CostPrice:                costPrice,
			Amount:                   unitPrice,
			PackagePriceConfigStatus: pkg.PriceConfigStatus,
			PackageIsGift:            pkg.IsGift,
		}
		items = append(items, item)
	}

	return items
}

// buildRetailPriceMap 构建订单明细零售价映射和总价（分）
// sellerShopID > 0 时取代理分配零售价，=0 时取套餐建议零售价
func (s *Service) buildRetailPriceMap(ctx context.Context, packages []*model.Package, sellerShopID uint) (map[uint]int64, int64, error) {
	priceMap := make(map[uint]int64, len(packages))
	var total int64

	for _, pkg := range packages {
		if pkg == nil {
			continue
		}

		price, err := s.purchaseValidationService.GetPurchasePrice(ctx, pkg, sellerShopID)
		if err != nil {
			return nil, 0, err
		}
		priceMap[pkg.ID] = price
		total += price
	}

	return priceMap, total, nil
}

// buildCostPriceMap 构建订单明细成本价映射和总价（分）
func (s *Service) buildCostPriceMap(ctx context.Context, packages []*model.Package, shopID uint) (map[uint]int64, int64, error) {
	priceMap := make(map[uint]int64, len(packages))
	var total int64

	for _, pkg := range packages {
		if pkg == nil {
			continue
		}

		costPrice, err := s.getCostPrice(ctx, shopID, pkg.ID)
		if err != nil {
			return nil, 0, err
		}
		priceMap[pkg.ID] = costPrice
		total += costPrice
	}

	return priceMap, total, nil
}

func (s *Service) fetchBuyerSnapshot(ctx context.Context, customerID uint) (phone, nickname *string) {
	if customerID == 0 {
		return nil, nil
	}
	customer, err := s.personalCustomerStore.GetByID(ctx, customerID)
	if err != nil {
		s.logger.Warn("fetchBuyerSnapshot: 查询个人客户失败", zap.Uint("customer_id", customerID), zap.Error(err))
	} else if customer != nil && customer.Nickname != "" {
		nickname = &customer.Nickname
	}

	phoneRecord, err := s.personalCustomerPhoneStore.GetPrimaryPhone(ctx, customerID)
	if err != nil {
		s.logger.Warn("fetchBuyerSnapshot: 查询买家手机号失败", zap.Uint("customer_id", customerID), zap.Error(err))
	} else if phoneRecord != nil && phoneRecord.Phone != "" {
		phone = &phoneRecord.Phone
	}
	return phone, nickname
}

func (s *Service) buildAccountOperatorSnapshot(ctx context.Context, userID uint, userType int) (*uint, string, string) {
	if userID == 0 {
		return nil, "", ""
	}

	var account model.Account
	if err := s.db.WithContext(ctx).Where("id = ?", userID).First(&account).Error; err != nil {
		s.logger.Warn("buildAccountOperatorSnapshot: 查询账号失败", zap.Uint("user_id", userID), zap.Error(err))
		id := userID
		return &id, orderOperatorAccountTypeFromUserType(userType), ""
	}

	id := account.ID
	return &id, orderOperatorAccountTypeFromUserType(account.UserType), account.Username
}

func (s *Service) buildPersonalCustomerOperatorSnapshot(ctx context.Context, customerID uint, nickname *string) (*uint, string, string) {
	if customerID == 0 {
		return nil, "", ""
	}

	name := ""
	if nickname != nil {
		name = strings.TrimSpace(*nickname)
	}
	if name == "" && s.personalCustomerStore != nil {
		customer, err := s.personalCustomerStore.GetByID(ctx, customerID)
		if err != nil {
			s.logger.Warn("buildPersonalCustomerOperatorSnapshot: 查询个人客户失败", zap.Uint("customer_id", customerID), zap.Error(err))
		} else if customer != nil {
			name = strings.TrimSpace(customer.Nickname)
		}
	}

	id := customerID
	return &id, model.OperatorAccountTypePersonalCustomer, name
}

func orderOperatorAccountTypeFromUserType(userType int) string {
	switch userType {
	case constants.UserTypeSuperAdmin, constants.UserTypePlatform:
		return model.OperatorAccountTypePlatform
	case constants.UserTypeAgent:
		return model.OperatorAccountTypeAgent
	case constants.UserTypeEnterprise:
		return model.OperatorAccountTypeEnterprise
	default:
		return ""
	}
}

// getCostPrice 查询店铺对套餐的成本价
// shopID: 店铺ID
// packageID: 套餐ID
// 返回成本价（分），如果查询失败返回错误
func (s *Service) getCostPrice(ctx context.Context, shopID uint, packageID uint) (int64, error) {
	allocation, err := s.shopPackageAllocationStore.GetByShopAndPackage(ctx, shopID, packageID)
	if err != nil {
		if err == gorm.ErrRecordNotFound {
			return 0, errors.New(errors.CodeInvalidParam, "店铺没有该套餐的分配配置")
		}
		return 0, errors.Wrap(errors.CodeDatabaseError, err, "查询套餐成本价失败")
	}
	return allocation.CostPrice, nil
}

// debitAgentMainWalletInTx 通过统一 Wallet Application 接缝扣款并写入流水与 Outbox。
func (s *Service) debitAgentMainWalletInTx(ctx context.Context, tx *gorm.DB, order *model.Order, shopID uint, amount int64, relatedShopID *uint) error {
	if s.agentWalletDebit == nil {
		return errors.New(errors.CodeInternalError, "代理主钱包扣款能力未配置")
	}
	subtype := ""
	remark := "购买套餐"
	purchaseRole := order.PurchaseRole
	if purchaseRole == "" {
		purchaseRole = model.PurchaseRoleSelfPurchase
	}

	switch purchaseRole {
	case model.PurchaseRoleSelfPurchase:
		subtype = constants.WalletTransactionSubtypeSelfPurchase
	case model.PurchaseRolePurchaseForSubordinate:
		subtype = constants.WalletTransactionSubtypePurchaseForSubordinate
		if relatedShopID != nil {
			var shop model.Shop
			if err := tx.Where("id = ?", *relatedShopID).First(&shop).Error; err == nil {
				remark = fmt.Sprintf("为下级代理【%s】购买套餐", shop.ShopName)
			} else {
				remark = "为下级代理购买套餐"
			}
		}
	}

	userID := middleware.GetUserIDFromContext(ctx)
	assetType, assetID, assetIdentifier := buildAgentWalletTransactionAssetSnapshot(order)
	requestID := ""
	if value := middleware.GetRequestIDFromContext(ctx); value != nil {
		requestID = *value
	}
	_, err := s.agentWalletDebit.DebitInTx(ctx, tx, walletapp.DebitCommand{
		ShopID: shopID, Amount: amount, ReferenceType: constants.ReferenceTypeOrder, ReferenceID: order.ID,
		UserID: userID, Creator: userID, TransactionSubtype: subtype, RelatedShopID: relatedShopID,
		AssetType: assetType, AssetID: assetID, AssetIdentifier: assetIdentifier, Remark: remark,
		RequestID: requestID, CorrelationID: order.OrderNo,
	})
	if err != nil {
		return err
	}
	return nil
}

// buildAgentWalletTransactionAssetSnapshot 从订单中生成代理钱包扣款流水的资产快照。
func buildAgentWalletTransactionAssetSnapshot(order *model.Order) (string, uint, string) {
	if order == nil {
		return "", 0, ""
	}
	switch order.OrderType {
	case model.OrderTypeSingleCard:
		if order.IotCardID == nil {
			return constants.AssetTypeIotCard, 0, order.AssetIdentifier
		}
		return constants.AssetTypeIotCard, *order.IotCardID, order.AssetIdentifier
	case model.OrderTypeDevice:
		if order.DeviceID == nil {
			return constants.AssetTypeDevice, 0, order.AssetIdentifier
		}
		return constants.AssetTypeDevice, *order.DeviceID, order.AssetIdentifier
	default:
		return "", 0, order.AssetIdentifier
	}
}

// buildOrderAssetIdentifier 生成订单资产标识快照。
// 后台按标识下单时保留请求标识；按ID下单时用卡ICCID或设备虚拟号/IMEI兜底。
func buildOrderAssetIdentifier(result *purchase_validation.PurchaseValidationResult) string {
	if result == nil {
		return ""
	}
	if result.Card != nil {
		return result.Card.ICCID
	}
	if result.Device != nil {
		return firstNonEmpty(result.Device.VirtualNo, result.Device.IMEI)
	}
	return ""
}

func firstNonEmpty(values ...string) string {
	for _, value := range values {
		if value != "" {
			return value
		}
	}
	return ""
}

// strPtr 字符串指针辅助函数
func strPtr(s string) *string {
	return &s
}

// createOrderWithWalletPayment 使用钱包支付创建订单并完成支付。
// 订单、扣款流水、Payment、套餐处理与 Outbox 在同一事务提交。
// ctx: 上下文
// order: 订单对象
// items: 订单明细列表
// operatorShopID: 操作者店铺ID（扣款的店铺）
// buyerShopID: 买家店铺ID（代购场景下级店铺ID）
func (s *Service) createOrderWithWalletPayment(ctx context.Context, order *model.Order, items []*model.OrderItem, operatorShopID uint, buyerShopID uint) (uint, error) {
	if order.ActualPaidAmount == nil {
		return 0, errors.New(errors.CodeInternalError, "实际支付金额不能为空")
	}
	actualAmount := *order.ActualPaidAmount
	var existingOrderID uint

	err := s.db.WithContext(ctx).Transaction(func(tx *gorm.DB) error {
		matchedOrderID, err := lockAndFindRecentWalletOrder(ctx, tx, order.IdempotencyKey)
		if err != nil {
			return err
		}
		if matchedOrderID > 0 {
			existingOrderID = matchedOrderID
			return nil
		}
		if err := tx.Create(order).Error; err != nil {
			return errors.Wrap(errors.CodeDatabaseError, err, "创建订单失败")
		}

		for _, item := range items {
			item.OrderID = order.ID
		}
		if err := tx.CreateInBatches(items, 100).Error; err != nil {
			return errors.Wrap(errors.CodeDatabaseError, err, "创建订单明细失败")
		}

		var relatedShopID *uint
		if order.PurchaseRole == model.PurchaseRolePurchaseForSubordinate {
			relatedShopID = &buyerShopID
		}
		if err := s.debitAgentMainWalletInTx(ctx, tx, order, operatorShopID, actualAmount, relatedShopID); err != nil {
			return err
		}
		if err := s.createWalletPaymentRecord(tx, order, model.PaymentByWallet, actualAmount); err != nil {
			return err
		}
		if err := s.activatePackage(ctx, tx, order); err != nil {
			return err
		}

		return nil
	})

	if err != nil {
		return 0, err
	}
	if existingOrderID > 0 {
		return existingOrderID, nil
	}

	// 3. 事务外：所有已支付且适用差价佣金的订单都进入佣金计算
	if order.CommissionStatus == model.CommissionStatusPending {
		s.enqueueCommissionCalculation(ctx, order.ID)
	}

	return 0, nil
}

func (s *Service) createOrderWithActivation(ctx context.Context, order *model.Order, items []*model.OrderItem) error {
	return s.db.WithContext(ctx).Transaction(func(tx *gorm.DB) error {
		if err := tx.Create(order).Error; err != nil {
			return errors.Wrap(errors.CodeDatabaseError, err, "创建代购订单失败")
		}

		for _, item := range items {
			item.OrderID = order.ID
		}
		if err := tx.CreateInBatches(items, 100).Error; err != nil {
			return errors.Wrap(errors.CodeDatabaseError, err, "创建订单明细失败")
		}

		return s.activatePackage(ctx, tx, order)
	})
}

func (s *Service) Get(ctx context.Context, id uint) (*dto.OrderResponse, error) {
	order, items, err := s.orderStore.GetByIDWithItems(ctx, id)
	if err != nil {
		if err == gorm.ErrRecordNotFound {
			return nil, errors.New(errors.CodeNotFound, "订单不存在")
		}
		return nil, err
	}

	return s.buildOrderResponse(ctx, order, items), nil
}

func (s *Service) List(ctx context.Context, req *dto.OrderListRequest, buyerType string, buyerID uint) (*dto.OrderListResponse, error) {
	page := req.Page
	pageSize := req.PageSize
	if page == 0 {
		page = 1
	}
	if pageSize == 0 {
		pageSize = constants.DefaultPageSize
	}

	opts := &store.QueryOptions{
		Page:     page,
		PageSize: pageSize,
	}

	filters := map[string]any{}
	// 仅代理用户需要限定买家范围；平台/超管不加限制，可查看所有订单
	if buyerType != "" {
		filters["buyer_type"] = buyerType
	}
	if buyerID != 0 {
		filters["buyer_id"] = buyerID
	}
	if req.PaymentStatus != nil {
		filters["payment_status"] = *req.PaymentStatus
	}
	if req.PaymentMethod != "" {
		filters["payment_method"] = req.PaymentMethod
	}
	if req.OrderType != "" {
		filters["order_type"] = req.OrderType
	}
	if req.OrderNo != "" {
		filters["order_no"] = req.OrderNo
	}
	if req.PurchaseRole != "" {
		filters["purchase_role"] = req.PurchaseRole
	}
	if req.SellerShopID != nil {
		filters["seller_shop_id"] = *req.SellerShopID
	}
	if req.StartTime != nil {
		filters["start_time"] = req.StartTime
	}
	if req.EndTime != nil {
		filters["end_time"] = req.EndTime
	}
	if req.Identifier != "" {
		resolvedIotCardID, resolvedDeviceID, err := s.resolveOrderListAssetIdentifier(ctx, req.Identifier)
		if err != nil {
			return nil, err
		}
		// 保留快照标识匹配，并叠加资产 ID 匹配（由 Store 层统一按 OR 组合）
		filters["identifier"] = req.Identifier
		if resolvedIotCardID != nil {
			filters["iot_card_id"] = *resolvedIotCardID
		}
		if resolvedDeviceID != nil {
			filters["device_id"] = *resolvedDeviceID
		}
	}
	if req.BuyerPhone != "" {
		filters["buyer_phone"] = req.BuyerPhone
	}

	orders, total, err := s.orderStore.List(ctx, opts, filters)
	if err != nil {
		return nil, err
	}

	var orderIDs []uint
	for _, o := range orders {
		orderIDs = append(orderIDs, o.ID)
	}

	itemsMap := make(map[uint][]*model.OrderItem)
	if len(orderIDs) > 0 {
		allItems, err := s.orderItemStore.ListByOrderIDs(ctx, orderIDs)
		if err != nil {
			return nil, err
		}
		for _, item := range allItems {
			itemsMap[item.OrderID] = append(itemsMap[item.OrderID], item)
		}
	}

	var list []*dto.OrderResponse
	for _, o := range orders {
		list = append(list, s.buildOrderResponse(ctx, o, itemsMap[o.ID]))
	}

	return &dto.OrderListResponse{
		List:     list,
		Total:    total,
		Page:     page,
		PageSize: pageSize,
	}, nil
}

// resolveOrderListAssetIdentifier 将订单列表的统一资产标识解析为卡或设备 ID
// 支持 ICCID、VirtualNo、IMEI、SN、MSISDN，与资产解析接口的识别口径保持一致。
func (s *Service) resolveOrderListAssetIdentifier(ctx context.Context, identifier string) (*uint, *uint, error) {
	if identifier == "" {
		return nil, nil, nil
	}

	if s.assetIdentifierStore != nil {
		regRecord, regErr := s.assetIdentifierStore.FindByIdentifier(ctx, identifier)
		if regErr != nil {
			return nil, nil, errors.Wrap(errors.CodeDatabaseError, regErr, "查询资产标识符失败")
		}
		if regRecord != nil {
			switch regRecord.AssetType {
			case model.AssetTypeIotCard:
				card, cardErr := s.iotCardStore.GetByID(ctx, regRecord.AssetID)
				if cardErr == nil && card != nil {
					cardID := card.ID
					return &cardID, nil, nil
				}
				if cardErr != nil && cardErr != gorm.ErrRecordNotFound {
					return nil, nil, errors.Wrap(errors.CodeDatabaseError, cardErr, "查询物联网卡失败")
				}
			case model.AssetTypeDevice:
				device, deviceErr := s.deviceStore.GetByID(ctx, regRecord.AssetID)
				if deviceErr == nil && device != nil {
					deviceID := device.ID
					return nil, &deviceID, nil
				}
				if deviceErr != nil && deviceErr != gorm.ErrRecordNotFound {
					return nil, nil, errors.Wrap(errors.CodeDatabaseError, deviceErr, "查询设备失败")
				}
			}
		}
	}

	device, deviceErr := s.deviceStore.GetByIdentifier(ctx, identifier)
	if deviceErr == nil && device != nil {
		deviceID := device.ID
		return nil, &deviceID, nil
	}
	if deviceErr != nil && deviceErr != gorm.ErrRecordNotFound {
		return nil, nil, errors.Wrap(errors.CodeDatabaseError, deviceErr, "查询设备失败")
	}

	var card model.IotCard
	query := s.db.WithContext(ctx).Model(&model.IotCard{})
	query = middleware.ApplyShopFilter(ctx, query)

	conditions := []string{"virtual_no = ?", "msisdn = ?", "iccid = ?"}
	args := []any{identifier, identifier, identifier}
	if len(identifier) == 19 {
		conditions = append(conditions, "iccid_19 = ?")
		args = append(args, identifier)
	} else if len(identifier) == 20 {
		conditions = append(conditions, "iccid_20 = ?")
		args = append(args, identifier)
	}

	if err := query.Where(strings.Join(conditions, " OR "), args...).First(&card).Error; err == nil {
		cardID := card.ID
		return &cardID, nil, nil
	} else if err != gorm.ErrRecordNotFound {
		return nil, nil, errors.Wrap(errors.CodeDatabaseError, err, "查询物联网卡失败")
	}

	return nil, nil, nil
}

func (s *Service) Cancel(ctx context.Context, id uint, buyerType string, buyerID uint) error {
	order, err := s.orderStore.GetByID(ctx, id)
	if err != nil {
		if err == gorm.ErrRecordNotFound {
			return errors.New(errors.CodeNotFound, "订单不存在")
		}
		return err
	}

	if order.BuyerType != buyerType || order.BuyerID != buyerID {
		return errors.New(errors.CodeForbidden, "无权操作此订单")
	}

	if order.PaymentStatus != model.PaymentStatusPending {
		return errors.New(errors.CodeInvalidStatus, "只能取消待支付的订单")
	}

	return s.cancelOrder(ctx, order)
}

// CancelExpiredOrders 批量取消已超时的待支付订单
// 返回已取消的订单数量和错误
func (s *Service) CancelExpiredOrders(ctx context.Context) (int, error) {
	startTime := time.Now()

	orders, err := s.orderStore.FindExpiredOrders(ctx, constants.OrderExpireBatchSize)
	if err != nil {
		return 0, errors.Wrap(errors.CodeDatabaseError, err, "查询超时订单失败")
	}

	if len(orders) == 0 {
		return 0, nil
	}

	cancelledCount := 0
	for _, order := range orders {
		if err := s.cancelOrder(ctx, order); err != nil {
			s.logger.Error("自动取消超时订单失败",
				zap.Uint("order_id", order.ID),
				zap.String("order_no", order.OrderNo),
				zap.Error(err),
			)
			continue
		}
		cancelledCount++
	}

	s.logger.Info("批量取消超时订单完成",
		zap.Int("total", len(orders)),
		zap.Int("cancelled", cancelledCount),
		zap.Int("failed", len(orders)-cancelledCount),
		zap.Duration("duration", time.Since(startTime)),
	)

	return cancelledCount, nil
}

// cancelOrder 内部取消订单逻辑（共用于手动取消和自动超时取消）
// 在事务中执行：更新订单状态为已取消、清除过期时间、解冻钱包余额（如有）
func (s *Service) cancelOrder(ctx context.Context, order *model.Order) error {
	return s.db.WithContext(ctx).Transaction(func(tx *gorm.DB) error {
		// 使用条件更新确保幂等性：只有待支付的订单才能取消
		result := tx.Model(&model.Order{}).
			Where("id = ? AND payment_status = ?", order.ID, model.PaymentStatusPending).
			Updates(map[string]any{
				"payment_status": model.PaymentStatusCancelled,
				"expires_at":     nil,
			})
		if result.Error != nil {
			return errors.Wrap(errors.CodeDatabaseError, result.Error, "更新订单状态失败")
		}
		if result.RowsAffected == 0 {
			// 订单已被处理（幂等），直接返回
			return nil
		}

		// 检查是否需要解冻钱包余额（混合支付场景）
		// 当前系统中钱包支付订单是立即支付的，不会进入待支付状态
		// 此处为预留逻辑，支持未来混合支付场景的钱包解冻
		if order.PaymentMethod == model.PaymentMethodWallet {
			if err := s.unfreezeWalletForCancel(ctx, tx, order); err != nil {
				s.logger.Error("取消订单时解冻钱包失败",
					zap.Uint("order_id", order.ID),
					zap.Error(err),
				)
				return err
			}
		}

		return nil
	})
}

// unfreezeWalletForCancel 取消订单时解冻钱包余额。
// 代理主钱包以预占事实中的钱包和金额为权威，避免代购订单误用买方店铺。
func (s *Service) unfreezeWalletForCancel(ctx context.Context, tx *gorm.DB, order *model.Order) error {
	if order.BuyerType == model.BuyerTypeAgent {
		if s.agentWalletReservation == nil {
			return errors.New(errors.CodeInternalError, "代理主钱包预占能力未配置")
		}
		requestID := ""
		if value := middleware.GetRequestIDFromContext(ctx); value != nil {
			requestID = *value
		}
		return s.agentWalletReservation.ReleaseInTx(ctx, tx, walletapp.ReservationCommand{
			ReferenceType: constants.ReferenceTypeOrder, ReferenceID: order.ID,
			UserID: middleware.GetUserIDFromContext(ctx), Creator: middleware.GetUserIDFromContext(ctx),
			RequestID: requestID, CorrelationID: order.OrderNo, Remark: "取消订单释放预占资金",
		})
	} else if order.BuyerType == model.BuyerTypePersonal {
		// 个人客户钱包（卡/设备钱包）
		var resourceType string
		var resourceID uint
		if order.OrderType == model.OrderTypeSingleCard && order.IotCardID != nil {
			resourceType = "iot_card"
			resourceID = *order.IotCardID
		} else if order.OrderType == model.OrderTypeDevice && order.DeviceID != nil {
			resourceType = "device"
			resourceID = *order.DeviceID
		} else {
			return errors.New(errors.CodeInternalError, "无法确定钱包归属")
		}
		wallet, err := s.assetWalletStore.GetByResourceTypeAndID(ctx, resourceType, resourceID)
		if err != nil {
			return errors.Wrap(errors.CodeWalletNotFound, err, "查询资产钱包失败")
		}
		// 资产钱包解冻：直接减少冻结余额
		result := tx.Model(&model.AssetWallet{}).
			Where("id = ? AND frozen_balance >= ?", wallet.ID, order.TotalAmount).
			Updates(map[string]any{
				"frozen_balance": gorm.Expr("frozen_balance - ?", order.TotalAmount),
			})
		if result.Error != nil {
			return result.Error
		}
		if result.RowsAffected == 0 {
			return errors.New(errors.CodeInsufficientBalance, "冻结余额不足，无法解冻")
		}
		return nil
	}
	return nil
}

func (s *Service) createWalletPaymentRecord(tx *gorm.DB, order *model.Order, paymentMethod string, amount int64) error {
	paidAt := order.PaidAt
	if paidAt == nil {
		now := time.Now()
		paidAt = &now
	}
	payment := &model.Payment{
		PaymentNo:     order.OrderNo,
		OrderID:       order.ID,
		OrderType:     model.PaymentOrderTypePackage,
		PaymentMethod: paymentMethod,
		Amount:        amount,
		Status:        model.PaymentRecordStatusPaid,
		PaidAt:        paidAt,
	}
	if err := tx.Create(payment).Error; err != nil {
		return errors.Wrap(errors.CodeDatabaseError, err, "创建钱包支付记录失败")
	}
	return nil
}

func (s *Service) WalletPay(ctx context.Context, orderID uint, buyerType string, buyerID uint) error {
	order, err := s.orderStore.GetByID(ctx, orderID)
	if err != nil {
		if err == gorm.ErrRecordNotFound {
			return errors.New(errors.CodeNotFound, "订单不存在")
		}
		return err
	}

	if order.BuyerType != buyerType || order.BuyerID != buyerID {
		return errors.New(errors.CodeForbidden, "无权操作此订单")
	}

	if order.IsPurchaseOnBehalf {
		return errors.New(errors.CodeInvalidStatus, "代购订单无需支付")
	}

	existingPayment, err := s.paymentStore.GetByOrderIDAndStatus(ctx, orderID, model.PaymentRecordStatusPaid)
	if err != nil && err != gorm.ErrRecordNotFound {
		return errors.Wrap(errors.CodeDatabaseError, err, "查询订单支付记录失败")
	}
	if existingPayment != nil {
		return nil
	}

	var resourceType string
	var resourceID uint

	if buyerType == model.BuyerTypePersonal {
		if order.OrderType == model.OrderTypeSingleCard && order.IotCardID != nil {
			resourceType = "iot_card"
			resourceID = *order.IotCardID
		} else if order.OrderType == model.OrderTypeDevice && order.DeviceID != nil {
			resourceType = "device"
			resourceID = *order.DeviceID
		} else {
			return errors.New(errors.CodeInvalidParam, "无法确定钱包归属")
		}
	} else if buyerType == model.BuyerTypeAgent {
		resourceType = "shop"
		resourceID = buyerID
	} else {
		return errors.New(errors.CodeInvalidParam, "不支持的买家类型")
	}

	// 根据资源类型选择对应的钱包系统
	now := time.Now()
	actualPaidAmount := order.TotalAmount
	shouldEnqueueCommission := false

	if resourceType == "shop" {
		err = s.db.WithContext(ctx).Transaction(func(tx *gorm.DB) error {
			result := tx.Model(&model.Order{}).
				Where("id = ? AND payment_status = ?", orderID, model.PaymentStatusPending).
				Updates(map[string]any{
					"payment_status":     model.PaymentStatusPaid,
					"payment_method":     model.PaymentMethodWallet,
					"paid_at":            now,
					"expires_at":         nil, // 支付成功，清除过期时间
					"actual_paid_amount": actualPaidAmount,
				})
			if result.Error != nil {
				return errors.Wrap(errors.CodeDatabaseError, result.Error, "更新订单支付状态失败")
			}

			if result.RowsAffected == 0 {
				var currentOrder model.Order
				if err := tx.First(&currentOrder, orderID).Error; err != nil {
					return errors.Wrap(errors.CodeDatabaseError, err, "查询订单失败")
				}

				switch currentOrder.PaymentStatus {
				case model.PaymentStatusPaid:
					return nil
				case model.PaymentStatusCancelled:
					return errors.New(errors.CodeInvalidStatus, "订单已取消，无法支付")
				case model.PaymentStatusRefunded:
					return errors.New(errors.CodeInvalidStatus, "订单已退款，无法支付")
				default:
					return errors.New(errors.CodeInvalidStatus, "订单状态异常")
				}
			}

			actualPaidAmountSnapshot := actualPaidAmount
			order.ActualPaidAmount = &actualPaidAmountSnapshot
			order.PaidAt = &now
			shouldEnqueueCommission = true

			if err := s.debitAgentMainWalletInTx(ctx, tx, order, resourceID, order.TotalAmount, nil); err != nil {
				return err
			}

			if err := s.createWalletPaymentRecord(tx, order, model.PaymentByWallet, order.TotalAmount); err != nil {
				return err
			}

			return s.activatePackage(ctx, tx, order)
		})
	} else {
		// 资产钱包系统（iot_card 或 device）
		wallet, err := s.assetWalletStore.GetByResourceTypeAndID(ctx, resourceType, resourceID)
		if err != nil {
			if err == gorm.ErrRecordNotFound {
				return errors.New(errors.CodeWalletNotFound, "钱包不存在")
			}
			return err
		}

		if wallet.Balance < order.TotalAmount {
			return errors.New(errors.CodeInsufficientBalance, "余额不足")
		}

		err = s.db.WithContext(ctx).Transaction(func(tx *gorm.DB) error {
			result := tx.Model(&model.Order{}).
				Where("id = ? AND payment_status = ?", orderID, model.PaymentStatusPending).
				Updates(map[string]any{
					"payment_status":     model.PaymentStatusPaid,
					"payment_method":     model.PaymentMethodWallet,
					"paid_at":            now,
					"expires_at":         nil, // 支付成功，清除过期时间
					"actual_paid_amount": actualPaidAmount,
				})
			if result.Error != nil {
				return errors.Wrap(errors.CodeDatabaseError, result.Error, "更新订单支付状态失败")
			}

			if result.RowsAffected == 0 {
				var currentOrder model.Order
				if err := tx.First(&currentOrder, orderID).Error; err != nil {
					return errors.Wrap(errors.CodeDatabaseError, err, "查询订单失败")
				}

				switch currentOrder.PaymentStatus {
				case model.PaymentStatusPaid:
					return nil
				case model.PaymentStatusCancelled:
					return errors.New(errors.CodeInvalidStatus, "订单已取消，无法支付")
				case model.PaymentStatusRefunded:
					return errors.New(errors.CodeInvalidStatus, "订单已退款，无法支付")
				default:
					return errors.New(errors.CodeInvalidStatus, "订单状态异常")
				}
			}

			actualPaidAmountSnapshot := actualPaidAmount
			order.ActualPaidAmount = &actualPaidAmountSnapshot

			// 扣款前记录余额快照，用于写入流水
			balanceBefore := wallet.Balance

			walletResult := tx.Model(&model.AssetWallet{}).
				Where("id = ? AND balance >= ? AND version = ?", wallet.ID, order.TotalAmount, wallet.Version).
				Updates(map[string]any{
					"balance": gorm.Expr("balance - ?", order.TotalAmount),
					"version": gorm.Expr("version + 1"),
				})
			if walletResult.Error != nil {
				return errors.Wrap(errors.CodeDatabaseError, walletResult.Error, "扣减钱包余额失败")
			}
			if walletResult.RowsAffected == 0 {
				return errors.New(errors.CodeInsufficientBalance, "余额不足或并发冲突")
			}

			// 扣款成功后补写扣款流水，填补流水表中扣款记录缺失的问题
			deductTx := &model.AssetWalletTransaction{
				AssetWalletID:   wallet.ID,
				ResourceType:    resourceType,
				ResourceID:      resourceID,
				UserID:          buyerID,
				TransactionType: "deduct",
				Amount:          -order.TotalAmount,
				BalanceBefore:   balanceBefore,
				BalanceAfter:    balanceBefore - order.TotalAmount,
				Status:          1,
				ReferenceType:   strPtr("order"),
				ReferenceNo:     &order.OrderNo,
				Remark:          strPtr("钱包支付套餐"),
				ShopIDTag:       wallet.ShopIDTag,
				EnterpriseIDTag: wallet.EnterpriseIDTag,
			}
			if err := tx.Create(deductTx).Error; err != nil {
				return errors.Wrap(errors.CodeDatabaseError, err, "创建扣款流水失败")
			}

			if err := s.createWalletPaymentRecord(tx, order, model.PaymentByWallet, order.TotalAmount); err != nil {
				return err
			}

			return s.activatePackage(ctx, tx, order)
		})
	}

	if err != nil {
		return err
	}

	if shouldEnqueueCommission && order.CommissionStatus == model.CommissionStatusPending {
		s.enqueueCommissionCalculation(ctx, orderID)
	}
	return nil
}

func (s *Service) HandlePaymentCallback(ctx context.Context, orderNo string, paymentMethod string, actualPaidAmount int64) error {
	order, err := s.orderStore.GetByOrderNo(ctx, orderNo)
	if err != nil {
		if err == gorm.ErrRecordNotFound {
			return errors.New(errors.CodeNotFound, "订单不存在")
		}
		return err
	}

	now := time.Now()
	shouldResumeAfterPayment := false
	shouldEnqueueCommission := false
	err = s.db.WithContext(ctx).Transaction(func(tx *gorm.DB) error {
		result := tx.Model(&model.Order{}).
			Where("id = ? AND payment_status = ?", order.ID, model.PaymentStatusPending).
			Updates(map[string]any{
				"payment_status":     model.PaymentStatusPaid,
				"payment_method":     paymentMethod,
				"paid_at":            now,
				"expires_at":         nil, // 支付成功，清除过期时间
				"actual_paid_amount": actualPaidAmount,
			})
		if result.Error != nil {
			return errors.Wrap(errors.CodeDatabaseError, result.Error, "更新订单支付状态失败")
		}

		if result.RowsAffected == 0 {
			var currentOrder model.Order
			if err := tx.First(&currentOrder, order.ID).Error; err != nil {
				return errors.Wrap(errors.CodeDatabaseError, err, "查询订单失败")
			}

			switch currentOrder.PaymentStatus {
			case model.PaymentStatusPaid:
				return nil
			case model.PaymentStatusCancelled:
				return errors.New(errors.CodeInvalidStatus, "订单已取消，无法支付")
			case model.PaymentStatusRefunded:
				return errors.New(errors.CodeInvalidStatus, "订单已退款，无法支付")
			default:
				return errors.New(errors.CodeInvalidStatus, "订单状态异常")
			}
		}

		// 回调更新成功后，同步内存对象，确保激活套餐时写入 paid_amount 快照
		actualPaidAmountSnapshot := actualPaidAmount
		order.ActualPaidAmount = &actualPaidAmountSnapshot
		shouldResumeAfterPayment = true
		shouldEnqueueCommission = true

		return s.activatePackage(ctx, tx, order)
	})

	if err != nil {
		return err
	}

	if shouldResumeAfterPayment {
		s.tryResumeAfterPayment(ctx, order)
	}
	if shouldEnqueueCommission && order.CommissionStatus == model.CommissionStatusPending {
		s.enqueueCommissionCalculation(ctx, order.ID)
	}
	return nil
}

// HandlePaymentRecordCallback 通过支付单处理套餐订单第三方支付回调。
func (s *Service) HandlePaymentRecordCallback(ctx context.Context, paymentNo string, paymentMethod string, thirdPartyTradeNo string, actualPaidAmount int64) error {
	payment, err := s.paymentStore.GetByPaymentNo(ctx, paymentNo)
	if err != nil {
		if err == gorm.ErrRecordNotFound {
			return errors.New(errors.CodeNotFound, "支付记录不存在")
		}
		return errors.Wrap(errors.CodeDatabaseError, err, "查询支付记录失败")
	}
	if payment.OrderType != model.PaymentOrderTypePackage {
		return errors.New(errors.CodeInvalidParam, "支付记录类型不匹配")
	}

	order, err := s.orderStore.GetByID(ctx, payment.OrderID)
	if err != nil {
		if err == gorm.ErrRecordNotFound {
			return errors.New(errors.CodeNotFound, "订单不存在")
		}
		return errors.Wrap(errors.CodeDatabaseError, err, "查询订单失败")
	}

	now := time.Now()
	shouldResumeAfterPayment := false
	shouldEnqueueCommission := false
	err = s.db.WithContext(ctx).Transaction(func(tx *gorm.DB) error {
		paymentUpdates := map[string]any{
			"status":  model.PaymentRecordStatusPaid,
			"paid_at": now,
		}
		if thirdPartyTradeNo != "" {
			paymentUpdates["third_party_trade_no"] = thirdPartyTradeNo
		}
		paymentResult := tx.Model(&model.Payment{}).
			Where("id = ? AND status = ?", payment.ID, model.PaymentRecordStatusPending).
			Updates(paymentUpdates)
		if paymentResult.Error != nil {
			return errors.Wrap(errors.CodeDatabaseError, paymentResult.Error, "更新支付记录失败")
		}
		if paymentResult.RowsAffected == 0 {
			var currentPayment model.Payment
			if err := tx.First(&currentPayment, payment.ID).Error; err != nil {
				return errors.Wrap(errors.CodeDatabaseError, err, "查询支付记录失败")
			}
			if currentPayment.Status == model.PaymentRecordStatusPaid {
				return nil
			}
			return errors.New(errors.CodeInvalidStatus, "支付记录状态不允许处理")
		}

		result := tx.Model(&model.Order{}).
			Where("id = ? AND payment_status = ?", order.ID, model.PaymentStatusPending).
			Updates(map[string]any{
				"payment_status":     model.PaymentStatusPaid,
				"payment_method":     paymentMethod,
				"paid_at":            now,
				"expires_at":         nil,
				"actual_paid_amount": actualPaidAmount,
			})
		if result.Error != nil {
			return errors.Wrap(errors.CodeDatabaseError, result.Error, "更新订单支付状态失败")
		}
		if result.RowsAffected == 0 {
			var currentOrder model.Order
			if err := tx.First(&currentOrder, order.ID).Error; err != nil {
				return errors.Wrap(errors.CodeDatabaseError, err, "查询订单失败")
			}

			switch currentOrder.PaymentStatus {
			case model.PaymentStatusPaid:
				return nil
			case model.PaymentStatusCancelled:
				return errors.New(errors.CodeInvalidStatus, "订单已取消，无法支付")
			case model.PaymentStatusRefunded:
				return errors.New(errors.CodeInvalidStatus, "订单已退款，无法支付")
			default:
				return errors.New(errors.CodeInvalidStatus, "订单状态异常")
			}
		}

		actualPaidAmountSnapshot := actualPaidAmount
		order.ActualPaidAmount = &actualPaidAmountSnapshot
		shouldResumeAfterPayment = true
		shouldEnqueueCommission = true

		return s.activatePackage(ctx, tx, order)
	})

	if err != nil {
		return err
	}

	if shouldResumeAfterPayment {
		s.tryResumeAfterPayment(ctx, order)
	}
	if shouldEnqueueCommission && order.CommissionStatus == model.CommissionStatusPending {
		s.enqueueCommissionCalculation(ctx, order.ID)
	}
	return nil
}

// tryResumeAfterPayment 支付成功后检查是否应触发自动复机
// 仅当本次支付直接激活了主套餐（status=1，非排队）时才调用复机，避免虚流量已超但套餐排队时错误复机
func (s *Service) tryResumeAfterPayment(ctx context.Context, order *model.Order) {
	if s.resumeCallback == nil {
		return
	}

	var resumeCarrierType string
	var resumeCarrierID uint

	if order.OrderType == model.OrderTypeSingleCard && order.IotCardID != nil {
		resumeCarrierType = "iot_card"
		resumeCarrierID = *order.IotCardID
	} else if order.OrderType == model.OrderTypeDevice && order.DeviceID != nil {
		resumeCarrierType = "device"
		resumeCarrierID = *order.DeviceID
	}

	if resumeCarrierID == 0 {
		return
	}

	var activatedCount int64
	s.db.WithContext(ctx).Model(&model.PackageUsage{}).
		Where("order_id = ? AND status = ? AND master_usage_id IS NULL", order.ID, constants.PackageUsageStatusActive).
		Count(&activatedCount)

	if activatedCount == 0 {
		return
	}

	resumeCtx := context.WithoutCancel(ctx)
	go func(ct string, cid uint) {
		if err := s.resumeCallback.ResumeCardIfStopped(resumeCtx, ct, cid); err != nil {
			s.logger.Error("支付后自动复机失败",
				zap.String("carrier_type", ct),
				zap.Uint("carrier_id", cid),
				zap.Uint("order_id", order.ID),
				zap.Error(err))
		}
	}(resumeCarrierType, resumeCarrierID)
}

func (s *Service) activatePackage(ctx context.Context, tx *gorm.DB, order *model.Order) error {
	var items []*model.OrderItem
	if err := tx.Where("order_id = ?", order.ID).Find(&items).Error; err != nil {
		return errors.Wrap(errors.CodeDatabaseError, err, "查询订单明细失败")
	}

	// 任务 8.1: 检查混买限制 - 禁止同订单混买正式套餐和加油包
	if err := s.validatePackageTypeMix(tx, items); err != nil {
		return err
	}

	// 确定载体类型和ID
	carrierType := "iot_card"
	var carrierID uint
	if order.OrderType == model.OrderTypeSingleCard && order.IotCardID != nil {
		carrierID = *order.IotCardID
	} else if order.OrderType == model.OrderTypeDevice && order.DeviceID != nil {
		carrierType = "device"
		carrierID = *order.DeviceID
	} else {
		return errors.New(errors.CodeInvalidParam, "无效的订单类型或缺少载体ID")
	}

	now := time.Now()
	createdUsage := false
	for _, item := range items {
		// 检查是否已存在使用记录
		var existingUsage model.PackageUsage
		err := tx.Where("order_id = ? AND package_id = ?", order.ID, item.PackageID).
			First(&existingUsage).Error
		if err == nil {
			s.logger.Warn("套餐使用记录已存在，跳过创建",
				zap.Uint("order_id", order.ID),
				zap.Uint("package_id", item.PackageID))
			continue
		}
		if err != gorm.ErrRecordNotFound {
			return errors.Wrap(errors.CodeDatabaseError, err, "检查套餐使用记录失败")
		}

		// 查询套餐信息
		var pkg model.Package
		if err := tx.First(&pkg, item.PackageID).Error; err != nil {
			return errors.Wrap(errors.CodeDatabaseError, err, "查询套餐信息失败")
		}

		// 根据套餐类型分别处理
		if pkg.PackageType == "formal" {
			// 主套餐处理逻辑（任务 8.2-8.4）
			if err := s.activateMainPackage(ctx, tx, order, &pkg, carrierType, carrierID, now); err != nil {
				return err
			}
			createdUsage = true
		} else if pkg.PackageType == "addon" {
			// 加油包处理逻辑（任务 8.5-8.7）
			if err := s.activateAddonPackage(ctx, tx, order, &pkg, carrierType, carrierID, now); err != nil {
				return err
			}
			createdUsage = true
		}
	}
	if createdUsage {
		if s.observationSeriesEvents == nil {
			return errors.New(errors.CodeInternalError, "购包观测 Outbox Writer 未配置")
		}
		eventID := "card-observation:order:" + strconv.FormatUint(uint64(order.ID), 10)
		requestID := requestIDFromContext(ctx)
		if requestID == "" {
			requestID = eventID
		}
		if err := s.observationSeriesEvents.AppendSeriesRequested(ctx, tx, cardObservationApp.SeriesRequestedEvent{
			EventID: eventID,
			Scene:   constants.CardObservationScenePackageChanged, ResourceType: carrierType, ResourceID: carrierID,
			SyncTypes: []string{constants.CardObservationSyncTypeRealname, constants.CardObservationSyncTypeTraffic, constants.CardObservationSyncTypeNetwork},
			Source:    constants.CardObservationSourceBusinessEvent, OccurredAt: now,
			RequestID: requestID, CorrelationID: requestID,
		}); err != nil {
			return err
		}
	}
	return nil
}

func requestIDFromContext(ctx context.Context) string {
	if value := middleware.GetRequestIDFromContext(ctx); value != nil {
		return *value
	}
	return ""
}

func (s *Service) lockPackageCarrier(ctx context.Context, tx *gorm.DB, carrierType string, carrierID uint) error {
	switch carrierType {
	case constants.AssetWalletResourceTypeIotCard, "card":
		var card model.IotCard
		if err := tx.WithContext(ctx).Clauses(clause.Locking{Strength: "UPDATE"}).First(&card, carrierID).Error; err != nil {
			return errors.Wrap(errors.CodeDatabaseError, err, "锁定卡失败")
		}
	case constants.AssetWalletResourceTypeDevice:
		var device model.Device
		if err := tx.WithContext(ctx).Clauses(clause.Locking{Strength: "UPDATE"}).First(&device, carrierID).Error; err != nil {
			return errors.Wrap(errors.CodeDatabaseError, err, "锁定设备失败")
		}
	default:
		return errors.New(errors.CodeInvalidParam, "无效的套餐载体类型")
	}
	return nil
}

// validatePackageTypeMix 任务 8.1: 检查混买限制
func (s *Service) validatePackageTypeMix(tx *gorm.DB, items []*model.OrderItem) error {
	hasFormal := false
	hasAddon := false

	for _, item := range items {
		var pkg model.Package
		if err := tx.First(&pkg, item.PackageID).Error; err != nil {
			return errors.Wrap(errors.CodeDatabaseError, err, "查询套餐信息失败")
		}

		if pkg.PackageType == constants.PackageTypeFormal {
			hasFormal = true
		} else if pkg.PackageType == constants.PackageTypeAddon {
			hasAddon = true
		}

		if hasFormal && hasAddon {
			return errors.New(errors.CodeInvalidParam, "不允许在同一订单中同时购买正式套餐和加油包")
		}
	}

	return nil
}

// validatePackageTypeMixFromPackages 基于已加载的套餐列表检查混买限制（无需 DB 查询）
func validatePackageTypeMixFromPackages(packages []*model.Package) error {
	hasFormal := false
	hasAddon := false

	for _, pkg := range packages {
		if pkg.PackageType == constants.PackageTypeFormal {
			hasFormal = true
		} else if pkg.PackageType == constants.PackageTypeAddon {
			hasAddon = true
		}

		if hasFormal && hasAddon {
			return errors.New(errors.CodeInvalidParam, "不允许在同一订单中同时购买正式套餐和加油包")
		}
	}

	return nil
}

// resolveCarrierInfo 从请求中提取载体类型和ID
func resolveCarrierInfo(req *dto.CreateOrderRequest) (carrierType string, carrierID uint) {
	if req.OrderType == model.OrderTypeSingleCard && req.IotCardID != nil {
		return "iot_card", *req.IotCardID
	}
	if req.OrderType == model.OrderTypeDevice && req.DeviceID != nil {
		return "device", *req.DeviceID
	}
	return "", 0
}

// resolveAdminCarrierInfoFromVars 从已解析的订单类型和资产ID中提取载体类型和ID
func resolveAdminCarrierInfoFromVars(orderType string, iotCardID *uint, deviceID *uint) (carrierType string, carrierID uint) {
	if orderType == model.OrderTypeSingleCard && iotCardID != nil {
		return "iot_card", *iotCardID
	}
	if orderType == model.OrderTypeDevice && deviceID != nil {
		return "device", *deviceID
	}
	return "", 0
}

// resolveAssetByIdentifier 通过卡 ICCID 或设备 VirtualNo、IMEI、SN 解析资产。
// 优先查注册表，注册表命中则直接返回对应卡或设备
func (s *Service) resolveAssetByIdentifier(ctx context.Context, identifier string) (*model.IotCard, *model.Device, error) {
	if s.assetIdentifierStore != nil {
		regRecord, regErr := s.assetIdentifierStore.FindByIdentifier(ctx, identifier)
		if regErr == nil && regRecord != nil {
			switch regRecord.AssetType {
			case model.AssetTypeIotCard:
				card, cardErr := s.iotCardStore.GetByID(ctx, regRecord.AssetID)
				if cardErr == nil && card != nil {
					return card, nil, nil
				}
			case model.AssetTypeDevice:
				device, devErr := s.deviceStore.GetByID(ctx, regRecord.AssetID)
				if devErr == nil && device != nil {
					return nil, device, nil
				}
			}
		}
	}
	if card, cardErr := s.iotCardStore.GetByIdentifier(ctx, identifier); cardErr == nil && card != nil {
		return card, nil, nil
	}
	if device, deviceErr := s.deviceStore.GetByIdentifier(ctx, identifier); deviceErr == nil && device != nil {
		return nil, device, nil
	}
	return nil, nil, errors.New(errors.CodeNotFound, "未找到对应资产，请使用 ICCID 或虚拟号")
}

// buildOrderIdempotencyKey 生成订单创建的幂等性业务键
// 格式: {buyer_type}:{buyer_id}:{order_type}:{carrier_type}:{carrier_id}:{sorted_package_ids}
func buildOrderIdempotencyKey(buyerType string, buyerID uint, orderType string, carrierType string, carrierID uint, packageIDs []uint) string {
	sortedIDs := make([]uint, len(packageIDs))
	copy(sortedIDs, packageIDs)
	sort.Slice(sortedIDs, func(i, j int) bool { return sortedIDs[i] < sortedIDs[j] })

	idStrs := make([]string, len(sortedIDs))
	for i, id := range sortedIDs {
		idStrs[i] = strconv.FormatUint(uint64(id), 10)
	}

	return fmt.Sprintf("%s:%d:%s:%s:%d:%s",
		buyerType, buyerID, orderType, carrierType, carrierID, strings.Join(idStrs, ","))
}

func orderIdempotencyDigest(key string) string {
	digest := sha256.Sum256([]byte(key))
	return fmt.Sprintf("%x", digest)
}

func orderIdempotencyAdvisoryKey(digest string) int64 {
	value := sha256.Sum256([]byte(digest))
	return int64(binary.BigEndian.Uint64(value[:8]))
}

const (
	orderIdempotencyTTL = 3 * time.Minute
	orderCreateLockTTL  = orderIdempotencyTTL
)

// checkOrderIdempotency 检查订单是否已创建（Redis SETNX + 分布式锁）
// 返回已存在的 orderID、当前请求持有的锁令牌以及错误。
func (s *Service) checkOrderIdempotency(ctx context.Context, buyerType string, buyerID uint, orderType string, carrierType string, carrierID uint, packageIDs []uint) (uint, string, error) {
	idempotencyKey := buildOrderIdempotencyKey(buyerType, buyerID, orderType, carrierType, carrierID, packageIDs)
	redisKey := constants.RedisOrderIdempotencyKey(idempotencyKey)

	// 第 1 层：Redis 快速检测，如果 key 已存在说明已创建或正在创建
	val, err := s.redis.Get(ctx, redisKey).Result()
	if err == nil && val != "" {
		orderID, _ := strconv.ParseUint(val, 10, 64)
		if orderID > 0 {
			s.logger.Info("订单幂等性命中，返回已有订单",
				zap.Uint("order_id", uint(orderID)),
				zap.String("idempotency_key", idempotencyKey))
			return uint(orderID), "", nil
		}
	}
	if err != nil && err != redis.Nil {
		return 0, "", errors.Wrap(errors.CodeServiceUnavailable, err, "订单幂等缓存不可用")
	}

	// 第 2 层：分布式锁，防止并发创建
	lockKey := constants.RedisOrderCreateLockKey(carrierType, carrierID)
	lockToken := uuid.NewString()
	locked, err := s.redis.SetNX(ctx, lockKey, lockToken, orderCreateLockTTL).Result()
	if err != nil {
		return 0, "", errors.Wrap(errors.CodeServiceUnavailable, err, "获取订单创建锁失败")
	}
	if !locked {
		return 0, "", errors.New(errors.CodeTooManyRequests, "订单正在创建中，请勿重复提交")
	}

	// 第 3 层：加锁后二次检测，防止锁等待期间已被处理
	val, err = s.redis.Get(ctx, redisKey).Result()
	if err == nil && val != "" {
		orderID, _ := strconv.ParseUint(val, 10, 64)
		if orderID > 0 {
			s.logger.Info("订单幂等性二次检测命中",
				zap.Uint("order_id", uint(orderID)),
				zap.String("idempotency_key", idempotencyKey))
			return uint(orderID), lockToken, nil
		}
	}
	if err != nil && err != redis.Nil {
		return 0, lockToken, errors.Wrap(errors.CodeServiceUnavailable, err, "复核订单幂等标记失败")
	}

	return 0, lockToken, nil
}

// releaseOrderCreateLock 仅释放当前请求持有的订单创建锁。
func (s *Service) releaseOrderCreateLock(ctx context.Context, lockKey, lockToken string) {
	const compareAndDelete = `
if redis.call("GET", KEYS[1]) == ARGV[1] then
    return redis.call("DEL", KEYS[1])
end
return 0`
	if err := s.redis.Eval(ctx, compareAndDelete, []string{lockKey}, lockToken).Err(); err != nil {
		s.logger.Warn("释放订单创建锁失败", zap.String("lock_key", lockKey), zap.Error(err))
	}
}

func lockAndFindRecentWalletOrder(ctx context.Context, tx *gorm.DB, idempotencyKey string) (uint, error) {
	if idempotencyKey == "" {
		return 0, errors.New(errors.CodeInternalError, "钱包订单缺少持久化幂等指纹")
	}
	if err := tx.WithContext(ctx).Exec("SELECT pg_advisory_xact_lock(?)", orderIdempotencyAdvisoryKey(idempotencyKey)).Error; err != nil {
		return 0, errors.Wrap(errors.CodeDatabaseError, err, "锁定钱包订单幂等指纹失败")
	}
	var existing model.Order
	err := tx.WithContext(ctx).
		Where("idempotency_key = ? AND created_at >= CURRENT_TIMESTAMP - (? * INTERVAL '1 second')",
			idempotencyKey, int64(orderIdempotencyTTL/time.Second)).
		Order("id DESC").First(&existing).Error
	if err == nil {
		return existing.ID, nil
	}
	if err == gorm.ErrRecordNotFound {
		return 0, nil
	}
	return 0, errors.Wrap(errors.CodeDatabaseError, err, "查询近期重复钱包订单失败")
}

// markOrderCreated 在订单事务提交后写入 Redis 快速幂等标记。
func (s *Service) markOrderCreated(ctx context.Context, idempotencyKey string, orderID uint) {
	redisKey := constants.RedisOrderIdempotencyKey(idempotencyKey)
	if err := s.redis.Set(ctx, redisKey, strconv.FormatUint(uint64(orderID), 10), orderIdempotencyTTL).Err(); err != nil {
		s.logger.Warn("设置订单幂等性标记失败",
			zap.Error(err),
			zap.Uint("order_id", orderID))
	}
}

// activateMainPackage 任务 8.2-8.4: 主套餐激活逻辑
func (s *Service) activateMainPackage(ctx context.Context, tx *gorm.DB, order *model.Order, pkg *model.Package, carrierType string, carrierID uint, now time.Time) error {
	terms, err := s.resolvePackageTerms(ctx, tx, pkg, order.SellerShopID)
	if err != nil {
		s.logger.Error("生成套餐计时快照失败", zap.Uint("package_id", pkg.ID), zap.Error(err))
		return err
	}
	if err := s.lockPackageCarrier(ctx, tx, carrierType, carrierID); err != nil {
		return err
	}

	hasCurrentMain, err := packagepkg.HasCurrentMainPackageForQueue(tx.WithContext(ctx), carrierType, carrierID, now)
	if err != nil {
		return errors.Wrap(errors.CodeDatabaseError, err, "查询主套餐失败")
	}

	var status int
	var priority int
	var activatedAt time.Time
	var expiresAt time.Time
	var nextResetAt *time.Time
	var pendingRealnameActivation bool

	if hasCurrentMain {
		// 当前仍有在用主套餐时，新主套餐进入待生效队列，后续由过期/退款等流程接续激活。
		status = constants.PackageUsageStatusPending
		var maxPriority int
		tx.Model(&model.PackageUsage{}).
			Where(carrierType+"_id = ?", carrierID).
			Select("COALESCE(MAX(priority), 0)").
			Scan(&maxPriority)
		priority = maxPriority + 1
	} else {
		status = constants.PackageUsageStatusActive
		priority = 1
		activatedAt = now
		// 使用工具函数计算过期时间
		expiresAt = packagepkg.CalculateExpiryTime(terms.CalendarType, activatedAt, terms.DurationMonths, terms.DurationDays)
		// 计算下次重置时间（基于套餐周期类型）
		nextResetAt = packagepkg.CalculateNextResetTime(pkg.DataResetCycle, terms.CalendarType, now, activatedAt)

		// REALNAME-02: 后台囤货场景三维决策（购买路径 + expiry_base + 实名状态）
		// 查询载体当前实名状态：已实名则跳过 pending，直接激活
		var currentlyRealnamed bool
		if carrierType == "iot_card" {
			var card model.IotCard
			if err := tx.Select("real_name_status").First(&card, carrierID).Error; err == nil {
				currentlyRealnamed = card.RealNameStatus == constants.RealNameStatusVerified
			}
			// err != nil 时 currentlyRealnamed 保守默认 false，不阻断购买流程
		} else if carrierType == "device" {
			// 子查询：统计该设备绑定的已实名卡数量（GORM 自动注入 deleted_at IS NULL）
			var count int64
			subQuery := tx.Model(&model.DeviceSimBinding{}).
				Select("iot_card_id").
				Where("device_id = ? AND bind_status = 1", carrierID)
			if err := tx.Model(&model.IotCard{}).
				Where("id IN (?) AND real_name_status = 1", subQuery).
				Count(&count).Error; err == nil {
				currentlyRealnamed = count > 0
			}
			// err != nil 时保守默认 false，不阻断购买流程
		}

		// 判断是否 C 端购买（C 端购买前已做实名前置检查，直接激活）
		isCEndPurchase := order.BuyerType == model.BuyerTypePersonal

		if !isCEndPurchase {
			// 后台囤货路径：按 expiry_base 决定是否等实名
			if terms.ExpiryBase != constants.PackageExpiryBaseFromPurchase {
				if currentlyRealnamed {
					s.logger.Info("购买时载体已实名，直接激活套餐",
						zap.String("carrier_type", carrierType),
						zap.Uint("carrier_id", carrierID))
				} else {
					// from_activation（默认）：未实名，等实名后激活
					status = constants.PackageUsageStatusPending
					pendingRealnameActivation = true
					activatedAt = time.Time{}
					expiresAt = time.Time{}
					nextResetAt = nil
				}
			}
			// from_purchase：立即激活，status 已为 Active，保持不变
		}
		// C 端购买已完成实名前置校验，直接激活。
	}

	// 创建套餐使用记录
	virtualTotalMBSnapshot, displayGainRatioSnapshot, enableVirtualDataSnapshot := model.BuildPackageUsageSnapshotValues(pkg)
	retailAmount := order.TotalAmount
	usage := &model.PackageUsage{
		BaseModel: model.BaseModel{
			Creator: order.Creator,
			Updater: order.Creator,
		},
		OrderID:                   order.ID,
		OrderNo:                   order.OrderNo,
		PackageID:                 pkg.ID,
		PackageName:               pkg.PackageName,
		UsageType:                 order.OrderType,
		DataLimitMB:               pkg.RealDataMB,
		VirtualTotalMBSnapshot:    virtualTotalMBSnapshot,
		DisplayGainRatioSnapshot:  displayGainRatioSnapshot,
		EnableVirtualDataSnapshot: enableVirtualDataSnapshot,
		Status:                    status,
		Priority:                  priority,
		DataResetCycle:            pkg.DataResetCycle,
		PendingRealnameActivation: pendingRealnameActivation,
		PaidAmount:                order.ActualPaidAmount,
		RetailAmount:              &retailAmount,
		PackagePriceConfigStatus:  pkg.PriceConfigStatus,
		PackageIsGift:             pkg.IsGift,
	}
	terms.Apply(usage)

	if carrierType == "iot_card" {
		usage.IotCardID = carrierID
	} else {
		usage.DeviceID = carrierID
	}

	if status == constants.PackageUsageStatusActive {
		usage.ActivatedAt = &activatedAt
		usage.ExpiresAt = &expiresAt
		usage.NextResetAt = nextResetAt
	}

	// 创建套餐使用记录（两步处理零值问题）
	if err := tx.Omit("status", "pending_realname_activation").Create(usage).Error; err != nil {
		return errors.Wrap(errors.CodeDatabaseError, err, "创建主套餐使用记录失败")
	}
	// 明确更新零值字段
	if err := tx.Model(usage).Updates(map[string]interface{}{
		"status":                      usage.Status,
		"pending_realname_activation": usage.PendingRealnameActivation,
	}).Error; err != nil {
		return errors.Wrap(errors.CodeDatabaseError, err, "更新主套餐状态失败")
	}

	return nil
}

// activateAddonPackage 任务 8.5-8.7: 加油包激活逻辑
func (s *Service) activateAddonPackage(ctx context.Context, tx *gorm.DB, order *model.Order, pkg *model.Package, carrierType string, carrierID uint, now time.Time) error {
	terms, err := s.resolvePackageTerms(ctx, tx, pkg, order.SellerShopID)
	if err != nil {
		s.logger.Error("生成加油包计时快照失败", zap.Uint("package_id", pkg.ID), zap.Error(err))
		return err
	}
	// 任务 8.5-8.6: 检查是否有可挂靠主套餐（待生效、未过期的生效中或已用完）
	mainPackage, err := packagepkg.FindAttachableMainPackageForAddon(tx, carrierType, carrierID, now)
	if err == gorm.ErrRecordNotFound {
		return errors.New(errors.CodeInvalidParam, "必须有主套餐才能购买加油包")
	}
	if err != nil {
		return errors.Wrap(errors.CodeDatabaseError, err, "查询主套餐失败")
	}

	// 任务 8.7: 创建加油包，绑定到主套餐
	// 查询当前最大优先级（加油包优先级低于主套餐）
	var maxPriority int
	tx.Model(&model.PackageUsage{}).
		Where(carrierType+"_id = ?", carrierID).
		Select("COALESCE(MAX(priority), 0)").
		Scan(&maxPriority)
	priority := maxPriority + 1

	// 加油包立即生效
	status := constants.PackageUsageStatusActive
	activatedAt := now

	// 计算过期时间（根据 has_independent_expiry）
	var expiresAt time.Time
	// 注意：has_independent_expiry 字段在 Package 模型中，暂时使用默认行为
	// 默认加油包跟随主套餐过期
	if mainPackage.ExpiresAt != nil {
		expiresAt = *mainPackage.ExpiresAt
	} else {
		expiresAt = now
	}

	virtualTotalMBSnapshot, displayGainRatioSnapshot, enableVirtualDataSnapshot := model.BuildPackageUsageSnapshotValues(pkg)
	addonRetailAmount := order.TotalAmount
	usage := &model.PackageUsage{
		BaseModel: model.BaseModel{
			Creator: order.Creator,
			Updater: order.Creator,
		},
		OrderID:                   order.ID,
		OrderNo:                   order.OrderNo,
		PackageID:                 pkg.ID,
		PackageName:               pkg.PackageName,
		UsageType:                 order.OrderType,
		DataLimitMB:               pkg.RealDataMB,
		VirtualTotalMBSnapshot:    virtualTotalMBSnapshot,
		DisplayGainRatioSnapshot:  displayGainRatioSnapshot,
		EnableVirtualDataSnapshot: enableVirtualDataSnapshot,
		Status:                    status,
		Priority:                  priority,
		MasterUsageID:             &mainPackage.ID,
		ActivatedAt:               &activatedAt,
		ExpiresAt:                 &expiresAt,
		DataResetCycle:            pkg.DataResetCycle,
		PaidAmount:                order.ActualPaidAmount,
		RetailAmount:              &addonRetailAmount,
		PackagePriceConfigStatus:  pkg.PriceConfigStatus,
		PackageIsGift:             pkg.IsGift,
	}
	terms.Apply(usage)

	if carrierType == "iot_card" {
		usage.IotCardID = carrierID
	} else {
		usage.DeviceID = carrierID
	}

	// 创建加油包使用记录（加油包 status=1，不需要处理零值）
	if err := tx.Create(usage).Error; err != nil {
		return errors.Wrap(errors.CodeDatabaseError, err, "创建加油包使用记录失败")
	}

	return nil
}

func (s *Service) resolvePackageTerms(ctx context.Context, tx *gorm.DB, pkg *model.Package, sellerShopID *uint) (packagedomain.TermsSnapshot, error) {
	return packagepkg.ResolveTermsFromTx(ctx, tx, pkg, sellerShopID)
}

func (s *Service) enqueueCommissionCalculation(ctx context.Context, orderID uint) {
	if s.queueClient == nil {
		s.logger.Warn("队列客户端未初始化，跳过佣金计算任务入队", zap.Uint("order_id", orderID))
		return
	}

	// 直接传 map，由 EnqueueTask 内部统一序列化一次（传 []byte 会导致 sonic.Marshal 二次 base64 编码）
	if err := s.queueClient.EnqueueTask(ctx, constants.TaskTypeCommission, map[string]any{"order_id": orderID}); err != nil {
		s.logger.Error("佣金计算任务入队失败",
			zap.Uint("order_id", orderID),
			zap.Error(err),
			zap.String("task_type", constants.TaskTypeCommission))
		return
	}

	s.logger.Info("佣金计算任务已入队",
		zap.Uint("order_id", orderID),
		zap.String("task_type", constants.TaskTypeCommission))
}

func (s *Service) buildOrderResponse(ctx context.Context, order *model.Order, items []*model.OrderItem) *dto.OrderResponse {
	var itemResponses []*dto.OrderItemResponse
	for _, item := range items {
		itemResponses = append(itemResponses, &dto.OrderItemResponse{
			ID:          item.ID,
			PackageID:   item.PackageID,
			PackageName: item.PackageName,
			PackageType: item.PackageType,
			Quantity:    item.Quantity,
			UnitPrice:   item.UnitPrice,
			Amount:      item.Amount,
		})
	}

	statusText := ""
	switch order.PaymentStatus {
	case model.PaymentStatusPending:
		statusText = "待支付"
	case model.PaymentStatusPaid:
		statusText = "已支付"
	case model.PaymentStatusCancelled:
		statusText = "已取消"
	case model.PaymentStatusRefunded:
		statusText = "已退款"
	}

	operatorID, operatorType, operatorName := s.resolveOrderOperatorView(ctx, order)
	sellerShopName := s.resolveSellerShopName(ctx, order.SellerShopID)

	// 生成派生字段
	isPurchasedByParent := order.PurchaseRole == model.PurchaseRolePurchasedByParent
	purchaseRemark := ""
	switch order.PurchaseRole {
	case model.PurchaseRolePurchasedByParent:
		if operatorName != "" {
			purchaseRemark = fmt.Sprintf("由上级代理【%s】购买", operatorName)
		} else {
			purchaseRemark = "由上级代理购买"
		}
	case model.PurchaseRolePurchasedByPlatform:
		purchaseRemark = "由平台代购"
	case model.PurchaseRolePurchaseForSubordinate:
		if operatorName != "" {
			purchaseRemark = fmt.Sprintf("由【%s】为下级购买", operatorName)
		}
	}

	assetType := ""
	if order.OrderType == model.OrderTypeSingleCard {
		assetType = "card"
	} else if order.OrderType == model.OrderTypeDevice {
		assetType = "device"
	}

	actualPaidAmount := order.ActualPaidAmount
	if actualPaidAmount == nil && order.PaymentStatus == model.PaymentStatusPaid {
		actualPaidAmountSnapshot := order.TotalAmount
		actualPaidAmount = &actualPaidAmountSnapshot
	}
	commissionResult := s.resolveOrderCommissionResult(ctx, order)

	return &dto.OrderResponse{
		ID:                      order.ID,
		OrderNo:                 order.OrderNo,
		OrderType:               order.OrderType,
		BuyerType:               order.BuyerType,
		BuyerID:                 order.BuyerID,
		BuyerPhone:              order.BuyerPhone,
		BuyerNickname:           order.BuyerNickname,
		IotCardID:               order.IotCardID,
		DeviceID:                order.DeviceID,
		TotalAmount:             order.TotalAmount,
		PaymentMethod:           order.PaymentMethod,
		PaymentStatus:           order.PaymentStatus,
		PaymentStatusText:       statusText,
		PaidAt:                  order.PaidAt,
		PaymentVoucherKey:       []string(order.PaymentVoucherKey),
		IsPurchaseOnBehalf:      order.IsPurchaseOnBehalf,
		CommissionStatus:        order.CommissionStatus,
		CommissionStatusName:    constants.GetOrderCommissionStatusName(order.CommissionStatus),
		CommissionResult:        commissionResult,
		CommissionResultName:    constants.GetOrderCommissionResultName(commissionResult),
		CommissionConfigVersion: order.CommissionConfigVersion,
		SellerShopID:            order.SellerShopID,
		SellerShopName:          sellerShopName,

		OperatorID:       operatorID,
		OperatorType:     operatorType,
		OperatorName:     operatorName,
		ActualPaidAmount: actualPaidAmount,

		PurchaseRole:        order.PurchaseRole,
		IsPurchasedByParent: isPurchasedByParent,
		PurchaseRemark:      purchaseRemark,

		Items:     itemResponses,
		CreatedAt: order.CreatedAt,
		UpdatedAt: order.UpdatedAt,

		ExpiresAt: order.ExpiresAt,
		IsExpired: order.ExpiresAt != nil && order.PaymentStatus == model.PaymentStatusPending && time.Now().After(*order.ExpiresAt),

		AssetIdentifier: order.AssetIdentifier,
		AssetType:       assetType,
	}
}

func (s *Service) resolveOrderOperatorView(ctx context.Context, order *model.Order) (*uint, string, string) {
	if order.OperatorAccountID != nil || order.OperatorAccountType != "" || order.OperatorAccountName != "" {
		return order.OperatorAccountID, order.OperatorAccountType, order.OperatorAccountName
	}

	if order.Source == constants.OrderSourceClient && order.BuyerType == model.BuyerTypePersonal {
		operatorID, operatorType, operatorName := s.buildPersonalCustomerOperatorSnapshot(ctx, order.BuyerID, order.BuyerNickname)
		if operatorID != nil || operatorType != "" || operatorName != "" {
			return operatorID, operatorType, operatorName
		}
	}

	if order.Creator > 0 {
		operatorID, operatorType, operatorName := s.buildAccountOperatorSnapshot(ctx, order.Creator, 0)
		if operatorID != nil || operatorType != "" || operatorName != "" {
			return operatorID, operatorType, operatorName
		}
	}

	if order.OperatorType == model.OperatorAccountTypeAgent && order.OperatorID != nil {
		return nil, model.OperatorAccountTypeAgent, s.resolveLegacyOperatorShopName(ctx, *order.OperatorID)
	}

	if order.OperatorType == model.OperatorAccountTypePlatform {
		return nil, model.OperatorAccountTypePlatform, "平台"
	}

	return nil, "", ""
}

func (s *Service) resolveLegacyOperatorShopName(ctx context.Context, shopID uint) string {
	if shopID == 0 {
		return ""
	}

	var shop model.Shop
	if err := s.db.WithContext(ctx).Where("id = ?", shopID).First(&shop).Error; err != nil {
		return ""
	}
	return shop.ShopName
}

func (s *Service) resolveSellerShopName(ctx context.Context, sellerShopID *uint) string {
	if sellerShopID == nil || *sellerShopID == 0 {
		return ""
	}

	var shop model.Shop
	if err := s.db.WithContext(ctx).Where("id = ?", *sellerShopID).First(&shop).Error; err != nil {
		return ""
	}
	return shop.ShopName
}

func (s *Service) resolveOrderCommissionResult(ctx context.Context, order *model.Order) int {
	if order.CommissionResult != model.CommissionResultUnknown {
		return order.CommissionResult
	}

	if order.CommissionStatus == model.CommissionStatusPending {
		return model.CommissionResultUnknown
	}

	var pendingReviewCount int64
	if err := s.db.WithContext(ctx).Model(&model.CommissionRecord{}).
		Where("order_id = ? AND status = ?", order.ID, constants.CommissionStatusPendingReview).
		Count(&pendingReviewCount).Error; err == nil && pendingReviewCount > 0 {
		return model.CommissionResultChainBroken
	}

	var releasedCount int64
	if err := s.db.WithContext(ctx).Model(&model.CommissionRecord{}).
		Where("order_id = ? AND status = ? AND amount > 0", order.ID, constants.CommissionStatusReleased).
		Count(&releasedCount).Error; err == nil && releasedCount > 0 {
		return model.CommissionResultHasAmount
	}

	if order.CommissionStatus == model.CommissionStatusCompleted {
		return model.CommissionResultNoAmount
	}

	return model.CommissionResultUnknown
}

// WechatPayJSAPI 发起微信 JSAPI 支付
// 通过 order.PaymentConfigID 动态加载支付配置，支持多商户场景
func (s *Service) WechatPayJSAPI(ctx context.Context, orderID uint, openID string, buyerType string, buyerID uint) (*dto.WechatPayJSAPIResponse, error) {
	order, err := s.orderStore.GetByID(ctx, orderID)
	if err != nil {
		if err == gorm.ErrRecordNotFound {
			return nil, errors.New(errors.CodeNotFound, "订单不存在")
		}
		return nil, errors.Wrap(errors.CodeInternalError, err, "查询订单失败")
	}

	if order.BuyerType != buyerType || order.BuyerID != buyerID {
		return nil, errors.New(errors.CodeForbidden, "无权操作此订单")
	}

	if order.PaymentStatus != model.PaymentStatusPending {
		return nil, errors.New(errors.CodeInvalidStatus, "订单状态不允许支付")
	}

	// 按 payment_config_id 动态加载支付配置
	if order.PaymentConfigID == nil {
		s.logger.Error("订单缺少支付配置", zap.Uint("order_id", orderID))
		return nil, errors.New(errors.CodeWechatConfigNotFound, "订单缺少支付配置")
	}
	paymentSvc, err := s.paymentLoader.LoadConfig(ctx, *order.PaymentConfigID)
	if err != nil {
		return nil, err
	}

	items, err := s.orderItemStore.ListByOrderIDs(ctx, []uint{orderID})
	if err != nil {
		return nil, errors.Wrap(errors.CodeInternalError, err, "查询订单明细失败")
	}
	description := "套餐购买"
	if len(items) > 0 {
		description = items[0].PackageName
	}

	result, err := paymentSvc.CreateJSAPIOrder(ctx, order.OrderNo, description, openID, int(order.TotalAmount))
	if err != nil {
		s.logger.Error("创建 JSAPI 支付失败",
			zap.Uint("order_id", orderID),
			zap.String("order_no", order.OrderNo),
			zap.Error(err),
		)
		return nil, err
	}

	s.logger.Info("创建 JSAPI 支付成功",
		zap.Uint("order_id", orderID),
		zap.String("order_no", order.OrderNo),
		zap.String("prepay_id", result.PrepayID),
	)

	payConfig, _ := result.PayConfig.(map[string]interface{})
	return &dto.WechatPayJSAPIResponse{
		PrepayID:  result.PrepayID,
		PayConfig: payConfig,
	}, nil
}

// WechatPayH5 发起微信 H5 支付
// 通过 order.PaymentConfigID 动态加载支付配置，支持多商户场景
func (s *Service) WechatPayH5(ctx context.Context, orderID uint, sceneInfo *dto.WechatH5SceneInfo, buyerType string, buyerID uint) (*dto.WechatPayH5Response, error) {
	order, err := s.orderStore.GetByID(ctx, orderID)
	if err != nil {
		if err == gorm.ErrRecordNotFound {
			return nil, errors.New(errors.CodeNotFound, "订单不存在")
		}
		return nil, errors.Wrap(errors.CodeInternalError, err, "查询订单失败")
	}

	if order.BuyerType != buyerType || order.BuyerID != buyerID {
		return nil, errors.New(errors.CodeForbidden, "无权操作此订单")
	}

	if order.PaymentStatus != model.PaymentStatusPending {
		return nil, errors.New(errors.CodeInvalidStatus, "订单状态不允许支付")
	}

	// 按 payment_config_id 动态加载支付配置
	if order.PaymentConfigID == nil {
		s.logger.Error("订单缺少支付配置", zap.Uint("order_id", orderID))
		return nil, errors.New(errors.CodeWechatConfigNotFound, "订单缺少支付配置")
	}
	paymentSvc, err := s.paymentLoader.LoadConfig(ctx, *order.PaymentConfigID)
	if err != nil {
		return nil, err
	}

	items, err := s.orderItemStore.ListByOrderIDs(ctx, []uint{orderID})
	if err != nil {
		return nil, errors.Wrap(errors.CodeInternalError, err, "查询订单明细失败")
	}
	description := "套餐购买"
	if len(items) > 0 {
		description = items[0].PackageName
	}

	h5SceneInfo := &wechat.H5SceneInfo{
		PayerClientIP: sceneInfo.PayerClientIP,
		H5Type:        sceneInfo.H5Info.Type,
	}

	result, err := paymentSvc.CreateH5Order(ctx, order.OrderNo, description, int(order.TotalAmount), h5SceneInfo)
	if err != nil {
		s.logger.Error("创建 H5 支付失败",
			zap.Uint("order_id", orderID),
			zap.String("order_no", order.OrderNo),
			zap.Error(err),
		)
		return nil, err
	}

	s.logger.Info("创建 H5 支付成功",
		zap.Uint("order_id", orderID),
		zap.String("order_no", order.OrderNo),
		zap.String("h5_url", result.H5URL),
	)

	return &dto.WechatPayH5Response{
		H5URL: result.H5URL,
	}, nil
}

type ForceRechargeRequirement struct {
	NeedForceRecharge   bool
	ForceRechargeAmount int64
	TriggerType         string
}

// checkForceRechargeRequirement 检查强充要求
// 从 PackageSeries 获取一次性佣金配置，使用 per-series 追踪判断是否需要强充
func (s *Service) checkForceRechargeRequirement(ctx context.Context, result *purchase_validation.PurchaseValidationResult) *ForceRechargeRequirement {
	defaultResult := &ForceRechargeRequirement{NeedForceRecharge: false}

	// 1. 获取 seriesID 和卖家店铺 ID
	var seriesID *uint
	var firstCommissionPaid bool
	var sellerShopID uint

	if result.Card != nil {
		seriesID = result.Card.SeriesID
		if seriesID != nil {
			firstCommissionPaid = result.Card.IsFirstRechargeTriggeredBySeries(*seriesID)
		}
		if result.Card.ShopID != nil {
			sellerShopID = *result.Card.ShopID
		}
	} else if result.Device != nil {
		seriesID = result.Device.SeriesID
		if seriesID != nil {
			firstCommissionPaid = result.Device.IsFirstRechargeTriggeredBySeries(*seriesID)
		}
		if result.Device.ShopID != nil {
			sellerShopID = *result.Device.ShopID
		}
	}

	if seriesID == nil {
		return defaultResult
	}

	// 2. 从 PackageSeries 获取一次性佣金配置
	series, err := s.packageSeriesStore.GetByID(ctx, *seriesID)
	if err != nil {
		s.logger.Warn("查询套餐系列失败", zap.Uint("series_id", *seriesID), zap.Error(err))
		return defaultResult
	}

	config, err := series.GetOneTimeCommissionConfig()
	if err != nil || config == nil || !config.Enable {
		return defaultResult
	}

	// 3. 如果该系列的一次性佣金已发放，无需强充
	if firstCommissionPaid {
		return defaultResult
	}

	// 4. 根据触发类型判断是否需要强充
	if config.TriggerType == model.OneTimeCommissionTriggerFirstRecharge {
		return &ForceRechargeRequirement{
			NeedForceRecharge:   true,
			ForceRechargeAmount: config.Threshold,
			TriggerType:         model.OneTimeCommissionTriggerFirstRecharge,
		}
	}

	// 5. 累计充值模式，检查平台是否启用强充
	if config.EnableForceRecharge {
		forceAmount := config.ForceAmount
		if forceAmount == 0 {
			forceAmount = config.Threshold
		}
		return &ForceRechargeRequirement{
			NeedForceRecharge:   true,
			ForceRechargeAmount: forceAmount,
			TriggerType:         model.OneTimeCommissionTriggerAccumulatedRecharge,
		}
	}

	// 6. 平台未设强充，查询卖家代理的 ShopSeriesAllocation，判断代理是否自设强充
	// 仅在累计充值模式且平台未启用时，代理强充配置才生效
	if sellerShopID > 0 {
		agentAllocation, allocErr := s.shopSeriesAllocationStore.GetByShopAndSeries(ctx, sellerShopID, *seriesID)
		if allocErr == nil && agentAllocation.EnableForceRecharge {
			agentForceAmount := agentAllocation.ForceRechargeAmount
			if agentForceAmount == 0 {
				agentForceAmount = config.Threshold
			}
			return &ForceRechargeRequirement{
				NeedForceRecharge:   true,
				ForceRechargeAmount: agentForceAmount,
				TriggerType:         model.OneTimeCommissionTriggerAccumulatedRecharge,
			}
		}
	}

	return defaultResult
}

func (s *Service) GetPurchaseCheck(ctx context.Context, req *dto.PurchaseCheckRequest) (*dto.PurchaseCheckResponse, error) {
	var validationResult *purchase_validation.PurchaseValidationResult
	var err error

	if req.OrderType == model.OrderTypeSingleCard {
		validationResult, err = s.purchaseValidationService.ValidateCardPurchase(ctx, req.ResourceID, req.PackageIDs)
	} else if req.OrderType == model.OrderTypeDevice {
		validationResult, err = s.purchaseValidationService.ValidateDevicePurchase(ctx, req.ResourceID, req.PackageIDs)
	} else {
		return nil, errors.New(errors.CodeInvalidParam, "无效的订单类型")
	}

	if err != nil {
		return nil, err
	}

	forceRechargeCheck := s.checkForceRechargeRequirement(ctx, validationResult)

	response := &dto.PurchaseCheckResponse{
		TotalPackageAmount:  validationResult.TotalPrice,
		NeedForceRecharge:   forceRechargeCheck.NeedForceRecharge,
		ForceRechargeAmount: forceRechargeCheck.ForceRechargeAmount,
		ActualPayment:       validationResult.TotalPrice,
		WalletCredit:        validationResult.TotalPrice,
	}

	if forceRechargeCheck.NeedForceRecharge {
		if validationResult.TotalPrice < forceRechargeCheck.ForceRechargeAmount {
			response.ActualPayment = forceRechargeCheck.ForceRechargeAmount
			response.WalletCredit = forceRechargeCheck.ForceRechargeAmount
			response.Message = "首次购买需满足最低充值要求"
		}
	}

	return response, nil
}

func (s *Service) FuiouPayJSAPI(ctx context.Context, orderID uint, openID string, buyerType string, buyerID uint) (*dto.FuiouPayJSAPIResponse, error) {
	return s.fuiouPreCreate(ctx, orderID, openID, buyerType, buyerID, "JSAPI", false)
}

func (s *Service) FuiouPayMiniApp(ctx context.Context, orderID uint, openID string, buyerType string, buyerID uint) (*dto.FuiouPayJSAPIResponse, error) {
	return s.fuiouPreCreate(ctx, orderID, openID, buyerType, buyerID, "LETPAY", true)
}

func (s *Service) fuiouPreCreate(
	ctx context.Context,
	orderID uint,
	openID string,
	buyerType string,
	buyerID uint,
	tradeType string,
	useMiniappAppID bool,
) (*dto.FuiouPayJSAPIResponse, error) {
	if strings.TrimSpace(openID) == "" {
		return nil, errors.New(errors.CodeInvalidParam, "openID 不能为空")
	}

	order, err := s.orderStore.GetByID(ctx, orderID)
	if err != nil {
		if err == gorm.ErrRecordNotFound {
			return nil, errors.New(errors.CodeNotFound, "订单不存在")
		}
		return nil, errors.Wrap(errors.CodeInternalError, err, "查询订单失败")
	}

	if order.BuyerType != buyerType || order.BuyerID != buyerID {
		return nil, errors.New(errors.CodeForbidden, "无权操作此订单")
	}

	if order.PaymentStatus != model.PaymentStatusPending {
		return nil, errors.New(errors.CodeInvalidStatus, "订单状态不允许支付")
	}

	activeConfig, err := s.wechatConfigService.GetActiveConfig(ctx)
	if err != nil {
		return nil, errors.Wrap(errors.CodeFuiouPayFailed, err, "查询生效支付配置失败")
	}
	if activeConfig == nil || activeConfig.ProviderType != model.ProviderTypeFuiou {
		return nil, errors.New(errors.CodeFuiouPayFailed, "未找到生效的富友支付配置")
	}

	subAppID := activeConfig.OaAppID
	if useMiniappAppID {
		subAppID = activeConfig.MiniappAppID
	}

	if strings.TrimSpace(activeConfig.FyInsCd) == "" ||
		strings.TrimSpace(activeConfig.FyMchntCd) == "" ||
		strings.TrimSpace(activeConfig.FyTermID) == "" ||
		strings.TrimSpace(activeConfig.FyPrivateKey) == "" ||
		strings.TrimSpace(activeConfig.FyPublicKey) == "" ||
		strings.TrimSpace(activeConfig.FyAPIURL) == "" ||
		strings.TrimSpace(activeConfig.FyNotifyURL) == "" ||
		strings.TrimSpace(subAppID) == "" {
		return nil, errors.New(errors.CodeFuiouPayFailed, "富友支付配置不完整")
	}

	client, err := fuiou.NewClient(
		activeConfig.FyInsCd,
		activeConfig.FyMchntCd,
		activeConfig.FyTermID,
		activeConfig.FyAPIURL,
		activeConfig.FyNotifyURL,
		activeConfig.FyPrivateKey,
		activeConfig.FyPublicKey,
		s.logger,
	)
	if err != nil {
		return nil, errors.Wrap(errors.CodeFuiouPayFailed, err, "创建富友支付客户端失败")
	}

	items, err := s.orderItemStore.ListByOrderIDs(ctx, []uint{orderID})
	if err != nil {
		return nil, errors.Wrap(errors.CodeInternalError, err, "查询订单明细失败")
	}
	description := "套餐购买"
	if len(items) > 0 {
		description = items[0].PackageName
	}

	termIP := "127.0.0.1"
	if ip := middleware.GetIPFromContext(ctx); ip != nil && strings.TrimSpace(*ip) != "" {
		termIP = *ip
	}

	resp, err := client.WxPreCreate(
		order.OrderNo,
		strconv.FormatInt(order.TotalAmount, 10),
		description,
		termIP,
		tradeType,
		subAppID,
		openID,
	)
	if err != nil {
		s.logger.Error("富友预下单失败",
			zap.Uint("order_id", orderID),
			zap.String("order_no", order.OrderNo),
			zap.String("trade_type", tradeType),
			zap.Error(err),
		)
		return nil, errors.Wrap(errors.CodeFuiouPayFailed, err, "富友预下单失败")
	}

	s.logger.Info("富友预下单成功",
		zap.Uint("order_id", orderID),
		zap.String("order_no", order.OrderNo),
		zap.String("trade_type", tradeType),
	)

	return &dto.FuiouPayJSAPIResponse{
		AppID:     resp.SdkAppid,
		TimeStamp: resp.SdkTimestamp,
		NonceStr:  resp.SdkNoncestr,
		Package:   resp.SdkPackage,
		SignType:  resp.SdkSigntype,
		PaySign:   resp.SdkPaysign,
	}, nil
}
