package task

import (
	"context"
	"errors"
	"strconv"
	"time"

	"github.com/bytedance/sonic"
	"github.com/hibiken/asynq"
	"github.com/redis/go-redis/v9"
	"go.uber.org/zap"
	"gorm.io/gorm"
	"gorm.io/gorm/clause"

	cardObservationApp "github.com/break/junhong_cmp_fiber/internal/application/cardobservation"
	packagedomain "github.com/break/junhong_cmp_fiber/internal/domain/package"
	"github.com/break/junhong_cmp_fiber/internal/model"
	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/store/postgres"
	"github.com/break/junhong_cmp_fiber/pkg/constants"
	pkgerrors "github.com/break/junhong_cmp_fiber/pkg/errors"
)

// AutoPurchasePayload 充值后自动购包任务载荷
type AutoPurchasePayload struct {
	RechargeOrderID uint `json:"recharge_order_id"`
}

// AutoPurchaseHandler 充值后自动购包任务处理器
type AutoPurchaseHandler struct {
	db                         *gorm.DB
	orderStore                 *postgres.OrderStore
	rechargeOrderStore         *postgres.RechargeOrderStore
	paymentStore               *postgres.PaymentStore
	walletStore                *postgres.AssetWalletStore
	walletTransactionStore     *postgres.AssetWalletTransactionStore
	packageUsageStore          *postgres.PackageUsageStore
	shopPackageAllocationStore *postgres.ShopPackageAllocationStore // 用于查询卖家成本价
	iotCardStore               *postgres.IotCardStore               // 用于获取卡的系列ID
	deviceStore                *postgres.DeviceStore                // 用于获取设备的系列ID
	redis                      *redis.Client
	asynqClient                *asynq.Client // 用于事务提交成功后触发佣金计算任务
	logger                     *zap.Logger
	observationSeriesEvents    cardObservationApp.SeriesEventWriter
}

// NewAutoPurchaseHandler 创建充值后自动购包处理器
func NewAutoPurchaseHandler(
	db *gorm.DB,
	orderStore *postgres.OrderStore,
	rechargeOrderStore *postgres.RechargeOrderStore,
	paymentStore *postgres.PaymentStore,
	walletStore *postgres.AssetWalletStore,
	walletTransactionStore *postgres.AssetWalletTransactionStore,
	packageUsageStore *postgres.PackageUsageStore,
	redisClient *redis.Client,
	asynqClient *asynq.Client,
	logger *zap.Logger,
	observationSeriesEvents cardObservationApp.SeriesEventWriter,
) *AutoPurchaseHandler {
	if orderStore == nil {
		orderStore = postgres.NewOrderStore(db, redisClient)
	}
	if rechargeOrderStore == nil {
		rechargeOrderStore = postgres.NewRechargeOrderStore(db, redisClient)
	}
	if paymentStore == nil {
		paymentStore = postgres.NewPaymentStore(db, redisClient)
	}
	if walletStore == nil {
		walletStore = postgres.NewAssetWalletStore(db, redisClient)
	}
	if walletTransactionStore == nil {
		walletTransactionStore = postgres.NewAssetWalletTransactionStore(db, redisClient)
	}
	if packageUsageStore == nil {
		packageUsageStore = postgres.NewPackageUsageStore(db, redisClient)
	}

	return &AutoPurchaseHandler{
		db:                         db,
		orderStore:                 orderStore,
		rechargeOrderStore:         rechargeOrderStore,
		paymentStore:               paymentStore,
		walletStore:                walletStore,
		walletTransactionStore:     walletTransactionStore,
		packageUsageStore:          packageUsageStore,
		shopPackageAllocationStore: postgres.NewShopPackageAllocationStore(db),
		iotCardStore:               postgres.NewIotCardStore(db, redisClient),
		deviceStore:                postgres.NewDeviceStore(db, redisClient),
		redis:                      redisClient,
		asynqClient:                asynqClient,
		logger:                     logger,
		observationSeriesEvents:    observationSeriesEvents,
	}
}

