package shop_commission

import (
	"context"
	"encoding/json"
	"fmt"
	"math/rand"
	"time"

	"github.com/break/junhong_cmp_fiber/internal/model"
	"github.com/break/junhong_cmp_fiber/internal/model/dto"
	"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/middleware"
	"go.uber.org/zap"
	"gorm.io/gorm"
)

// Service 代理商资金管理服务
type Service struct {
	shopStore                        *postgres.ShopStore
	accountStore                     *postgres.AccountStore
	agentWalletStore                 *postgres.AgentWalletStore
	commissionWithdrawalReqStore     *postgres.CommissionWithdrawalRequestStore
	commissionWithdrawalSettingStore *postgres.CommissionWithdrawalSettingStore
	commissionRecordStore            *postgres.CommissionRecordStore
	agentWalletTransactionStore      *postgres.AgentWalletTransactionStore
	db                               *gorm.DB
	logger                           *zap.Logger
}

// New 创建代理商资金管理服务
func New(
	shopStore *postgres.ShopStore,
	accountStore *postgres.AccountStore,
	agentWalletStore *postgres.AgentWalletStore,
	commissionWithdrawalReqStore *postgres.CommissionWithdrawalRequestStore,
	commissionWithdrawalSettingStore *postgres.CommissionWithdrawalSettingStore,
	commissionRecordStore *postgres.CommissionRecordStore,
	agentWalletTransactionStore *postgres.AgentWalletTransactionStore,
	db *gorm.DB,
	logger *zap.Logger,
) *Service {
	return &Service{
		shopStore:                        shopStore,
		accountStore:                     accountStore,
		agentWalletStore:                 agentWalletStore,
		commissionWithdrawalReqStore:     commissionWithdrawalReqStore,
		commissionWithdrawalSettingStore: commissionWithdrawalSettingStore,
		commissionRecordStore:            commissionRecordStore,
		agentWalletTransactionStore:      agentWalletTransactionStore,
		db:                               db,
		logger:                           logger,
	}
}

// ListShopWithdrawalRequests 查询代理商提现记录
// GET /shops/:id/withdrawal-requests
func (s *Service) ListShopWithdrawalRequests(ctx context.Context, shopID uint, req *dto.ShopWithdrawalRequestListReq) (*dto.ShopWithdrawalRequestPageResult, error) {
	// 越权校验：平台人员可查所有，代理只能查自己和下级
	if err := middleware.CanManageShop(ctx, shopID); err != nil {
		return nil, errors.New(errors.CodeForbidden, "无权限操作该资源或资源不存在")
	}

	_, err := s.shopStore.GetByID(ctx, shopID)
	if err != nil {
		return nil, errors.New(errors.CodeShopNotFound, "店铺不存在")
	}

	opts := &store.QueryOptions{
		Page:     req.Page,
		PageSize: req.PageSize,
		OrderBy:  "created_at DESC",
	}
	if opts.Page == 0 {
		opts.Page = 1
	}
	if opts.PageSize == 0 {
		opts.PageSize = constants.DefaultPageSize
	}

	filters := &postgres.WithdrawalRequestListFilters{
		ShopID:       shopID,
		WithdrawalNo: req.WithdrawalNo,
	}

	if req.StartTime != "" {
		t, err := time.Parse("2006-01-02 15:04:05", req.StartTime)
		if err == nil {
			filters.StartTime = &t
		}
	}
	if req.EndTime != "" {
		t, err := time.Parse("2006-01-02 15:04:05", req.EndTime)
		if err == nil {
			filters.EndTime = &t
		}
	}

	requests, total, err := s.commissionWithdrawalReqStore.ListByShopID(ctx, opts, filters)
	if err != nil {
		return nil, errors.Wrap(errors.CodeInternalError, err, "查询提现记录失败")
	}

	shop, _ := s.shopStore.GetByID(ctx, shopID)
	shopHierarchy := s.buildShopHierarchyPath(ctx, shop)

	applicantIDs := make([]uint, 0)
	processorIDs := make([]uint, 0)
	for _, r := range requests {
		if r.ApplicantID > 0 {
			applicantIDs = append(applicantIDs, r.ApplicantID)
		}
		if r.ProcessorID > 0 {
			processorIDs = append(processorIDs, r.ProcessorID)
		}
	}

	applicantMap := make(map[uint]string)
	processorMap := make(map[uint]string)

	if len(applicantIDs) > 0 {
		accounts, _ := s.accountStore.GetByIDs(ctx, applicantIDs)
		for _, acc := range accounts {
			applicantMap[acc.ID] = acc.Username
		}
	}
	if len(processorIDs) > 0 {
		accounts, _ := s.accountStore.GetByIDs(ctx, processorIDs)
		for _, acc := range accounts {
			processorMap[acc.ID] = acc.Username
		}
	}

	items := make([]dto.ShopWithdrawalRequestItem, 0, len(requests))
	for _, r := range requests {
		item := s.buildWithdrawalRequestItem(r, shop.ShopName, shopHierarchy, applicantMap, processorMap)
		items = append(items, item)
	}

	return &dto.ShopWithdrawalRequestPageResult{
		Items: items,
		Total: total,
		Page:  opts.Page,
		Size:  opts.PageSize,
	}, nil
}

