// Package refund 提供退款申请的业务逻辑服务
// 包含退款申请的创建、审批、拒绝、退回、重新提交等完整生命周期管理
// 审批通过后异步执行佣金回扣和资产世代重置
package refund

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

	"go.uber.org/zap"
	"gorm.io/gorm"

	"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"

	deviceSvc "github.com/break/junhong_cmp_fiber/internal/service/device"
	iotCardSvc "github.com/break/junhong_cmp_fiber/internal/service/iot_card"
	packageSvc "github.com/break/junhong_cmp_fiber/internal/service/package"
)

// Service 退款业务服务
// 负责退款申请的 CRUD、审批流程、佣金回扣和资产世代重置
type Service struct {
	db                          *gorm.DB
	refundStore                 *postgres.RefundStore
	orderStore                  *postgres.OrderStore
	commissionRecordStore       *postgres.CommissionRecordStore
	agentWalletStore            *postgres.AgentWalletStore
	agentWalletTransactionStore *postgres.AgentWalletTransactionStore
	stopResumeService           *iotCardSvc.StopResumeService
	deviceService               *deviceSvc.Service
	packageActivationService    *packageSvc.ActivationService
	iotCardStore                *postgres.IotCardStore
	deviceStore                 *postgres.DeviceStore
	assetWalletStore            *postgres.AssetWalletStore
	logger                      *zap.Logger
}

// New 创建退款业务服务实例
func New(
	db *gorm.DB,
	refundStore *postgres.RefundStore,
	orderStore *postgres.OrderStore,
	commissionRecordStore *postgres.CommissionRecordStore,
	agentWalletStore *postgres.AgentWalletStore,
	agentWalletTransactionStore *postgres.AgentWalletTransactionStore,
	stopResumeService *iotCardSvc.StopResumeService,
	deviceService *deviceSvc.Service,
	packageActivationService *packageSvc.ActivationService,
	iotCardStore *postgres.IotCardStore,
	deviceStore *postgres.DeviceStore,
	assetWalletStore *postgres.AssetWalletStore,
	logger *zap.Logger,
) *Service {
	return &Service{
		db:                          db,
		refundStore:                 refundStore,
		orderStore:                  orderStore,
		commissionRecordStore:       commissionRecordStore,
		agentWalletStore:            agentWalletStore,
		agentWalletTransactionStore: agentWalletTransactionStore,
		stopResumeService:           stopResumeService,
		deviceService:               deviceService,
		packageActivationService:    packageActivationService,
		iotCardStore:                iotCardStore,
		deviceStore:                 deviceStore,
		assetWalletStore:            assetWalletStore,
		logger:                      logger,
	}
}

// Create 创建退款申请
// 校验订单存在且已支付，检查是否存在活跃退款申请，生成退款单号并创建记录
func (s *Service) Create(ctx context.Context, req *dto.CreateRefundRequest) (*dto.RefundResponse, error) {
	userID := middleware.GetUserIDFromContext(ctx)
	if userID == 0 {
		return nil, errors.New(errors.CodeUnauthorized, "未授权访问")
	}

	// 校验订单存在且已支付
	order, err := s.orderStore.GetByID(ctx, req.OrderID)
	if err != nil {
		return nil, errors.New(errors.CodeNotFound, "订单不存在")
	}
	if order.PaymentStatus != model.PaymentStatusPaid {
		return nil, errors.New(errors.CodeInvalidStatus, "仅已支付订单可申请退款")
	}

	// 检查是否存在活跃退款申请（待审批、已通过、已退回状态）
	existing, err := s.refundStore.FindActiveByOrderID(ctx, req.OrderID)
	if err == nil && existing != nil {
		return nil, errors.New(errors.CodeConflict, "该订单已存在退款申请")
	}

	// 从订单获取 shop_id：优先使用 SellerShopID，代理商买家使用 BuyerID
	var shopID *uint
	if order.SellerShopID != nil {
		shopID = order.SellerShopID
	} else if order.BuyerType == model.BuyerTypeAgent {
		shopID = &order.BuyerID
	}

	refund := &model.RefundRequest{
		RefundNo:              generateRefundNo(),
		OrderID:               req.OrderID,
		PackageUsageID:        req.PackageUsageID,
		ShopID:                shopID,
		ActualReceivedAmount:  req.ActualReceivedAmount,
		RequestedRefundAmount: req.RequestedRefundAmount,
		RefundReason:          req.RefundReason,
		Status:                model.RefundStatusPending,
	}
	refund.Creator = userID
	refund.Updater = userID

	if err := s.refundStore.Create(ctx, refund); err != nil {
		return nil, errors.Wrap(errors.CodeInternalError, err, "创建退款申请失败")
	}

	return buildRefundResponse(refund), nil
}