// ProcessTask 处理充值后自动购包任务
func (h *AutoPurchaseHandler) ProcessTask(ctx context.Context, task *asynq.Task) error {
	var payload AutoPurchasePayload
	if err := sonic.Unmarshal(task.Payload(), &payload); err != nil {
		h.logger.Error("解析自动购包任务载荷失败", zap.Error(err))
		return asynq.SkipRetry
	}
	if payload.RechargeOrderID == 0 {
		h.logger.Error("自动购包任务载荷无效", zap.Uint("recharge_order_id", payload.RechargeOrderID))
		return asynq.SkipRetry
	}

	rechargeOrder, err := h.rechargeOrderStore.GetByID(ctx, payload.RechargeOrderID)
	if err != nil {
		if err == gorm.ErrRecordNotFound {
			h.logger.Warn("充值订单不存在，跳过自动购包", zap.Uint("recharge_order_id", payload.RechargeOrderID))
			return asynq.SkipRetry
		}
		h.logger.Error("查询充值订单失败", zap.Uint("recharge_order_id", payload.RechargeOrderID), zap.Error(err))
		return err
	}

	if rechargeOrder.AutoPurchaseStatus == constants.AutoPurchaseStatusSuccess {
		return nil
	}
	if rechargeOrder.AutoPurchaseStatus == constants.AutoPurchaseStatusFailed {
		return nil
	}

	packageIDs, err := parseLinkedPackageIDs(rechargeOrder.LinkedPackageIDs)
	if err != nil {
		h.logger.Error("解析关联套餐ID失败", zap.Uint("recharge_order_id", rechargeOrder.ID), zap.Error(err))
		h.markAutoPurchaseFailedIfFinalRetry(ctx, rechargeOrder.ID)
		return asynq.SkipRetry
	}
	if len(packageIDs) == 0 {
		h.logger.Error("关联套餐ID为空，无法自动购包", zap.Uint("recharge_order_id", rechargeOrder.ID))
		h.markAutoPurchaseFailedIfFinalRetry(ctx, rechargeOrder.ID)
		return asynq.SkipRetry
	}

	packages, totalAmount, err := h.loadPackages(ctx, packageIDs)
	if err != nil {
		h.logger.Error("加载关联套餐失败", zap.Uint("recharge_order_id", rechargeOrder.ID), zap.Error(err))
		h.markAutoPurchaseFailedIfFinalRetry(ctx, rechargeOrder.ID)
		return err
	}

	// 获取资产系列ID，用于差价佣金和一次性佣金计算
	var seriesID *uint
	if rechargeOrder.LinkedCarrierID != nil && *rechargeOrder.LinkedCarrierID > 0 {
		if rechargeOrder.LinkedCarrierType == "card" || rechargeOrder.LinkedCarrierType == constants.AssetWalletResourceTypeIotCard {
			if card, cardErr := h.iotCardStore.GetByID(ctx, *rechargeOrder.LinkedCarrierID); cardErr == nil {
				seriesID = card.SeriesID
			} else {
				h.logger.Warn("自动购包获取卡系列ID失败",
					zap.Uint("card_id", *rechargeOrder.LinkedCarrierID),
					zap.Error(cardErr))
			}
		} else if rechargeOrder.LinkedCarrierType == "device" || rechargeOrder.LinkedCarrierType == constants.AssetWalletResourceTypeDevice {
			if device, deviceErr := h.deviceStore.GetByID(ctx, *rechargeOrder.LinkedCarrierID); deviceErr == nil {
				seriesID = device.SeriesID
			} else {
				h.logger.Warn("自动购包获取设备系列ID失败",
					zap.Uint("device_id", *rechargeOrder.LinkedCarrierID),
					zap.Error(deviceErr))
			}
		}
	}

	// 获取卖家成本价，用于差价佣金链式计算的起点
	// 平台直销（ShopIDTag == 0）时成本价为 0，差价佣金计算会直接跳过
	var sellerCostPrice int64
	if rechargeOrder.ShopIDTag > 0 && len(packages) > 0 {
		allocation, allocErr := h.shopPackageAllocationStore.GetByShopAndPackageForSystem(ctx, rechargeOrder.ShopIDTag, packages[0].ID)
		if allocErr == nil {
			sellerCostPrice = allocation.CostPrice
		} else {
			h.logger.Warn("自动购包获取卖家成本价失败，差价佣金将计算为0",
				zap.Uint("shop_id", rechargeOrder.ShopIDTag),
				zap.Uint("package_id", packages[0].ID),
				zap.Error(allocErr))
		}
	}

	var createdOrderID uint
	if err := h.db.WithContext(ctx).Transaction(func(tx *gorm.DB) error {
		wallet, walletErr := h.walletStore.GetByID(ctx, rechargeOrder.AssetWalletID)
		if walletErr != nil {
			if walletErr == gorm.ErrRecordNotFound {
				return errors.New("资产钱包不存在")
			}
			return walletErr
		}
		if wallet.GetAvailableBalance() < totalAmount {
			return errors.New("钱包余额不足")
		}

		if err = h.walletStore.DeductBalanceWithTx(ctx, tx, wallet.ID, totalAmount, wallet.Version); err != nil {
			return err
		}

		now := time.Now()
		order, orderItems, buildErr := h.buildOrderAndItems(ctx, rechargeOrder, packages, totalAmount, seriesID, sellerCostPrice, now)
		if buildErr != nil {
			return buildErr
		}

		if err = tx.Create(order).Error; err != nil {
			return err
		}
		createdOrderID = order.ID

		for _, item := range orderItems {
			item.OrderID = order.ID
		}
		if err = tx.CreateInBatches(orderItems, 100).Error; err != nil {
			return err
		}

		payment := &model.Payment{
			PaymentNo:     order.OrderNo,
			OrderID:       order.ID,
			OrderType:     model.PaymentOrderTypePackage,
			PaymentMethod: model.PaymentByWallet,
			Amount:        totalAmount,
			Status:        model.PaymentRecordStatusPaid,
		}
		if err = tx.Create(payment).Error; err != nil {
			return err
		}

		refType := constants.ReferenceTypeOrder
		walletTx := &model.AssetWalletTransaction{
			AssetWalletID:   wallet.ID,
			ResourceType:    wallet.ResourceType,
			ResourceID:      wallet.ResourceID,
			UserID:          rechargeOrder.UserID,
			TransactionType: constants.AssetTransactionTypeDeduct,
			Amount:          -totalAmount,
			BalanceBefore:   wallet.Balance,
			BalanceAfter:    wallet.Balance - totalAmount,
			Status:          constants.TransactionStatusSuccess,
			ReferenceType:   &refType,
			ReferenceNo:     &order.OrderNo,
			Creator:         rechargeOrder.UserID,
			ShopIDTag:       wallet.ShopIDTag,
			EnterpriseIDTag: wallet.EnterpriseIDTag,
		}
		if err = h.walletTransactionStore.CreateWithTx(ctx, tx, walletTx); err != nil {
			return err
		}

		if err = h.activatePackages(ctx, tx, order, packages, now); err != nil {
			return err
		}
		if h.observationSeriesEvents == nil {
			return pkgerrors.New(pkgerrors.CodeInternalError, "自动购包观测 Outbox Writer 未配置")
		}
		resourceType, resourceID := orderObservationResource(order)
		if resourceID == 0 {
			return pkgerrors.New(pkgerrors.CodeInvalidParam, "自动购包观测事件缺少载体")
		}
		requestID := "card-observation:auto-purchase:" + strconv.FormatUint(uint64(order.ID), 10)
		if err = h.observationSeriesEvents.AppendSeriesRequested(ctx, tx, cardObservationApp.SeriesRequestedEvent{
			EventID: requestID, Scene: constants.CardObservationScenePackageChanged,
			ResourceType: resourceType, ResourceID: resourceID,
			SyncTypes: []string{constants.CardObservationSyncTypeRealname, constants.CardObservationSyncTypeTraffic, constants.CardObservationSyncTypeNetwork},
			Source:    constants.CardObservationSourceBusinessEvent, OccurredAt: now,
			RequestID: requestID, CorrelationID: requestID,
		}); err != nil {
			return err
		}

		if err = tx.Model(&model.RechargeOrder{}).
			Where("id = ?", rechargeOrder.ID).
			Update("auto_purchase_status", constants.AutoPurchaseStatusSuccess).Error; err != nil {
			return err
		}

		return nil
	}); err != nil {
		h.logger.Error("自动购包任务执行失败",
			zap.Uint("recharge_record_id", rechargeOrder.ID),
			zap.Error(err),
		)
		h.markAutoPurchaseFailedIfFinalRetry(ctx, rechargeOrder.ID)
		return err
	}

	// 事务提交成功后触发佣金计算（不在事务内，防止任务提交后事务回滚的数据一致性问题）
	if h.asynqClient != nil && createdOrderID > 0 {
		payloadBytes, marshalErr := sonic.Marshal(map[string]any{"order_id": createdOrderID})
		if marshalErr != nil {
			h.logger.Warn("佣金任务载荷序列化失败",
				zap.Uint("order_id", createdOrderID),
				zap.Error(marshalErr))
		} else {
			commissionTask := asynq.NewTask(constants.TaskTypeCommission, payloadBytes,
				asynq.MaxRetry(3),
				asynq.Queue(constants.QueueForTaskType(constants.TaskTypeCommission)),
			)
			if _, enqueueErr := h.asynqClient.EnqueueContext(ctx, commissionTask); enqueueErr != nil {
				h.logger.Warn("自动购包后提交佣金任务失败",
					zap.Uint("order_id", createdOrderID),
					zap.Error(enqueueErr))
			}
		}
	}

	h.logger.Info("自动购包任务执行成功", zap.Uint("recharge_record_id", rechargeOrder.ID))
	return nil
}