// buildWithdrawalRequestItem 构造提现记录条目
func (s *Service) buildWithdrawalRequestItem(r *model.CommissionWithdrawalRequest, shopName, shopHierarchy string, applicantMap, processorMap map[uint]string) dto.ShopWithdrawalRequestItem {
	var processorID *uint
	if r.ProcessorID > 0 {
		processorID = &r.ProcessorID
	}

	var accountName, accountNumber, bankName string
	if len(r.AccountInfo) > 0 {
		var info map[string]interface{}
		if err := json.Unmarshal(r.AccountInfo, &info); err == nil {
			if v, ok := info["account_name"].(string); ok {
				accountName = v
			}
			if v, ok := info["account_number"].(string); ok {
				accountNumber = v
			}
			if v, ok := info["bank_name"].(string); ok {
				bankName = v
			}
		}
	}

	var processedAt, paidAt string
	if r.ProcessedAt != nil {
		processedAt = r.ProcessedAt.Format("2006-01-02 15:04:05")
	}
	if r.PaidAt != nil {
		paidAt = r.PaidAt.Format("2006-01-02 15:04:05")
	}

	return dto.ShopWithdrawalRequestItem{
		ID:               r.ID,
		WithdrawalNo:     r.WithdrawalNo,
		Amount:           r.Amount,
		FeeRate:          r.FeeRate,
		Fee:              r.Fee,
		ActualAmount:     r.ActualAmount,
		Status:           r.Status,
		StatusName:       constants.GetWithdrawalStatusName(r.Status),
		ShopID:           r.ShopID,
		ShopName:         shopName,
		ShopHierarchy:    shopHierarchy,
		ApplicantID:      r.ApplicantID,
		ApplicantName:    applicantMap[r.ApplicantID],
		ProcessorID:      processorID,
		ProcessorName:    processorMap[r.ProcessorID],
		WithdrawalMethod: r.WithdrawalMethod,
		PaymentType:      r.PaymentType,
		AccountName:      accountName,
		AccountNumber:    accountNumber,
		BankName:         bankName,
		RejectReason:     r.RejectReason,
		Remark:           r.Remark,
		CreatedAt:        r.CreatedAt.Format("2006-01-02 15:04:05"),
		ProcessedAt:      processedAt,
		PaidAt:           paidAt,
	}
}

// buildShopHierarchyPath 构造店铺层级路径（最多两层上级）
func (s *Service) buildShopHierarchyPath(ctx context.Context, shop *model.Shop) string {
	if shop == nil {
		return ""
	}

	path := shop.ShopName
	current := shop
	depth := 0

	for current.ParentID != nil && depth < 2 {
		parent, err := s.shopStore.GetByID(ctx, *current.ParentID)
		if err != nil {
			break
		}
		path = parent.ShopName + "_" + path
		current = parent
		depth++
	}

	return path
}

