// Package agent_recharge 提供代理预充值的业务逻辑服务
// 包含充值订单创建、线下确认、支付回调处理、列表查询等功能
package agent_recharge

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

	"github.com/redis/go-redis/v9"
	"go.uber.org/zap"
	"gorm.io/gorm"

	agentrechargeapp "github.com/break/junhong_cmp_fiber/internal/application/agentrecharge"
	walletapp "github.com/break/junhong_cmp_fiber/internal/application/wallet"
	"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/postgres"
	"github.com/break/junhong_cmp_fiber/pkg/config"
	"github.com/break/junhong_cmp_fiber/pkg/constants"
	"github.com/break/junhong_cmp_fiber/pkg/errors"
	"github.com/break/junhong_cmp_fiber/pkg/middleware"
)

// AuditServiceInterface 审计日志服务接口
type AuditServiceInterface interface {
	LogOperation(ctx context.Context, log *model.AccountOperationLog)
}

// OperationPasswordServiceInterface 全局操作密码服务接口
type OperationPasswordServiceInterface interface {
	Verify(ctx context.Context, inputPassword string) error
}

// WechatConfigServiceInterface 支付配置服务接口
type WechatConfigServiceInterface interface {
	GetActiveConfig(ctx context.Context) (*model.WechatConfig, error)
}

// Service 代理预充值业务服务
// 负责代理钱包充值订单的创建、线下确认、回调处理等业务逻辑
type Service struct {
	db                       *gorm.DB
	agentRechargeStore       *postgres.AgentRechargeStore
	agentWalletStore         *postgres.AgentWalletStore
	agentWalletPosting       *walletapp.PostingService
	offlineCreation          *agentrechargeapp.OfflineCreationService
	shopStore                *postgres.ShopStore
	wechatConfigService      WechatConfigServiceInterface
	auditService             AuditServiceInterface
	operationPasswordService OperationPasswordServiceInterface
	redis                    *redis.Client
	logger                   *zap.Logger
}

// New 创建代理预充值服务实例
func New(
	db *gorm.DB,
	agentRechargeStore *postgres.AgentRechargeStore,
	agentWalletStore *postgres.AgentWalletStore,
	shopStore *postgres.ShopStore,
	wechatConfigService WechatConfigServiceInterface,
	auditService AuditServiceInterface,
	operationPasswordService OperationPasswordServiceInterface,
	rdb *redis.Client,
	logger *zap.Logger,
) *Service {
	return &Service{
		db:                       db,
		agentRechargeStore:       agentRechargeStore,
		agentWalletStore:         agentWalletStore,
		shopStore:                shopStore,
		wechatConfigService:      wechatConfigService,
		auditService:             auditService,
		operationPasswordService: operationPasswordService,
		redis:                    rdb,
		logger:                   logger,
	}
}

// SetAgentWalletPostingService 注入代理主钱包统一入账用例。
func (s *Service) SetAgentWalletPostingService(service *walletapp.PostingService) {
	s.agentWalletPosting = service
}

// SetOfflineCreationService 注入员工线下代充值审批申请用例。
func (s *Service) SetOfflineCreationService(service *agentrechargeapp.OfflineCreationService) {
	s.offlineCreation = service
}