func orderObservationResource(order *model.Order) (string, uint) {
	if order != nil && order.DeviceID != nil {
		return constants.CardObservationResourceTypeDevice, *order.DeviceID
	}
	if order != nil && order.IotCardID != nil {
		return constants.CardObservationResourceTypeCard, *order.IotCardID
	}
	return "", 0
}

// NewAutoPurchaseTask 创建充值后自动购包任务
func NewAutoPurchaseTask(rechargeOrderID uint) (*asynq.Task, error) {
	payloadBytes, err := sonic.Marshal(AutoPurchasePayload{RechargeOrderID: rechargeOrderID})
	if err != nil {
		return nil, err
	}

	return asynq.NewTask(constants.TaskTypeAutoPurchaseAfterRecharge, payloadBytes,
		asynq.MaxRetry(3),
		asynq.Timeout(2*time.Minute),
		asynq.Queue(constants.QueueForTaskType(constants.TaskTypeAutoPurchaseAfterRecharge)),
	), nil
}

func (h *AutoPurchaseHandler) markAutoPurchaseFailedIfFinalRetry(ctx context.Context, rechargeOrderID uint) {
	retryCount, ok := asynq.GetRetryCount(ctx)
	if !ok {
		return
	}
	maxRetry, ok := asynq.GetMaxRetry(ctx)
	if !ok {
		return
	}
	if retryCount < maxRetry-1 {
		return
	}

	if err := h.db.WithContext(ctx).
		Model(&model.RechargeOrder{}).
		Where("id = ?", rechargeOrderID).
		Update("auto_purchase_status", constants.AutoPurchaseStatusFailed).Error; err != nil {
		h.logger.Error("更新自动购包失败状态失败",
			zap.Uint("recharge_record_id", rechargeOrderID),
			zap.Error(err),
		)
		return
	}

	h.logger.Warn("自动购包达到最大重试次数，已标记失败", zap.Uint("recharge_record_id", rechargeOrderID))
}