// List 分页查询退款申请列表
func (s *Service) List(ctx context.Context, req *dto.RefundListRequest) (*dto.RefundListResponse, error) {
	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.RefundListFilters{
		Status:  req.Status,
		OrderID: req.OrderID,
		ShopID:  req.ShopID,
	}

	requests, total, err := s.refundStore.List(ctx, opts, filters)
	if err != nil {
		return nil, errors.Wrap(errors.CodeInternalError, err, "查询退款申请列表失败")
	}

	items := make([]dto.RefundResponse, 0, len(requests))
	for _, r := range requests {
		items = append(items, *buildRefundResponse(r))
	}

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

// GetByID 根据 ID 查询退款申请详情
func (s *Service) GetByID(ctx context.Context, id uint) (*dto.RefundResponse, error) {
	refund, err := s.refundStore.GetByID(ctx, id)
	if err != nil {
		return nil, errors.New(errors.CodeNotFound, "退款申请不存在")
	}
	return buildRefundResponse(refund), nil
}

// Approve 审批通过退款申请
// 条件更新 WHERE status=1，设置审批信息
// 事务提交成功后异步执行佣金回扣和资产重置
func (s *Service) Approve(ctx context.Context, id uint, req *dto.ApproveRefundRequest) error {
	userID := middleware.GetUserIDFromContext(ctx)
	if userID == 0 {
		return errors.New(errors.CodeUnauthorized, "未授权访问")
	}

	refund, err := s.refundStore.GetByID(ctx, id)
	if err != nil {
		return errors.New(errors.CodeNotFound, "退款申请不存在")
	}
	if refund.Status != model.RefundStatusPending {
		return errors.New(errors.CodeInvalidStatus, "仅待审批状态可审批通过")
	}

	now := time.Now()
	approvedAmount := refund.RequestedRefundAmount
	if req.ApprovedRefundAmount != nil {
		approvedAmount = *req.ApprovedRefundAmount
	}

	// 条件更新确保幂等性
	result := s.db.WithContext(ctx).
		Model(&model.RefundRequest{}).
		Where("id = ? AND status = ?", id, model.RefundStatusPending).
		Updates(map[string]any{
			"status":                 model.RefundStatusApproved,
			"processor_id":           userID,
			"processed_at":           now,
			"approved_refund_amount": approvedAmount,
			"remark":                 req.Remark,
			"updater":                userID,
			"updated_at":             now,
		})
	if result.Error != nil {
		return errors.Wrap(errors.CodeInternalError, result.Error, "审批退款申请失败")
	}
	if result.RowsAffected == 0 {
		return errors.New(errors.CodeInvalidStatus, "退款申请状态已变更，请刷新后重试")
	}

	// 事务提交成功后，异步执行佣金回扣和资产重置（失败不影响审批结果）
	go func() {
		asyncCtx := context.Background()
		s.deductAllCommission(asyncCtx, id)
	}()

	go func() {
		asyncCtx := context.Background()
		s.handleAssetReset(asyncCtx, id)
	}()

	return nil
}

// Reject 审批拒绝退款申请
// 条件更新 WHERE status=1
func (s *Service) Reject(ctx context.Context, id uint, req *dto.RejectRefundRequest) error {
	userID := middleware.GetUserIDFromContext(ctx)
	if userID == 0 {
		return errors.New(errors.CodeUnauthorized, "未授权访问")
	}

	now := time.Now()
	result := s.db.WithContext(ctx).
		Model(&model.RefundRequest{}).
		Where("id = ? AND status = ?", id, model.RefundStatusPending).
		Updates(map[string]any{
			"status":        model.RefundStatusRejected,
			"processor_id":  userID,
			"processed_at":  now,
			"reject_reason": req.RejectReason,
			"updater":       userID,
			"updated_at":    now,
		})
	if result.Error != nil {
		return errors.Wrap(errors.CodeInternalError, result.Error, "拒绝退款申请失败")
	}
	if result.RowsAffected == 0 {
		return errors.New(errors.CodeInvalidStatus, "退款申请状态已变更，请刷新后重试")
	}
	return nil
}

// Return 退回退款申请
// 条件更新 WHERE status=1，退回后可重新提交
func (s *Service) Return(ctx context.Context, id uint, req *dto.ReturnRefundRequest) error {
	userID := middleware.GetUserIDFromContext(ctx)
	if userID == 0 {
		return errors.New(errors.CodeUnauthorized, "未授权访问")
	}

	now := time.Now()
	result := s.db.WithContext(ctx).
		Model(&model.RefundRequest{}).
		Where("id = ? AND status = ?", id, model.RefundStatusPending).
		Updates(map[string]any{
			"status":       model.RefundStatusReturned,
			"processor_id": userID,
			"processed_at": now,
			"remark":       req.Remark,
			"updater":      userID,
			"updated_at":   now,
		})
	if result.Error != nil {
		return errors.Wrap(errors.CodeInternalError, result.Error, "退回退款申请失败")
	}
	if result.RowsAffected == 0 {
		return errors.New(errors.CodeInvalidStatus, "退款申请状态已变更，请刷新后重试")
	}
	return nil
}

// Resubmit 重新提交退款申请
// 条件更新 WHERE status=4（已退回），修改部分字段后重新进入待审批状态
func (s *Service) Resubmit(ctx context.Context, id uint, req *dto.ResubmitRefundRequest) error {
	userID := middleware.GetUserIDFromContext(ctx)
	if userID == 0 {
		return errors.New(errors.CodeUnauthorized, "未授权访问")
	}

	now := time.Now()
	updates := map[string]any{
		"status":     model.RefundStatusPending,
		"updater":    userID,
		"updated_at": now,
	}
	if req.ActualReceivedAmount != nil {
		updates["actual_received_amount"] = *req.ActualReceivedAmount
	}
	if req.RequestedRefundAmount != nil {
		updates["requested_refund_amount"] = *req.RequestedRefundAmount
	}
	if req.RefundReason != nil {
		updates["refund_reason"] = *req.RefundReason
	}

	result := s.db.WithContext(ctx).
		Model(&model.RefundRequest{}).
		Where("id = ? AND status = ?", id, model.RefundStatusReturned).
		Updates(updates)
	if result.Error != nil {
		return errors.Wrap(errors.CodeInternalError, result.Error, "重新提交退款申请失败")
	}
	if result.RowsAffected == 0 {
		return errors.New(errors.CodeInvalidStatus, "仅已退回状态可重新提交")
	}
	return nil
}

// deductAllCommission 异步回扣该订单所有已入账佣金
// 查询退款单关联订单的所有已入账佣金记录，逐条从代理佣金钱包扣减
// 失败仅记录日志，不影响审批结果
func (s *Service) deductAllCommission(ctx context.Context, refundID uint) {
	logger := s.logger

	// 查询退款单
	var refund model.RefundRequest
	if err := s.db.Where("id = ?", refundID).First(&refund).Error; err != nil {
		logger.Error("佣金回扣：查询退款单失败", zap.Uint("refund_id", refundID), zap.Error(err))
		return
	}

	// 查询该订单所有已入账佣金记录
	var commissions []model.CommissionRecord
	if err := s.db.Where("order_id = ? AND status = ?", refund.OrderID, constants.CommissionStatusReleased).Find(&commissions).Error; err != nil {
		logger.Error("佣金回扣：查询佣金记录失败", zap.Uint("refund_id", refundID), zap.Uint("order_id", refund.OrderID), zap.Error(err))
		return
	}

	if len(commissions) == 0 {
		logger.Info("佣金回扣：无已入账佣金记录", zap.Uint("refund_id", refundID))
		// 无佣金需要回扣，直接标记完成
		s.db.Model(&model.RefundRequest{}).Where("id = ?", refundID).Update("commission_deducted", true)
		return
	}

	// 对每条佣金记录执行扣减
	for _, commission := range commissions {
		if err := s.deductSingleCommission(ctx, &refund, &commission); err != nil {
			logger.Error("佣金回扣：单条佣金扣减失败",
				zap.Uint("refund_id", refundID),
				zap.Uint("commission_id", commission.ID),
				zap.Uint("shop_id", commission.ShopID),
				zap.Int64("amount", commission.Amount),
				zap.Error(err),
			)
			// 继续处理下一条，不中断
		}
	}

	// 全部完成后标记退款单佣金已回扣
	if err := s.db.Model(&model.RefundRequest{}).Where("id = ?", refundID).Update("commission_deducted", true).Error; err != nil {
		logger.Error("佣金回扣：更新回扣标记失败", zap.Uint("refund_id", refundID), zap.Error(err))
	}
}

// deductSingleCommission 扣减单条佣金记录对应的代理钱包余额
// 使用乐观锁扣减（允许余额为负数），并创建交易流水
func (s *Service) deductSingleCommission(ctx context.Context, refund *model.RefundRequest, commission *model.CommissionRecord) error {
	// 获取对应代理的佣金钱包
	wallet, err := s.agentWalletStore.GetCommissionWallet(ctx, commission.ShopID)
	if err != nil {
		return fmt.Errorf("获取佣金钱包失败: shop_id=%d, %w", commission.ShopID, err)
	}

	// 乐观锁扣减余额（允许负数）
	result := s.db.Model(&model.AgentWallet{}).
		Where("id = ? AND version = ?", wallet.ID, wallet.Version).
		Updates(map[string]any{
			"balance": gorm.Expr("balance - ?", commission.Amount),
			"version": gorm.Expr("version + 1"),
		})
	if result.Error != nil {
		return fmt.Errorf("扣减钱包余额失败: %w", result.Error)
	}
	if result.RowsAffected == 0 {
		return fmt.Errorf("乐观锁冲突: wallet_id=%d, version=%d", wallet.ID, wallet.Version)
	}

	// 创建交易流水
	refType := constants.ReferenceTypeRefund
	refID := refund.ID
	transaction := &model.AgentWalletTransaction{
		AgentWalletID:   wallet.ID,
		ShopID:          commission.ShopID,
		UserID:          refund.Creator,
		TransactionType: constants.AgentTransactionTypeCommissionDeduct,
		Amount:          -commission.Amount,
		BalanceBefore:   wallet.Balance,
		BalanceAfter:    wallet.Balance - commission.Amount,
		Status:          constants.TransactionStatusSuccess,
		ReferenceType:   &refType,
		ReferenceID:     &refID,
		Creator:         refund.Creator,
		ShopIDTag:       commission.ShopID,
	}

	if err := s.agentWalletTransactionStore.CreateWithTx(ctx, s.db, transaction); err != nil {
		return fmt.Errorf("创建交易流水失败: %w", err)
	}

	return nil
}

// handleAssetReset 异步处理资产重置
// 包括：套餐失效、停机、世代重置（generation+1）、钱包重建、订单状态更新
// 失败仅记录日志，不影响审批结果
func (s *Service) handleAssetReset(ctx context.Context, refundID uint) {
	logger := s.logger

	// 查询退款单
	var refund model.RefundRequest
	if err := s.db.Where("id = ?", refundID).First(&refund).Error; err != nil {
		logger.Error("资产重置：查询退款单失败", zap.Uint("refund_id", refundID), zap.Error(err))
		return
	}

	// 查询关联订单
	var order model.Order
	if err := s.db.Where("id = ?", refund.OrderID).First(&order).Error; err != nil {
		logger.Error("资产重置：查询订单失败", zap.Uint("refund_id", refundID), zap.Uint("order_id", refund.OrderID), zap.Error(err))
		return
	}

	// 确定资产类型和 ID
	var assetType string
	var assetID uint
	switch order.OrderType {
	case model.OrderTypeSingleCard:
		if order.IotCardID == nil {
			logger.Error("资产重置：单卡订单缺少 iot_card_id", zap.Uint("order_id", order.ID))
			return
		}
		assetType = "iot_card"
		assetID = *order.IotCardID
	case model.OrderTypeDevice:
		if order.DeviceID == nil {
			logger.Error("资产重置：设备订单缺少 device_id", zap.Uint("order_id", order.ID))
			return
		}
		assetType = "device"
		assetID = *order.DeviceID
	default:
		logger.Error("资产重置：未知订单类型", zap.String("order_type", order.OrderType))
		return
	}

	// 1. 失效所有套餐
	if s.packageActivationService != nil {
		if err := s.packageActivationService.InvalidateAllPackagesByAsset(ctx, assetType, assetID); err != nil {
			logger.Error("资产重置：失效套餐失败", zap.String("asset_type", assetType), zap.Uint("asset_id", assetID), zap.Error(err))
		}
	}

	// 2. 停机
	s.stopAsset(ctx, assetType, assetID)

	// 3. 世代重置（参照 exchange/service.go）
	if err := s.resetAssetGeneration(ctx, assetType, assetID); err != nil {
		logger.Error("资产重置：世代重置失败", zap.String("asset_type", assetType), zap.Uint("asset_id", assetID), zap.Error(err))
		return
	}

	// 4. 更新订单支付状态为已退款
	if err := s.db.Model(&model.Order{}).Where("id = ?", order.ID).Update("payment_status", model.PaymentStatusRefunded).Error; err != nil {
		logger.Error("资产重置：更新订单状态失败", zap.Uint("order_id", order.ID), zap.Error(err))
	}

	// 5. 标记退款单资产已重置
	if err := s.db.Model(&model.RefundRequest{}).Where("id = ?", refundID).Update("asset_reset", true).Error; err != nil {
		logger.Error("资产重置：更新重置标记失败", zap.Uint("refund_id", refundID), zap.Error(err))
	}
}

// stopAsset 根据资产类型执行停机操作
func (s *Service) stopAsset(ctx context.Context, assetType string, assetID uint) {
	logger := s.logger

	switch assetType {
	case "iot_card":
		// 单卡停机：需要先查卡获取 iccid
		card, err := s.iotCardStore.GetByID(ctx, assetID)
		if err != nil {
			logger.Error("资产重置：查询卡信息失败", zap.Uint("card_id", assetID), zap.Error(err))
			return
		}
		if s.stopResumeService != nil {
			if err := s.stopResumeService.ManualStopCard(ctx, card.ICCID); err != nil {
				logger.Error("资产重置：单卡停机失败", zap.String("iccid", card.ICCID), zap.Error(err))
			}
		}
	case "device":
		// 设备停机
		if s.deviceService != nil {
			if _, err := s.deviceService.StopDevice(ctx, assetID); err != nil {
				logger.Error("资产重置：设备停机失败", zap.Uint("device_id", assetID), zap.Error(err))
			}
		}
	}
}

// resetAssetGeneration 执行资产世代重置
// 参照 exchange/service.go 实现：
// 1. generation+1, asset_status=1, 清零累计充值和佣金标记
// 2. 清理个人客户绑定
// 3. 删除旧钱包、创建新空钱包
func (s *Service) resetAssetGeneration(ctx context.Context, assetType string, assetID uint) error {
	return s.db.WithContext(ctx).Transaction(func(tx *gorm.DB) error {
		now := time.Now()

		if assetType == "iot_card" {
			var card model.IotCard
			if err := tx.Where("id = ?", assetID).First(&card).Error; err != nil {
				return fmt.Errorf("查询卡信息失败: %w", err)
			}

			// 世代+1, 重置状态和累计数据
			if err := tx.Model(&model.IotCard{}).Where("id = ?", card.ID).Updates(map[string]any{
				"generation":                         card.Generation + 1,
				"asset_status":                       1,
				"accumulated_recharge":               0,
				"first_commission_paid":              false,
				"accumulated_recharge_by_series":     "{}",
				"first_recharge_triggered_by_series": "{}",
				"updated_at":                         now,
			}).Error; err != nil {
				return fmt.Errorf("重置卡世代失败: %w", err)
			}

			// 清理个人客户绑定（按 virtual_no）
			if card.VirtualNo != "" {
				if err := tx.Where("virtual_no = ?", card.VirtualNo).Delete(&model.PersonalCustomerDevice{}).Error; err != nil {
					return fmt.Errorf("清理个人客户绑定失败: %w", err)
				}
			}

			// 删除旧钱包、创建新空钱包
			if err := tx.Where("resource_type = ? AND resource_id = ?", constants.ExchangeAssetTypeIotCard, card.ID).Delete(&model.AssetWallet{}).Error; err != nil {
				return fmt.Errorf("清理旧钱包失败: %w", err)
			}

			shopTag := uint(0)
			if card.ShopID != nil {
				shopTag = *card.ShopID
			}
			if err := tx.Create(&model.AssetWallet{
				ResourceType:  constants.ExchangeAssetTypeIotCard,
				ResourceID:    card.ID,
				Balance:       0,
				FrozenBalance: 0,
				Currency:      "CNY",
				Status:        1,
				Version:       0,
				ShopIDTag:     shopTag,
			}).Error; err != nil {
				return fmt.Errorf("创建新钱包失败: %w", err)
			}

			return nil
		}

		// 设备类型
		var device model.Device
		if err := tx.Where("id = ?", assetID).First(&device).Error; err != nil {
			return fmt.Errorf("查询设备失败: %w", err)
		}

		// 世代+1, 重置状态和累计数据
		if err := tx.Model(&model.Device{}).Where("id = ?", device.ID).Updates(map[string]any{
			"generation":                         device.Generation + 1,
			"asset_status":                       1,
			"accumulated_recharge":               0,
			"first_commission_paid":              false,
			"accumulated_recharge_by_series":     "{}",
			"first_recharge_triggered_by_series": "{}",
			"updated_at":                         now,
		}).Error; err != nil {
			return fmt.Errorf("重置设备世代失败: %w", err)
		}

		// 清理个人客户绑定（按 virtual_no）
		if device.VirtualNo != "" {
			if err := tx.Where("virtual_no = ?", device.VirtualNo).Delete(&model.PersonalCustomerDevice{}).Error; err != nil {
				return fmt.Errorf("清理个人客户绑定失败: %w", err)
			}
		}

		// 删除旧钱包、创建新空钱包
		if err := tx.Where("resource_type = ? AND resource_id = ?", constants.ExchangeAssetTypeDevice, device.ID).Delete(&model.AssetWallet{}).Error; err != nil {
			return fmt.Errorf("清理旧钱包失败: %w", err)
		}

		shopTag := uint(0)
		if device.ShopID != nil {
			shopTag = *device.ShopID
		}
		if err := tx.Create(&model.AssetWallet{
			ResourceType:  constants.ExchangeAssetTypeDevice,
			ResourceID:    device.ID,
			Balance:       0,
			FrozenBalance: 0,
			Currency:      "CNY",
			Status:        1,
			Version:       0,
			ShopIDTag:     shopTag,
		}).Error; err != nil {
			return fmt.Errorf("创建新钱包失败: %w", err)
		}

		return nil
	})
}

// generateRefundNo 生成退款单号
// 格式：RF + 日期时间 + 6位随机数
func generateRefundNo() string {
	now := time.Now()
	randomNum := rand.Intn(1000000)
	return fmt.Sprintf("RF%s%06d", now.Format("20060102150405"), randomNum)
}

// buildRefundResponse 将退款 Model 转换为 DTO 响应
func buildRefundResponse(r *model.RefundRequest) *dto.RefundResponse {
	resp := &dto.RefundResponse{
		ID:                    r.ID,
		RefundNo:              r.RefundNo,
		OrderID:               r.OrderID,
		PackageUsageID:        r.PackageUsageID,
		ShopID:                r.ShopID,
		ActualReceivedAmount:  r.ActualReceivedAmount,
		RequestedRefundAmount: r.RequestedRefundAmount,
		ApprovedRefundAmount:  r.ApprovedRefundAmount,
		RefundReason:          r.RefundReason,
		Status:                r.Status,
		StatusName:            constants.GetRefundStatusName(r.Status),
		ProcessorID:           r.ProcessorID,
		RejectReason:          r.RejectReason,
		Remark:                r.Remark,
		CommissionDeducted:    r.CommissionDeducted,
		AssetReset:            r.AssetReset,
		Creator:               r.Creator,
		Updater:               r.Updater,
		CreatedAt:             r.CreatedAt.Format("2006-01-02 15:04:05"),
		UpdatedAt:             r.UpdatedAt.Format("2006-01-02 15:04:05"),
	}

	if r.ProcessedAt != nil {
		resp.ProcessedAt = r.ProcessedAt.Format("2006-01-02 15:04:05")
	}

	return resp
}