// Create 创建代理充值订单
// POST /api/admin/agent-recharges
func (s *Service) Create(ctx context.Context, req *dto.CreateAgentRechargeRequest) (*dto.AgentRechargeResponse, error) {
	userID := middleware.GetUserIDFromContext(ctx)
	userType := middleware.GetUserTypeFromContext(ctx)
	userShopID := middleware.GetShopIDFromContext(ctx)

	// 代理只能充自己店铺
	if userType == constants.UserTypeAgent && req.ShopID != userShopID {
		return nil, errors.New(errors.CodeForbidden, "代理只能为自己的店铺充值")
	}

	// 线下充值仅平台可用
	if req.PaymentMethod == constants.RechargeMethodOffline && userType != constants.UserTypePlatform && userType != constants.UserTypeSuperAdmin {
		return nil, errors.New(errors.CodeForbidden, "线下充值仅平台管理员可操作")
	}

	// 线下充值必须上传支付凭证
	if req.PaymentMethod == constants.RechargeMethodOffline && len(req.PaymentVoucherKey) == 0 {
		return nil, errors.New(errors.CodeInvalidParam, "线下充值必须上传支付凭证")
	}

	if req.Amount < constants.AgentRechargeMinAmount || req.Amount > constants.AgentRechargeMaxAmount {
		return nil, errors.New(errors.CodeInvalidParam, "充值金额超出允许范围")
	}

	rechargeNo := s.generateRechargeNo()
	if req.PaymentMethod == constants.RechargeMethodOffline {
		return s.createOffline(ctx, req, userID, userType, rechargeNo)
	}

	// 查找目标店铺的主钱包
	wallet, err := s.agentWalletStore.GetMainWallet(ctx, req.ShopID)
	if err != nil {
		if err == gorm.ErrRecordNotFound {
			return nil, errors.New(errors.CodeNotFound, "目标店铺主钱包不存在")
		}
		return nil, errors.Wrap(errors.CodeDatabaseError, err, "查询店铺主钱包失败")
	}

	// 查询店铺名称
	shop, err := s.shopStore.GetByID(ctx, req.ShopID)
	if err != nil {
		if err == gorm.ErrRecordNotFound {
			return nil, errors.New(errors.CodeNotFound, "目标店铺不存在")
		}
		return nil, errors.Wrap(errors.CodeDatabaseError, err, "查询店铺失败")
	}

	// 在线支付需要查询生效的支付配置
	var paymentConfigID *uint
	var paymentChannel string
	if req.PaymentMethod == "wechat" {
		activeConfig, cfgErr := s.wechatConfigService.GetActiveConfig(ctx)
		if cfgErr != nil || activeConfig == nil {
			return nil, errors.New(errors.CodeNoPaymentConfig, "当前无可用的支付配置，请联系管理员")
		}
		paymentConfigID = &activeConfig.ID
		paymentChannel = activeConfig.ProviderType
	} else {
		paymentChannel = "offline"
	}

	record := &model.AgentRechargeRecord{
		UserID:            userID,
		AgentWalletID:     wallet.ID,
		ShopID:            req.ShopID,
		RechargeNo:        rechargeNo,
		Amount:            req.Amount,
		PaymentMethod:     req.PaymentMethod,
		PaymentChannel:    &paymentChannel,
		PaymentConfigID:   paymentConfigID,
		PaymentVoucherKey: model.StringJSONBArray(req.PaymentVoucherKey),
		Remark:            req.Remark,
		Status:            constants.RechargeStatusPending,
		ShopIDTag:         wallet.ShopIDTag,
		EnterpriseIDTag:   wallet.EnterpriseIDTag,
	}

	if err := s.agentRechargeStore.Create(ctx, record); err != nil {
		return nil, errors.Wrap(errors.CodeDatabaseError, err, "创建充值订单失败")
	}

	s.logger.Info("创建代理充值订单成功",
		zap.Uint("recharge_id", record.ID),
		zap.String("recharge_no", rechargeNo),
		zap.Int64("amount", req.Amount),
		zap.Uint("shop_id", req.ShopID),
		zap.Uint("user_id", userID),
	)

	resp := toResponse(record, shop.ShopName)
	resp.SubmitterName = s.loadSubmitterNameBestEffort(ctx, record.UserID)
	return resp, nil
}