func (h *AutoPurchaseHandler) loadPackages(ctx context.Context, packageIDs []uint) ([]*model.Package, int64, error) {
	packages := make([]*model.Package, 0, len(packageIDs))
	if err := h.db.WithContext(ctx).Where("id IN ?", packageIDs).Find(&packages).Error; err != nil {
		return nil, 0, err
	}
	if len(packages) != len(packageIDs) {
		return nil, 0, gorm.ErrRecordNotFound
	}

	totalAmount := int64(0)
	for _, pkg := range packages {
		if pkg.IsGift {
			return nil, 0, errors.New("赠送套餐不能进入自动购包链路")
		}
		totalAmount += packageprice.PackageEffectiveRetailPrice(pkg)
	}

	if err := validatePackageTypeMix(packages); err != nil {
		return nil, 0, err
	}

	return packages, totalAmount, nil
}

func (h *AutoPurchaseHandler) buildOrderAndItems(
	ctx context.Context,
	rechargeOrder *model.RechargeOrder,
	packages []*model.Package,
	totalAmount int64,
	seriesID *uint,
	sellerCostPrice int64,
	now time.Time,
) (*model.Order, []*model.OrderItem, error) {
	orderType, iotCardID, deviceID, err := parseLinkedCarrier(rechargeOrder.LinkedOrderType, rechargeOrder.LinkedCarrierType, rechargeOrder.LinkedCarrierID)
	if err != nil {
		return nil, nil, err
	}

	generation := rechargeOrder.Generation
	if generation <= 0 {
		generation = 1
	}

	var sellerShopID *uint
	if rechargeOrder.ShopIDTag > 0 {
		shopID := rechargeOrder.ShopIDTag
		sellerShopID = &shopID
	}

	paidAmount := totalAmount
	operatorAccountID, operatorAccountName := h.buildPersonalCustomerOperatorSnapshot(ctx, rechargeOrder.UserID)
	order := &model.Order{
		BaseModel: model.BaseModel{
			Creator: rechargeOrder.UserID,
			Updater: rechargeOrder.UserID,
		},
		OrderNo:                 h.orderStore.GenerateOrderNo(),
		OrderType:               orderType,
		BuyerType:               model.BuyerTypePersonal,
		BuyerID:                 rechargeOrder.UserID,
		IotCardID:               iotCardID,
		DeviceID:                deviceID,
		TotalAmount:             totalAmount,
		PaymentMethod:           model.PaymentMethodWallet,
		PaymentStatus:           model.PaymentStatusPaid,
		PaidAt:                  &now,
		CommissionStatus:        model.CommissionStatusPending,
		CommissionConfigVersion: 0,
		Source:                  constants.OrderSourceClient,
		Generation:              generation,
		ActualPaidAmount:        &paidAmount,
		OperatorAccountID:       operatorAccountID,
		OperatorAccountType:     model.OperatorAccountTypePersonalCustomer,
		OperatorAccountName:     operatorAccountName,
		SellerShopID:            sellerShopID,
		SeriesID:                seriesID,
		SellerCostPrice:         sellerCostPrice,
	}

	items := make([]*model.OrderItem, 0, len(packages))
	for _, pkg := range packages {
		unitPrice := packageprice.PackageEffectiveRetailPrice(pkg)
		items = append(items, &model.OrderItem{
			BaseModel: model.BaseModel{
				Creator: rechargeOrder.UserID,
				Updater: rechargeOrder.UserID,
			},
			PackageID:                pkg.ID,
			PackageName:              pkg.PackageName,
			Quantity:                 1,
			UnitPrice:                unitPrice,
			Amount:                   unitPrice,
			PackagePriceConfigStatus: pkg.PriceConfigStatus,
			PackageIsGift:            pkg.IsGift,
		})
	}

	return order, items, nil
}

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

	var customer model.PersonalCustomer
	if err := h.db.WithContext(ctx).Where("id = ?", customerID).First(&customer).Error; err != nil {
		id := customerID
		return &id, ""
	}

	id := customerID
	return &id, customer.Nickname
}