// ListShopCommissionRecords 查询代理商佣金明细
// GET /shops/:id/commission-records
func (s *Service) ListShopCommissionRecords(ctx context.Context, shopID uint, req *dto.ShopCommissionRecordListReq) (*dto.ShopCommissionRecordPageResult, error) {
	// 越权校验：平台人员可查所有，代理只能查自己和下级
	if err := middleware.CanManageShop(ctx, shopID); err != nil {
		return nil, errors.New(errors.CodeForbidden, "无权限操作该资源或资源不存在")
	}

	_, err := s.shopStore.GetByID(ctx, shopID)
	if err != nil {
		return nil, errors.New(errors.CodeShopNotFound, "店铺不存在")
	}

	opts := &store.QueryOptions{
		Page:     req.Page,
		PageSize: req.PageSize,
		OrderBy:  "created_at DESC",
	}
	if opts.Page == 0 {
		opts.Page = 1
	}
	if opts.PageSize == 0 {
		opts.PageSize = constants.DefaultPageSize
	}

	filters := &postgres.CommissionRecordListFilters{
		ShopID:           shopID,
		CommissionSource: req.CommissionSource,
		ICCID:            req.ICCID,
		DeviceNo:         req.VirtualNo,
		OrderNo:          req.OrderNo,
	}

	records, total, err := s.commissionRecordStore.ListByShopID(ctx, opts, filters)
	if err != nil {
		return nil, errors.Wrap(errors.CodeInternalError, err, "查询佣金明细失败")
	}

	sellerShopIDs := make([]uint, 0)
	for _, r := range records {
		if r.SellerShopID != nil && *r.SellerShopID > 0 {
			sellerShopIDs = append(sellerShopIDs, *r.SellerShopID)
		}
	}

	shopNameMap := make(map[uint]string)
	if len(sellerShopIDs) > 0 {
		shops, err := s.shopStore.GetByIDs(ctx, sellerShopIDs)
		if err == nil {
			for _, sh := range shops {
				shopNameMap[sh.ID] = sh.ShopName
			}
		}
	}

	items := make([]dto.ShopCommissionRecordItem, 0, len(records))
	for _, r := range records {
		var orderCreatedAt string
		if r.OrderCreatedAt != nil {
			orderCreatedAt = r.OrderCreatedAt.Format("2006-01-02 15:04:05")
		}
		var sellerShopID uint
		if r.SellerShopID != nil {
			sellerShopID = *r.SellerShopID
		}
		item := dto.ShopCommissionRecordItem{
			ID:               r.ID,
			Amount:           r.Amount,
			BalanceAfter:     r.BalanceAfter,
			CommissionSource: r.CommissionSource,
			Status:           r.Status,
			StatusName:       constants.GetCommissionRecordStatusName(r.Status),
			OrderID:          r.OrderID,
			OrderNo:          r.OrderNo,
			VirtualNo:        r.VirtualNo,
			ICCID:            r.ICCID,
			OrderCreatedAt:   orderCreatedAt,
			SellerShopID:     sellerShopID,
			SellerShopName:   shopNameMap[sellerShopID],
			CreatedAt:        r.CreatedAt.Format("2006-01-02 15:04:05"),
		}
		items = append(items, item)
	}

	return &dto.ShopCommissionRecordPageResult{
		Items: items,
		Total: total,
		Page:  opts.Page,
		Size:  opts.PageSize,
	}, nil
}

// GetStats 获取佣金统计
// GET /shops/:id/commission-stats
func (s *Service) GetStats(ctx context.Context, shopID uint, req *dto.CommissionStatsRequest) (*dto.CommissionStatsResponse, error) {
	// 越权校验：平台人员可查所有，代理只能查自己和下级
	if err := middleware.CanManageShop(ctx, shopID); err != nil {
		return nil, errors.New(errors.CodeForbidden, "无权限操作该资源或资源不存在")
	}

	filters := &postgres.CommissionRecordListFilters{
		ShopID:    shopID,
		StartTime: req.StartTime,
		EndTime:   req.EndTime,
	}

	stats, err := s.commissionRecordStore.GetStats(ctx, filters)
	if err != nil {
		return nil, errors.Wrap(errors.CodeInternalError, err, "获取佣金统计失败")
	}

	if stats == nil {
		return &dto.CommissionStatsResponse{}, nil
	}

	var costDiffPercent, oneTimePercent int64
	if stats.TotalAmount > 0 {
		costDiffPercent = stats.CostDiffAmount * 1000 / stats.TotalAmount
		oneTimePercent = stats.OneTimeAmount * 1000 / stats.TotalAmount
	}

	return &dto.CommissionStatsResponse{
		TotalAmount:     stats.TotalAmount,
		CostDiffAmount:  stats.CostDiffAmount,
		OneTimeAmount:   stats.OneTimeAmount,
		CostDiffPercent: costDiffPercent,
		OneTimePercent:  oneTimePercent,
		TotalCount:      stats.TotalCount,
		CostDiffCount:   stats.CostDiffCount,
		OneTimeCount:    stats.OneTimeCount,
	}, nil
}