func (s *Service) createOffline(
	ctx context.Context,
	req *dto.CreateAgentRechargeRequest,
	userID uint,
	userType int,
	rechargeNo string,
) (*dto.AgentRechargeResponse, error) {
	if s.offlineCreation == nil {
		return nil, errors.New(errors.CodeServiceUnavailable, "员工线下代充值审批能力未配置")
	}
	result, err := s.offlineCreation.Execute(ctx, agentrechargeapp.CreateOfflineCommand{
		SubmitterAccountID: userID,
		SubmitterUserType:  userType,
		ShopID:             req.ShopID,
		RechargeNo:         rechargeNo,
		Amount:             req.Amount,
		PaymentVoucherKeys: req.PaymentVoucherKey,
		Remark:             req.Remark,
	})
	if err != nil {
		return nil, err
	}
	resp := toResponse(result.Record, result.ShopName)
	resp.SubmitterName = result.SubmitterName
	resp.ApprovalProvider = constants.IntegrationProviderWeCom
	resp.ApprovalStatus = &result.ApprovalStatus
	resp.ApprovalStatusName = constants.GetApprovalStatusName(result.ApprovalStatus)
	s.logger.Info("创建员工线下代充值审批申请成功",
		zap.Uint("recharge_id", result.Record.ID),
		zap.String("recharge_no", result.Record.RechargeNo),
		zap.Uint("approval_instance_id", *result.Record.ApprovalInstanceID),
		zap.Int64("amount", result.Record.Amount),
		zap.Uint("shop_id", result.Record.ShopID),
		zap.Uint("submitter_id", result.Record.UserID),
	)
	return resp, nil
}

// OfflinePay 线下充值确认
// POST /api/admin/agent-recharges/:id/offline-pay
func (s *Service) OfflinePay(ctx context.Context, id uint, req *dto.AgentOfflinePayRequest) (*dto.AgentRechargeResponse, error) {
	if !legacyOfflineRechargePayEnabled() {
		return nil, errors.New(errors.CodeInvalidStatus, "线下充值人工确认入口已停用，请查看企业微信审批状态")
	}
	userID := middleware.GetUserIDFromContext(ctx)
	userType := middleware.GetUserTypeFromContext(ctx)

	// 仅平台账号可操作
	if userType != constants.UserTypePlatform && userType != constants.UserTypeSuperAdmin {
		return nil, errors.New(errors.CodeForbidden, "仅平台管理员可确认线下充值")
	}

	// 验证全局操作密码
	if err := s.operationPasswordService.Verify(ctx, req.OperationPassword); err != nil {
		return nil, err
	}

	record, err := s.agentRechargeStore.GetByID(ctx, id)
	if err != nil {
		if err == gorm.ErrRecordNotFound {
			return nil, errors.New(errors.CodeNotFound, "充值记录不存在")
		}
		return nil, errors.Wrap(errors.CodeDatabaseError, err, "查询充值记录失败")
	}

	if record.PaymentMethod != constants.RechargeMethodOffline {
		return nil, errors.New(errors.CodeInvalidParam, "该订单非线下充值，不支持此操作")
	}
	if record.ApprovalInstanceID != nil {
		return nil, errors.New(errors.CodeInvalidStatus, "该线下充值申请由企业微信审批决定，不能人工确认")
	}
	if record.Status != constants.RechargeStatusPending {
		return nil, errors.New(errors.CodeInvalidParam, "该订单状态不允许确认支付")
	}

	now := time.Now()
	err = s.db.Transaction(func(tx *gorm.DB) error {
		// 条件更新充值记录状态
		result := tx.Model(&model.AgentRechargeRecord{}).
			Where("id = ? AND status = ?", record.ID, constants.RechargeStatusPending).
			Updates(map[string]interface{}{
				"status":       constants.RechargeStatusCompleted,
				"paid_at":      now,
				"completed_at": now,
			})
		if result.Error != nil {
			return errors.Wrap(errors.CodeDatabaseError, result.Error, "更新充值记录状态失败")
		}
		if result.RowsAffected == 0 {
			return errors.New(errors.CodeInvalidParam, "充值记录状态已变更")
		}

		if s.agentWalletPosting == nil {
			return errors.New(errors.CodeInternalError, "代理主钱包入账能力未配置")
		}
		requestID := ""
		if value := middleware.GetRequestIDFromContext(ctx); value != nil {
			requestID = *value
		}
		if _, err := s.agentWalletPosting.PostInTx(ctx, tx, walletapp.PostingCommand{
			ShopID: record.ShopID, WalletID: record.AgentWalletID, Amount: record.Amount,
			ReferenceType: constants.ReferenceTypeTopup, ReferenceID: record.ID,
			TransactionType: constants.AgentTransactionTypeRecharge, UserID: userID, Creator: userID,
			Remark: "线下充值确认", RequestID: requestID, CorrelationID: record.RechargeNo,
		}); err != nil {
			return err
		}

		return nil
	})

	if err != nil {
		return nil, err
	}

	// 异步记录审计日志
	go s.auditService.LogOperation(ctx, &model.AccountOperationLog{
		OperatorID:    userID,
		OperatorType:  userType,
		OperationType: "offline_recharge_confirm",
		OperationDesc: fmt.Sprintf("确认线下充值，充值单号: %s，金额: %d分", record.RechargeNo, record.Amount),
		RequestID:     middleware.GetRequestIDFromContext(ctx),
		IPAddress:     middleware.GetIPFromContext(ctx),
		UserAgent:     middleware.GetUserAgentFromContext(ctx),
	})

	shop, _ := s.shopStore.GetByID(ctx, record.ShopID)
	shopName := ""
	if shop != nil {
		shopName = shop.ShopName
	}

	// 更新本地对象以反映最新状态
	record.Status = constants.RechargeStatusCompleted
	record.PaidAt = &now
	record.CompletedAt = &now

	resp := toResponse(record, shopName)
	resp.SubmitterName = s.loadSubmitterNameBestEffort(ctx, record.UserID)
	approvalSummaries, err := s.loadApprovalSummaries(ctx, []*model.AgentRechargeRecord{record})
	if err != nil {
		return nil, err
	}
	applyApprovalSummary(resp, approvalSummaries, record.ApprovalInstanceID)
	return resp, nil
}