func (h *AutoPurchaseHandler) activatePackages(
	ctx context.Context,
	tx *gorm.DB,
	order *model.Order,
	packages []*model.Package,
	now time.Time,
) error {
	carrierType := constants.AssetWalletResourceTypeIotCard
	carrierID := uint(0)
	if order.OrderType == model.OrderTypeSingleCard && order.IotCardID != nil {
		carrierID = *order.IotCardID
	} else if order.OrderType == model.OrderTypeDevice && order.DeviceID != nil {
		carrierType = constants.AssetWalletResourceTypeDevice
		carrierID = *order.DeviceID
	} else {
		return errors.New("无效的订单载体")
	}
	// 在查询既有记录前锁定载体，避免并发任务同时判定不存在而重复创建套餐使用记录。
	if err := h.lockPackageCarrier(ctx, tx, carrierType, carrierID); err != nil {
		return err
	}

	for _, pkg := range packages {
		var existingUsage model.PackageUsage
		err := tx.Where("order_id = ? AND package_id = ?", order.ID, pkg.ID).First(&existingUsage).Error
		if err == nil {
			continue
		}
		if err != gorm.ErrRecordNotFound {
			return err
		}

		if pkg.PackageType == constants.PackageTypeFormal {
			if err = h.activateMainPackage(ctx, tx, order, pkg, carrierType, carrierID, now); err != nil {
				return err
			}
			continue
		}
		if pkg.PackageType == constants.PackageTypeAddon {
			if err = h.activateAddonPackage(ctx, tx, order, pkg, carrierType, carrierID, now); err != nil {
				return err
			}
		}
	}

	return nil
}