// GetDailyStats 获取每日佣金统计
// GET /shops/:id/commission-daily-stats
func (s *Service) GetDailyStats(ctx context.Context, shopID uint, req *dto.DailyCommissionStatsRequest) ([]*dto.DailyCommissionStatsResponse, error) {
	// 越权校验：平台人员可查所有，代理只能查自己和下级
	if err := middleware.CanManageShop(ctx, shopID); err != nil {
		return nil, errors.New(errors.CodeForbidden, "无权限操作该资源或资源不存在")
	}

	days := 30
	if req.Days != nil && *req.Days > 0 {
		days = *req.Days
	}

	filters := &postgres.CommissionRecordListFilters{
		ShopID:    shopID,
		StartTime: req.StartDate,
		EndTime:   req.EndDate,
	}

	dailyStats, err := s.commissionRecordStore.GetDailyStats(ctx, filters, days)
	if err != nil {
		return nil, errors.Wrap(errors.CodeInternalError, err, "获取每日佣金统计失败")
	}

	result := make([]*dto.DailyCommissionStatsResponse, 0, len(dailyStats))
	for _, stat := range dailyStats {
		result = append(result, &dto.DailyCommissionStatsResponse{
			Date:        stat.Date,
			TotalAmount: stat.TotalAmount,
			TotalCount:  stat.TotalCount,
		})
	}

	return result, nil
}