func legacyOfflineRechargePayEnabled() bool {
	cfg := config.Get()
	return cfg == nil || cfg.Approval.LegacyOfflineRechargePayEnabled
}

// HandlePaymentCallback 处理支付回调
// 幂等处理：status != 待支付则直接返回成功
func (s *Service) HandlePaymentCallback(ctx context.Context, rechargeNo string, paymentMethod string, paymentTransactionID string, paidAmount int64) error {
	paymentTransactionID = strings.TrimSpace(paymentTransactionID)
	record, err := s.agentRechargeStore.GetByRechargeNo(ctx, rechargeNo)
	if err != nil {
		if err == gorm.ErrRecordNotFound {
			return errors.New(errors.CodeNotFound, "充值订单不存在")
		}
		return errors.Wrap(errors.CodeDatabaseError, err, "查询充值订单失败")
	}

	if err := validateAgentRechargePayment(record, paymentMethod, paymentTransactionID, paidAmount); err != nil {
		return err
	}

	// 已完成订单仅在第三方交易号一致时按同一回调幂等成功。
	if record.Status != constants.RechargeStatusPending {
		if record.Status == constants.RechargeStatusCompleted && record.PaymentTransactionID != nil && *record.PaymentTransactionID == strings.TrimSpace(paymentTransactionID) {
			s.logger.Info("代理充值支付回调幂等命中", zap.String("recharge_no", rechargeNo), zap.Int("status", record.Status))
			return nil
		}
		return errors.New(errors.CodeInvalidStatus, "充值订单状态不允许确认支付")
	}
	now := time.Now()
	err = s.db.Transaction(func(tx *gorm.DB) error {
		// 条件更新（WHERE status = 1）
		result := tx.Model(&model.AgentRechargeRecord{}).
			Where("id = ? AND status = ? AND payment_method <> ? AND amount = ?", record.ID, constants.RechargeStatusPending, constants.RechargeMethodOffline, paidAmount).
			Updates(map[string]interface{}{
				"status":                 constants.RechargeStatusCompleted,
				"payment_transaction_id": paymentTransactionID,
				"paid_at":                now,
				"completed_at":           now,
			})
		if result.Error != nil {
			return errors.Wrap(errors.CodeDatabaseError, result.Error, "更新充值记录状态失败")
		}
		if result.RowsAffected == 0 {
			var current model.AgentRechargeRecord
			if err := tx.WithContext(ctx).Unscoped().
				Where("id = ?", record.ID).First(&current).Error; err != nil {
				return errors.Wrap(errors.CodeDatabaseError, err, "复核充值记录终态失败")
			}
			if current.Status == constants.RechargeStatusCompleted && current.PaymentTransactionID != nil && *current.PaymentTransactionID == paymentTransactionID {
				return nil
			}
			return errors.New(errors.CodeConflict, "充值订单已被其他请求处理")
		}

		if s.agentWalletPosting == nil {
			return errors.New(errors.CodeInternalError, "代理主钱包入账能力未配置")
		}
		requestID := ""
		if value := middleware.GetRequestIDFromContext(ctx); value != nil {
			requestID = *value
		}
		if _, err := s.agentWalletPosting.PostInTx(ctx, tx, walletapp.PostingCommand{
			ShopID: record.ShopID, WalletID: record.AgentWalletID, Amount: record.Amount,
			ReferenceType: constants.ReferenceTypeTopup, ReferenceID: record.ID,
			TransactionType: constants.AgentTransactionTypeRecharge, UserID: record.UserID, Creator: record.UserID,
			Remark: "在线支付充值", RequestID: requestID, CorrelationID: record.RechargeNo,
		}); err != nil {
			return err
		}

		return nil
	})

	if err != nil {
		return err
	}

	s.logger.Info("代理充值支付回调处理成功",
		zap.String("recharge_no", rechargeNo),
		zap.Int64("amount", record.Amount),
		zap.Uint("shop_id", record.ShopID),
	)

	return nil
}