func (h *AutoPurchaseHandler) activateMainPackage(
	ctx context.Context,
	tx *gorm.DB,
	order *model.Order,
	pkg *model.Package,
	carrierType string,
	carrierID uint,
	now time.Time,
) error {
	terms, err := h.resolvePackageTerms(ctx, tx, pkg, order.SellerShopID)
	if err != nil {
		h.logger.Error("自动购包生成套餐计时快照失败", zap.Uint("package_id", pkg.ID), zap.Error(err))
		return err
	}
	if err := h.lockPackageCarrier(ctx, tx, carrierType, carrierID); err != nil {
		return err
	}

	hasCurrentMain, err := packagepkg.HasCurrentMainPackageForQueue(tx.WithContext(ctx), carrierType, carrierID, now)
	if err != nil {
		return err
	}

	var status int
	var priority int
	var activatedAt time.Time
	var expiresAt time.Time
	var nextResetAt *time.Time
	var pendingRealnameActivation bool
	if terms.ExpiryBase == constants.PackageExpiryBaseFromActivation {
		realnamed, realnameErr := h.isCarrierRealnamed(ctx, tx, carrierType, carrierID)
		if realnameErr != nil {
			return realnameErr
		}
		pendingRealnameActivation = !realnamed
	}

	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 {
		priority = 1
		if pendingRealnameActivation {
			status = constants.PackageUsageStatusPending
		} else {
			status = constants.PackageUsageStatusActive
			activatedAt = now
			expiresAt = packagepkg.CalculateExpiryTime(terms.CalendarType, activatedAt, terms.DurationMonths, terms.DurationDays)
			nextResetAt = packagepkg.CalculateNextResetTime(pkg.DataResetCycle, terms.CalendarType, now, activatedAt)
		}
	}

	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,
		Generation:                order.Generation,
		PaidAmount:                order.ActualPaidAmount,
		RetailAmount:              &retailAmount,
		PackagePriceConfigStatus:  pkg.PriceConfigStatus,
		PackageIsGift:             pkg.IsGift,
	}
	terms.Apply(usage)

	if carrierType == constants.AssetWalletResourceTypeIotCard {
		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 err
	}

	return tx.Model(usage).Updates(map[string]any{
		"status":                      usage.Status,
		"pending_realname_activation": usage.PendingRealnameActivation,
	}).Error
}

// isCarrierRealnamed 查询自动购包载体是否已满足实名激活条件。
func (h *AutoPurchaseHandler) isCarrierRealnamed(ctx context.Context, tx *gorm.DB, carrierType string, carrierID uint) (bool, error) {
	switch carrierType {
	case constants.AssetWalletResourceTypeIotCard, "card":
		var card model.IotCard
		if err := tx.WithContext(ctx).Select("real_name_status").First(&card, carrierID).Error; err != nil {
			return false, err
		}
		return card.RealNameStatus == constants.RealNameStatusVerified, nil
	case constants.AssetWalletResourceTypeDevice:
		var count int64
		subQuery := tx.WithContext(ctx).Model(&model.DeviceSimBinding{}).
			Select("iot_card_id").Where("device_id = ? AND bind_status = ?", carrierID, constants.BindStatusBound)
		if err := tx.WithContext(ctx).Model(&model.IotCard{}).
			Where("id IN (?) AND real_name_status = ?", subQuery, constants.RealNameStatusVerified).
			Count(&count).Error; err != nil {
			return false, err
		}
		return count > 0, nil
	default:
		return false, pkgerrors.New(pkgerrors.CodeInvalidParam, "无效的套餐载体类型")
	}
}