// CreateWithdrawalRequest 代理发起提现申请
// POST /shops/:id/withdrawal-requests
func (s *Service) CreateWithdrawalRequest(ctx context.Context, shopID uint, req *dto.CreateMyWithdrawalReq) (*dto.CreateMyWithdrawalResp, error) {
	// 提现权限比查询更严格：必须是代理账号本人操作，不允许平台人员或顶级代理替下级提现
	userType := middleware.GetUserTypeFromContext(ctx)
	if userType != constants.UserTypeAgent {
		return nil, errors.New(errors.CodeForbidden, "仅代理商用户可发起提现")
	}
	if shopID != middleware.GetShopIDFromContext(ctx) {
		return nil, errors.New(errors.CodeForbidden, "仅可为本人店铺发起提现")
	}

	currentUserID := middleware.GetUserIDFromContext(ctx)
	if currentUserID == 0 {
		return nil, errors.New(errors.CodeForbidden, "无法获取用户信息")
	}

	// 获取提现配置
	setting, err := s.commissionWithdrawalSettingStore.GetCurrent(ctx)
	if err != nil {
		return nil, errors.New(errors.CodeInvalidParam, "暂未开放提现功能")
	}

	// 验证最低提现金额
	if req.Amount < setting.MinWithdrawalAmount {
		return nil, errors.New(errors.CodeInvalidParam, fmt.Sprintf("提现金额不能低于 %.2f 元", float64(setting.MinWithdrawalAmount)/100))
	}

	// 获取佣金钱包
	wallet, err := s.agentWalletStore.GetCommissionWallet(ctx, shopID)
	if err != nil {
		return nil, errors.New(errors.CodeInsufficientBalance, "钱包不存在")
	}

	// 验证可用余额
	if req.Amount > wallet.GetAvailableBalance() {
		return nil, errors.New(errors.CodeInsufficientBalance, "可提现余额不足")
	}

	// 验证今日提现次数
	today := time.Now().Format("2006-01-02")
	var todayCount int64
	s.db.WithContext(ctx).Model(&model.CommissionWithdrawalRequest{}).
		Where("shop_id = ? AND created_at >= ? AND created_at <= ?", shopID, today+" 00:00:00", today+" 23:59:59").
		Count(&todayCount)
	if int(todayCount) >= setting.DailyWithdrawalLimit {
		return nil, errors.New(errors.CodeInvalidParam, "今日提现次数已达上限")
	}

	// 计算手续费
	fee := req.Amount * setting.FeeRate / 10000
	actualAmount := req.Amount - fee
	withdrawalNo := generateWithdrawalNo()

	accountInfo := map[string]string{
		"account_name":   req.AccountName,
		"account_number": req.AccountNumber,
	}
	accountInfoJSON, _ := json.Marshal(accountInfo)

	var withdrawalRequest *model.CommissionWithdrawalRequest

	err = s.db.Transaction(func(tx *gorm.DB) error {
		// 使用条件更新防并发
		result := tx.WithContext(ctx).Model(&model.AgentWallet{}).
			Where("id = ? AND balance - frozen_balance >= ?", wallet.ID, req.Amount).
			Updates(map[string]interface{}{
				"frozen_balance": gorm.Expr("frozen_balance + ?", req.Amount),
			})
		if result.Error != nil {
			return errors.Wrap(errors.CodeInternalError, result.Error, "冻结余额失败")
		}
		if result.RowsAffected == 0 {
			return errors.New(errors.CodeInsufficientBalance, "余额不足或并发冲突，请稍后重试")
		}

		withdrawalRequest = &model.CommissionWithdrawalRequest{
			WithdrawalNo:     withdrawalNo,
			ShopID:           shopID,
			ApplicantID:      currentUserID,
			Amount:           req.Amount,
			FeeRate:          setting.FeeRate,
			Fee:              fee,
			ActualAmount:     actualAmount,
			WithdrawalMethod: req.WithdrawalMethod,
			AccountInfo:      accountInfoJSON,
			Status:           constants.WithdrawalStatusPending, // 待审核
		}
		withdrawalRequest.Creator = currentUserID
		withdrawalRequest.Updater = currentUserID

		if err := tx.WithContext(ctx).Create(withdrawalRequest).Error; err != nil {
			return errors.Wrap(errors.CodeInternalError, err, "创建提现申请失败")
		}

		remark := fmt.Sprintf("提现冻结，单号：%s", withdrawalNo)
		refType := constants.ReferenceTypeWithdrawal
		transaction := &model.AgentWalletTransaction{
			AgentWalletID:   wallet.ID,
			ShopID:          shopID,
			UserID:          currentUserID,
			TransactionType: constants.AgentTransactionTypeWithdrawal,
			Amount:          -req.Amount,
			BalanceBefore:   wallet.Balance,
			BalanceAfter:    wallet.Balance - req.Amount,
			Status:          constants.TransactionStatusProcessing,
			ReferenceType:   &refType,
			ReferenceID:     &withdrawalRequest.ID,
			Remark:          &remark,
			Creator:         currentUserID,
			ShopIDTag:       shopID,
		}

		if err := tx.WithContext(ctx).Create(transaction).Error; err != nil {
			return errors.Wrap(errors.CodeInternalError, err, "创建钱包流水失败")
		}

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

	return &dto.CreateMyWithdrawalResp{
		ID:           withdrawalRequest.ID,
		WithdrawalNo: withdrawalRequest.WithdrawalNo,
		Amount:       withdrawalRequest.Amount,
		FeeRate:      withdrawalRequest.FeeRate,
		Fee:          withdrawalRequest.Fee,
		ActualAmount: withdrawalRequest.ActualAmount,
		Status:       withdrawalRequest.Status,
		StatusName:   constants.GetWithdrawalStatusName(withdrawalRequest.Status),
		CreatedAt:    withdrawalRequest.CreatedAt.Format("2006-01-02 15:04:05"),
	}, nil
}

// ListMainWalletTransactions 查询代理主钱包（预充值钱包）流水
// GET /shops/:id/main-wallet/transactions
func (s *Service) ListMainWalletTransactions(ctx context.Context, shopID uint, req *dto.MainWalletTransactionListRequest) (*dto.MainWalletTransactionListResponse, error) {
	// 越权校验
	if err := middleware.CanManageShop(ctx, shopID); err != nil {
		return nil, errors.New(errors.CodeForbidden, "无权限操作该资源或资源不存在")
	}

	page := req.Page
	pageSize := req.PageSize
	if page == 0 {
		page = 1
	}
	if pageSize == 0 {
		pageSize = constants.DefaultPageSize
	}

	// 获取主钱包，不存在则返回空列表
	mainWallet, err := s.agentWalletStore.GetMainWallet(ctx, shopID)
	if err != nil {
		return &dto.MainWalletTransactionListResponse{
			Items: []dto.MainWalletTransactionItem{},
			Total: 0,
			Page:  page,
			Size:  pageSize,
		}, nil
	}

	filters := &postgres.AgentWalletTransactionListFilters{
		TransactionType: req.TransactionType,
		StartDate:       req.StartDate,
		EndDate:         req.EndDate,
		AssetIdentifier: req.AssetIdentifier,
	}

	offset := (page - 1) * pageSize
	transactions, err := s.agentWalletTransactionStore.ListByWalletIDWithFilters(ctx, mainWallet.ID, offset, pageSize, filters)
	if err != nil {
		return nil, errors.Wrap(errors.CodeInternalError, err, "查询主钱包流水失败")
	}

	total, err := s.agentWalletTransactionStore.CountByWalletID(ctx, mainWallet.ID, filters)
	if err != nil {
		return nil, errors.Wrap(errors.CodeInternalError, err, "统计主钱包流水失败")
	}

	items := make([]dto.MainWalletTransactionItem, 0, len(transactions))
	for _, t := range transactions {
		var remark string
		if t.Remark != nil {
			remark = *t.Remark
		}
		var subtype string
		if t.TransactionSubtype != nil {
			subtype = *t.TransactionSubtype
		}
		items = append(items, dto.MainWalletTransactionItem{
			ID:                 t.ID,
			TransactionType:    t.TransactionType,
			TransactionSubtype: subtype,
			Amount:             t.Amount,
			BalanceBefore:      t.BalanceBefore,
			BalanceAfter:       t.BalanceAfter,
			AssetType:          t.AssetType,
			AssetID:            t.AssetID,
			AssetIdentifier:    t.AssetIdentifier,
			Remark:             remark,
			CreatedAt:          t.CreatedAt.Format("2006-01-02 15:04:05"),
		})
	}

	return &dto.MainWalletTransactionListResponse{
		Items: items,
		Total: total,
		Page:  page,
		Size:  pageSize,
	}, nil
}

// ResolveCommissionRecord 修正待审佣金记录（status=99）
// release: 填入金额并入账到代理佣金钱包
// invalidate: 标记为已失效
func (s *Service) ResolveCommissionRecord(ctx context.Context, recordID uint, req *dto.CommissionRecordResolveRequest) error {
	record, err := s.commissionRecordStore.GetByID(ctx, recordID)
	if err != nil {
		return errors.Wrap(errors.CodeNotFound, err, "佣金记录不存在")
	}

	if record.Status != constants.CommissionStatusPendingReview {
		return errors.New(errors.CodeInvalidParam, "该记录不是待修正状态")
	}

	now := time.Now()
	resolveRemark := record.Remark
	if req.Remark != "" {
		resolveRemark += " | 处理备注: " + req.Remark
	}

	if req.Action == "invalidate" {
		return s.commissionRecordStore.UpdateByID(ctx, nil, recordID, map[string]any{
			"status": constants.CommissionStatusInvalid,
			"remark": resolveRemark,
		})
	}

	// release 入账
	if req.Amount == nil || *req.Amount <= 0 {
		return errors.New(errors.CodeInvalidParam, "入账操作必须指定金额")
	}
	amount := *req.Amount

	wallet, err := s.agentWalletStore.GetCommissionWallet(ctx, record.ShopID)
	if err != nil {
		return errors.Wrap(errors.CodeNotFound, err, "店铺佣金钱包不存在")
	}

	return s.db.Transaction(func(tx *gorm.DB) error {
		if err := s.commissionRecordStore.UpdateByID(ctx, tx, recordID, map[string]any{
			"status":      constants.CommissionStatusReleased,
			"amount":      amount,
			"released_at": now,
			"remark":      resolveRemark,
		}); err != nil {
			return errors.Wrap(errors.CodeDatabaseError, err, "更新佣金记录失败")
		}

		balanceBefore := wallet.Balance
		result := tx.Model(&model.AgentWallet{}).
			Where("id = ? AND version = ?", wallet.ID, wallet.Version).
			Updates(map[string]any{
				"balance": gorm.Expr("balance + ?", amount),
				"version": gorm.Expr("version + 1"),
			})
		if result.Error != nil {
			return errors.Wrap(errors.CodeDatabaseError, result.Error, "更新佣金钱包余额失败")
		}
		if result.RowsAffected == 0 {
			return errors.New(errors.CodeInternalError, "佣金钱包版本冲突，请重试")
		}

		if err := s.commissionRecordStore.UpdateByID(ctx, tx, recordID, map[string]any{
			"balance_after": balanceBefore + amount,
		}); err != nil {
			return errors.Wrap(errors.CodeDatabaseError, err, "更新入账后余额失败")
		}

		return nil
	})
}

// generateWithdrawalNo 生成提现单号
func generateWithdrawalNo() string {
	now := time.Now()
	return fmt.Sprintf("W%s%04d", now.Format("20060102150405"), rand.Intn(10000))
}