func validateAgentRechargePayment(record *model.AgentRechargeRecord, paymentMethod, paymentTransactionID string, paidAmount int64) error {
	if record == nil || strings.TrimSpace(paymentTransactionID) == "" || paidAmount <= 0 || paidAmount != record.Amount {
		return errors.New(errors.CodeInvalidParam, "代理充值支付回调金额或交易号不匹配")
	}
	if record.PaymentMethod == constants.RechargeMethodOffline || record.PaymentConfigID == nil || record.PaymentChannel == nil {
		return errors.New(errors.CodeInvalidStatus, "线下充值订单不能通过支付回调确认")
	}
	channel := strings.TrimSpace(*record.PaymentChannel)
	switch strings.TrimSpace(paymentMethod) {
	case model.PaymentMethodWechat:
		if record.PaymentMethod != constants.RechargeMethodWechat || (channel != model.ProviderTypeWechat && channel != model.ProviderTypeWechatV2) {
			return errors.New(errors.CodeInvalidParam, "代理充值支付渠道不匹配")
		}
	case model.ProviderTypeFuiou:
		if record.PaymentMethod != constants.RechargeMethodWechat || channel != model.ProviderTypeFuiou {
			return errors.New(errors.CodeInvalidParam, "代理充值支付渠道不匹配")
		}
	default:
		return errors.New(errors.CodeInvalidParam, "代理充值支付渠道不受支持")
	}
	return nil
}

// Reject 驳回代理充值订单
// 仅 status=1（待支付）的订单可驳回，驳回后状态变为 6（已驳回），为终态
func (s *Service) Reject(ctx context.Context, id uint, rejectionReason string) error {
	record, err := s.agentRechargeStore.GetByID(ctx, id)
	if err != nil {
		if err == gorm.ErrRecordNotFound {
			return errors.New(errors.CodeNotFound, "充值记录不存在")
		}
		return errors.Wrap(errors.CodeDatabaseError, err, "查询充值记录失败")
	}

	if record.Status != constants.RechargeStatusPending {
		return errors.New(errors.CodeInvalidStatus, "仅待支付订单可驳回")
	}
	if record.ApprovalInstanceID != nil {
		return errors.New(errors.CodeInvalidStatus, "该线下充值申请由企业微信审批决定，不能人工驳回")
	}

	if err := s.agentRechargeStore.UpdateStatusWithRejection(ctx, id, rejectionReason); err != nil {
		if err == gorm.ErrRecordNotFound {
			return errors.New(errors.CodeInvalidStatus, "仅待支付订单可驳回")
		}
		return errors.Wrap(errors.CodeDatabaseError, err, "驳回充值订单失败")
	}

	s.logger.Info("代理充值订单驳回成功",
		zap.Uint("record_id", id),
		zap.String("rejection_reason", rejectionReason),
	)
	return nil
}