func (h *AutoPurchaseHandler) lockPackageCarrier(ctx context.Context, tx *gorm.DB, carrierType string, carrierID uint) error {
	switch carrierType {
	case constants.AssetWalletResourceTypeIotCard, "card":
		var card model.IotCard
		return tx.WithContext(ctx).Clauses(clause.Locking{Strength: "UPDATE"}).First(&card, carrierID).Error
	case constants.AssetWalletResourceTypeDevice:
		var device model.Device
		return tx.WithContext(ctx).Clauses(clause.Locking{Strength: "UPDATE"}).First(&device, carrierID).Error
	default:
		return errors.New("无效的套餐载体类型")
	}
}

func (h *AutoPurchaseHandler) activateAddonPackage(
	ctx context.Context,
	tx *gorm.DB,
	order *model.Order,
	pkg *model.Package,
	carrierType string,
	carrierID uint,
	now time.Time,
) error {
	terms, err := h.resolvePackageTerms(ctx, tx, pkg, order.SellerShopID)
	if err != nil {
		h.logger.Error("自动购包生成加油包计时快照失败", zap.Uint("package_id", pkg.ID), zap.Error(err))
		return err
	}
	mainPackage, err := packagepkg.FindAttachableMainPackageForAddon(tx, carrierType, carrierID, now)
	if err == gorm.ErrRecordNotFound {
		return errors.New("必须有主套餐才能购买加油包")
	}
	if err != nil {
		return err
	}

	var maxPriority int
	tx.Model(&model.PackageUsage{}).
		Where(carrierType+"_id = ?", carrierID).
		Select("COALESCE(MAX(priority), 0)").
		Scan(&maxPriority)

	priority := maxPriority + 1
	expiresAt := mainPackage.ExpiresAt

	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:                    constants.PackageUsageStatusActive,
		Priority:                  priority,
		MasterUsageID:             &mainPackage.ID,
		ActivatedAt:               &now,
		ExpiresAt:                 expiresAt,
		DataResetCycle:            pkg.DataResetCycle,
		Generation:                order.Generation,
		PaidAmount:                order.ActualPaidAmount,
		RetailAmount:              &addonRetailAmount,
		PackagePriceConfigStatus:  pkg.PriceConfigStatus,
		PackageIsGift:             pkg.IsGift,
	}
	terms.Apply(usage)

	if carrierType == constants.AssetWalletResourceTypeIotCard {
		usage.IotCardID = carrierID
	} else {
		usage.DeviceID = carrierID
	}

	return tx.Create(usage).Error
}

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

func parseLinkedPackageIDs(raw []byte) ([]uint, error) {
	var packageIDs []uint
	if len(raw) == 0 {
		return nil, nil
	}
	if err := sonic.Unmarshal(raw, &packageIDs); err != nil {
		return nil, err
	}
	return packageIDs, nil
}

func parseLinkedCarrier(linkedOrderType string, linkedCarrierType string, linkedCarrierID *uint) (string, *uint, *uint, error) {
	if linkedCarrierID == nil || *linkedCarrierID == 0 {
		return "", nil, nil, errors.New("关联载体ID为空")
	}

	if linkedOrderType == model.OrderTypeSingleCard || linkedCarrierType == "card" || linkedCarrierType == constants.AssetWalletResourceTypeIotCard {
		id := *linkedCarrierID
		return model.OrderTypeSingleCard, &id, nil, nil
	}
	if linkedOrderType == model.OrderTypeDevice || linkedCarrierType == "device" || linkedCarrierType == constants.AssetWalletResourceTypeDevice {
		id := *linkedCarrierID
		return model.OrderTypeDevice, nil, &id, nil
	}

	return "", nil, nil, errors.New("关联载体类型无效")
}

func validatePackageTypeMix(packages []*model.Package) error {
	hasFormal := false
	hasAddon := false

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

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

	return nil
}