// GetByID 根据ID查询充值订单详情
// GET /api/admin/agent-recharges/:id
func (s *Service) GetByID(ctx context.Context, id uint) (*dto.AgentRechargeResponse, error) {
	record, err := s.agentRechargeStore.GetByID(ctx, id)
	if err != nil {
		if err == gorm.ErrRecordNotFound {
			return nil, errors.New(errors.CodeNotFound, "充值记录不存在")
		}
		return nil, errors.Wrap(errors.CodeDatabaseError, err, "查询充值记录失败")
	}

	shop, _ := s.shopStore.GetByID(ctx, record.ShopID)
	shopName := ""
	if shop != nil {
		shopName = shop.ShopName
	}

	resp := toResponse(record, shopName)
	resp.SubmitterName = s.loadSubmitterNameBestEffort(ctx, record.UserID)
	approvalSummaries, err := s.loadApprovalSummaries(ctx, []*model.AgentRechargeRecord{record})
	if err != nil {
		return nil, err
	}
	applyApprovalSummary(resp, approvalSummaries, record.ApprovalInstanceID)
	return resp, nil
}

// List 分页查询充值订单列表
// GET /api/admin/agent-recharges
func (s *Service) List(ctx context.Context, req *dto.AgentRechargeListRequest) ([]*dto.AgentRechargeResponse, int64, error) {
	page := req.Page
	pageSize := req.PageSize
	if page == 0 {
		page = 1
	}
	if pageSize == 0 {
		pageSize = constants.DefaultPageSize
	}

	query := s.db.WithContext(ctx).Model(&model.AgentRechargeRecord{})

	if req.ShopID != nil {
		query = query.Where("shop_id = ?", *req.ShopID)
	}
	if req.Status != nil {
		query = query.Where("status = ?", *req.Status)
	}
	if req.StartDate != "" {
		query = query.Where("created_at >= ?", req.StartDate+" 00:00:00")
	}
	if req.EndDate != "" {
		query = query.Where("created_at <= ?", req.EndDate+" 23:59:59")
	}

	var total int64
	if err := query.Count(&total).Error; err != nil {
		return nil, 0, errors.Wrap(errors.CodeDatabaseError, err, "查询充值记录总数失败")
	}

	var records []*model.AgentRechargeRecord
	offset := (page - 1) * pageSize
	if err := query.Order("created_at DESC").Offset(offset).Limit(pageSize).Find(&records).Error; err != nil {
		return nil, 0, errors.Wrap(errors.CodeDatabaseError, err, "查询充值记录列表失败")
	}

	// 批量查询店铺名称
	shopIDs := make([]uint, 0, len(records))
	for _, r := range records {
		shopIDs = append(shopIDs, r.ShopID)
	}
	shopMap := make(map[uint]string)
	if len(shopIDs) > 0 {
		shops, err := s.shopStore.GetByIDs(ctx, shopIDs)
		if err == nil {
			for _, sh := range shops {
				shopMap[sh.ID] = sh.ShopName
			}
		}
	}
	submitterIDs := make([]uint, 0, len(records))
	for _, record := range records {
		if record.UserID > 0 {
			submitterIDs = append(submitterIDs, record.UserID)
		}
	}
	submitterNames, err := s.loadSubmitterNames(ctx, submitterIDs)
	if err != nil {
		return nil, 0, errors.Wrap(errors.CodeDatabaseError, err, "查询充值提交人失败")
	}
	approvalSummaries, err := s.loadApprovalSummaries(ctx, records)
	if err != nil {
		return nil, 0, err
	}

	list := make([]*dto.AgentRechargeResponse, 0, len(records))
	for _, r := range records {
		item := toResponse(r, shopMap[r.ShopID])
		item.SubmitterName = submitterNames[r.UserID]
		applyApprovalSummary(item, approvalSummaries, r.ApprovalInstanceID)
		list = append(list, item)
	}

	return list, total, nil
}

// generateRechargeNo 生成代理充值订单号
// 格式: ARCH + 14位时间戳 + 6位随机数
func (s *Service) generateRechargeNo() string {
	timestamp := time.Now().Format("20060102150405")
	randomNum := rand.Intn(1000000)
	return fmt.Sprintf("%s%s%06d", constants.AgentRechargeOrderPrefix, timestamp, randomNum)
}

// toResponse 将模型转换为响应 DTO
func toResponse(record *model.AgentRechargeRecord, shopName string) *dto.AgentRechargeResponse {
	resp := &dto.AgentRechargeResponse{
		ID:                 record.ID,
		RechargeNo:         record.RechargeNo,
		ShopID:             record.ShopID,
		ShopName:           shopName,
		AgentWalletID:      record.AgentWalletID,
		Amount:             record.Amount,
		PaymentMethod:      record.PaymentMethod,
		PaymentVoucherKey:  []string(record.PaymentVoucherKey),
		Remark:             record.Remark,
		Status:             record.Status,
		StatusName:         constants.GetRechargeStatusName(record.Status),
		RejectionReason:    record.RejectionReason,
		SubmitterID:        record.UserID,
		ApprovalInstanceID: record.ApprovalInstanceID,
		CreatedAt:          record.CreatedAt.Format("2006-01-02 15:04:05"),
		UpdatedAt:          record.UpdatedAt.Format("2006-01-02 15:04:05"),
	}

	if record.PaymentChannel != nil {
		resp.PaymentChannel = *record.PaymentChannel
	}
	if record.PaymentConfigID != nil {
		resp.PaymentConfigID = record.PaymentConfigID
	}
	if record.PaymentTransactionID != nil {
		resp.PaymentTransactionID = *record.PaymentTransactionID
	}
	if record.PaidAt != nil {
		t := record.PaidAt.Format("2006-01-02 15:04:05")
		resp.PaidAt = &t
	}
	if record.CompletedAt != nil {
		t := record.CompletedAt.Format("2006-01-02 15:04:05")
		resp.CompletedAt = &t
	}

	return resp
}

type approvalSummary struct {
	Provider string
	Status   int
}

func (s *Service) loadApprovalSummaries(
	ctx context.Context,
	records []*model.AgentRechargeRecord,
) (map[uint]approvalSummary, error) {
	ids := make([]uint, 0, len(records))
	seen := make(map[uint]struct{}, len(records))
	for _, record := range records {
		if record == nil || record.ApprovalInstanceID == nil || *record.ApprovalInstanceID == 0 {
			continue
		}
		id := *record.ApprovalInstanceID
		if _, exists := seen[id]; exists {
			continue
		}
		seen[id] = struct{}{}
		ids = append(ids, id)
	}
	summaries := make(map[uint]approvalSummary, len(ids))
	if len(ids) == 0 {
		return summaries, nil
	}
	var instances []model.ApprovalInstance
	if err := s.db.WithContext(ctx).Select("id", "provider", "status").Where("id IN ?", ids).Find(&instances).Error; err != nil {
		return nil, errors.Wrap(errors.CodeDatabaseError, err, "批量查询充值审批状态失败")
	}
	for _, instance := range instances {
		summaries[instance.ID] = approvalSummary{Provider: instance.Provider, Status: instance.Status}
	}
	return summaries, nil
}

func applyApprovalSummary(response *dto.AgentRechargeResponse, summaries map[uint]approvalSummary, instanceID *uint) {
	if response == nil || instanceID == nil {
		return
	}
	summary, exists := summaries[*instanceID]
	if !exists {
		return
	}
	status := summary.Status
	response.ApprovalProvider = summary.Provider
	response.ApprovalStatus = &status
	response.ApprovalStatusName = constants.GetApprovalStatusName(status)
}

func (s *Service) loadSubmitterNames(ctx context.Context, ids []uint) (map[uint]string, error) {
	accounts, err := postgres.NewAccountStore(s.db, nil).GetDisplayAccountsByIDs(ctx, ids)
	if err != nil {
		return nil, err
	}
	names := make(map[uint]string, len(accounts))
	for _, account := range accounts {
		names[account.ID] = account.Username
	}
	return names, nil
}

func (s *Service) loadSubmitterNameBestEffort(ctx context.Context, id uint) string {
	names, err := s.loadSubmitterNames(ctx, []uint{id})
	if err != nil {
		s.logger.Warn("查询充值提交人失败", zap.Uint("submitter_id", id), zap.Error(err))
		return ""
	}
	return names[id]
}
