package com.crm.ucard.service.impl;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.crm.rely.backend.core.constant.Constants;
import com.crm.rely.backend.core.constant.PayConstant;
import com.crm.rely.backend.core.dto.base.BaseReportResultDto;
import com.crm.rely.backend.core.dto.base.BaseResultDto;
import com.crm.rely.backend.core.dto.base.PageDto;
import com.crm.rely.backend.core.dto.base.ResultWithPagerDto;
import com.crm.rely.backend.core.dto.ib.account.AccountInfoDto;
import com.crm.rely.backend.core.dto.ucard.*;
import com.crm.rely.backend.core.dto.wasabi.*;
import com.crm.rely.backend.core.entity.base.BaseEntity;
import com.crm.rely.backend.core.entity.base.SingleLongEntity;
import com.crm.rely.backend.core.entity.finance.balance.FinanceBalanceAddEntity;
import com.crm.rely.backend.core.entity.ib.account.AccountInfoListEntity;
import com.crm.rely.backend.core.entity.ucard.*;
import com.crm.rely.backend.core.entity.wasabi.*;
import com.crm.rely.backend.core.enums.*;
import com.crm.rely.backend.core.pojo.table.CustomInfoTable;
import com.crm.rely.backend.core.pojo.table.FinanceBalanceTable;
import com.crm.rely.backend.core.pojo.table.ucard.*;
import com.crm.rely.backend.exception.ServiceException;
import com.crm.rely.backend.service.MqSendService;
import com.crm.rely.backend.service.RedisService;
import com.crm.rely.backend.util.DateUtil;
import com.crm.rely.backend.util.GetRandom;
import com.crm.rely.backend.util.ListSplitUtil;
import com.crm.rely.backend.util.UUIDUtil;
import com.crm.ucard.config.WasabiConfig;
import com.crm.ucard.dao.mapper.*;
import com.crm.ucard.dao.repository.*;
import com.crm.ucard.model.ResultData;
import com.crm.ucard.service.*;
import com.crm.ucard.util.ObjectIdUtil;
import com.google.common.base.Strings;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.*;
import java.util.stream.Collectors;

@Slf4j
@Service
public class UcardCardServiceImpl implements UcardCardService {

    @Autowired
    private CardApplyRepository cardApplyRepository;
    @Autowired
    private UcardCardRepository cardRepository;
    @Autowired
    private CardActivateRepository cardActivateRepository;
    @Autowired
    private CardRechargeOrderRepository rechargeOrderRepository;
    @Autowired
    private CardMerchantUserRepository merchantUserRepository;
    @Autowired
    private CardKycStatusRepository kycStatusRepository;
    @Autowired
    private CardOperateRepository cardOperateRepository;
    @Autowired
    private CardTypeRepository cardTypeRepository;
    @Autowired
    private CardCountryMapper cardCountryMapper;
    @Autowired
    private MqSendService mqSendService;
    @Autowired
    private CustomInfoRepository customInfoRepository;
    @Autowired
    private CardOccupationsMapper cardOccupationsMapper;
    @Autowired
    private UcardOccupationsRepository occupationsRepository;
    @Autowired
    private UcardWalletRepository ucardWalletRepository;
    @Autowired
    private AccountInfoFeignService accountInfoFeignService;
    @Autowired
    private CardApplyMapper cardApplyMapper;
    @Autowired
    private UcardWalletRecordRepository ucardWalletRecordRepository;
    @Autowired
    private CardWalletRecordMapper walletRecordMapper;
    @Autowired
    private CardOperateMapper operateMapper;
    @Autowired
    private CardKycStatusMapper kycStatusMapper;
    @Autowired
    private CardPasswordResetRepository passwordResetRepository;
    @Autowired
    private CardMerchantUserMapper cardMerchantUserMapper;
    @Autowired
    private CardTypeConfigRepository cardTypeConfigRepository;
    @Autowired
    private CardTypeMapper cardTypeMapper;
    @Autowired
    private CardIdTypeConfigRepository cardIdTypeConfigRepository;
    @Autowired
    private CardMerchantUserMapper merchantUserMapper;
    @Autowired
    private CardWithdrawRepository withdrawRepository;
    @Autowired
    private CardWithdrawMapper withdrawMapper;
    @Autowired
    private Card3dsTransactionMapper card3dsTransactionMapper;
    @Autowired
    private WasabiDocumentApiService wasabiDocumentApiService;
    @Autowired
    private UcardEmailService ucardEmailService;
    @Autowired
    private UcardNumberService ucardNumberService;
    @Autowired
    private CardTransacOrderMapper cardTransacOrderMapper;
    @Autowired
    private CardRechargeOrderMapper rechargeOrderMapper;
    @Autowired
    private UcardCardMapper cardMapper;
    @Autowired
    private CardTransacOrderRepository cardTransacOrderRepository;
    @Autowired
    private RedisService redisService;
    @Autowired
    private SysUcardConfigService sysUcardConfigService;


    /**
     * 更新国家、地区、手机区号
     */
    @Override
    public void cardUpdateCountry() throws Exception {
        cardCountryMapper.deleteByCardCategory(Constants.CARD_CATEGORY_WASABI);

        List<CardCountryTable> tables = new ArrayList<>();
        Date now = new Date();
        // 获取国家地区列表
        List<WasabiRegionDto> wasabiRegionDtos = wasabiDocumentApiService.getRegionList().getData();
        // 获取手机区号列表
        List<WasabiMobileAreaCodeDto> areaCodeDtos = wasabiDocumentApiService.getMobileAreaCode().getData();
        Map<String, String> areaCodeMap = areaCodeDtos.stream()
                .collect(Collectors.toMap(WasabiMobileAreaCodeDto::getAreaCode, WasabiMobileAreaCodeDto::getCode
                ));
        // 获取城市信息
        WasabiCityEntity entity = new WasabiCityEntity();
        List<WasabiCityDto> cityDtos = wasabiDocumentApiService.getCityList(entity).getData();
        for (WasabiCityDto cityDto : cityDtos) {
            CardCountryTable table = new CardCountryTable();
            table.setCode(cityDto.getCode());
            table.setStandardCode(null);
            table.setEnName(cityDto.getName());
            table.setPcode(cityDto.getCountry());
            table.setCardCategory(Constants.CARD_CATEGORY_WASABI);
            table.setAddTime(now);
            tables.add(table);
        }
        for (WasabiRegionDto regionDto : wasabiRegionDtos) {
            CardCountryTable table = new CardCountryTable();
            table.setCode(regionDto.getCode());
            table.setStandardCode(regionDto.getStandardCode());
            table.setEnName(regionDto.getName());
            table.setAreaCode(areaCodeMap.get(regionDto.getCode()));
            table.setCardCategory(Constants.CARD_CATEGORY_WASABI);
            table.setAddTime(now);
            tables.add(table);
        }
        List<List<CardCountryTable>> lists = ListSplitUtil.split(tables);
        for (List<CardCountryTable> list : lists) {
            cardCountryMapper.batchSave(list);
        }
    }

    /**
     * 获取并更新支持的卡BIN列表
     */
    @Override
    public void saveCardTypeList() throws Exception {
        try {
            cardTypeMapper.deleteByCardCategory(Constants.CARD_CATEGORY_WASABI);
            List<WasabiCardTypesDto> list = wasabiDocumentApiService.getCardTypeList();
            List<CardTypeTable> tables = new ArrayList<>();
            Date now = new Date();
            for (WasabiCardTypesDto cardTypeDto : list) {
                CardTypeTable table = new CardTypeTable();
                BeanUtils.copyProperties(cardTypeDto, table);
                table.setRisk(String.join(",", cardTypeDto.getRisk()));
                table.setSupport(String.join(",", cardTypeDto.getSupport()));
                table.setSupportHolderAreaCode(String.join(",", cardTypeDto.getSupportHolderAreaCode()));
                table.setSupportHolderRegin(String.join(",", cardTypeDto.getSupportHolderRegin()));
                if ("Physical".equals(cardTypeDto.getType())) {
                    table.setEnableStatus(1);
                } else {
                    table.setEnableStatus(0);
                }
                WasabiCardTypeHolderMetadataDto holderMetadataDto = cardTypeDto.getMetadata();
                BeanUtils.copyProperties(holderMetadataDto, table);
                table.setCardTypeId(cardTypeDto.getCardTypeId().intValue());
                table.setCardCategory(Constants.CARD_CATEGORY_WASABI);
                table.setAddTime(now);
                tables.add(table);
            }
            cardTypeMapper.batchSave(tables);
        } catch (Exception e) {
            log.error("获取支持的卡BIN列表失败", e);
            throw new ServiceException("获取支持的卡BIN列表失败");
        }
    }

    /**
     * 用户获取卡片类型
     */
    @Override
    public List<CardTypeUserDto> getCardTypeList(CardTypeEntity entity) throws Exception {
        List<CardTypeDto> cardTypeList = cardTypeMapper.getByEnableStatus();
        CardMerchantUserTable userTable = merchantUserRepository.findByCId(entity.getCId());
        List<CardTypeUserDto> dtos = new ArrayList<>();
        for (CardTypeDto typeDto : cardTypeList) {
            CardTypeUserDto dto = new CardTypeUserDto();
            BeanUtils.copyProperties(typeDto, dto);
            BigDecimal cardFee = queryCardFee(userTable, typeDto.getCardTypeId());
            dto.setCardFee(cardFee);
            if (userTable.getCardRechargeFeeRate() != null) {
                dto.setRechargeFeeRate(userTable.getCardRechargeFeeRate());
            }
            entity.setCardTypeId(dto.getCardTypeId());
            CardTypeUserDto cardTypeStatus = cardMerchantUserMapper.getCardTypeStatus(entity);
            if (null != cardTypeStatus) {
                dto.setHolderStatus(cardTypeStatus.getHolderStatus());
                dto.setApplyStatus(cardTypeStatus.getApplyStatus());
                dto.setCardStatus(cardTypeStatus.getCardStatus());
            }
            dtos.add(dto);
        }
        return dtos;
    }

    /**
     * 商户用户注册
     *
     * @param entity 注册请求参数
     * @return 注册结果
     * @throws ServiceException 服务异常
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public BaseResultDto registerMerchantUser(CardMerchantUserEntity entity) throws ServiceException {
        CardMerchantUserTable ctable =
                merchantUserRepository.findFirstByCustomIdAndCardCategory(entity.getCustomId(),
                        Constants.CARD_CATEGORY_WASABI);
        if (ctable != null) {
            return BaseResultDto.error("用户已注册");
        }
        CardMerchantUserTable etable = merchantUserRepository.getByEmailAndCardCategory(entity.getEmail(),
                Constants.CARD_CATEGORY_WASABI);
        if (etable != null) {
            return BaseResultDto.error("邮箱已注册");
        }
        CardMerchantUserTable ptable = merchantUserRepository.getByMobileAndCardCategory(entity.getMobile(),
                Constants.CARD_CATEGORY_WASABI);
        if (ptable != null) {
            return BaseResultDto.error("手机号已注册");
        }

        int nameLength = entity.getLastName().length() + entity.getFirstName().length();
        if (nameLength > 23 || nameLength < 2) {
            return BaseResultDto.error(Constants.PARAMETER_ERROR);
        }
        String code = entity.getCountry();
        CardIdTypeConfigTable idTypeConfigTable = cardIdTypeConfigRepository.findByCode(code);
        if (idTypeConfigTable != null) {
            List<String> idTypes;
            String idType = idTypeConfigTable.getIdType();
            if (StringUtils.isNotEmpty(idType)) {
                if (idType.contains(",")) {
                    idTypes = Arrays.asList(idType.split(","));
                } else {
                    idTypes = Collections.singletonList(idType);
                }
                if (!idTypes.contains(entity.getIdType())) {
                    return BaseResultDto.error(Constants.ID_TYPE_ERROR);
                }
            }
        }

        CardMerchantUserTable table = new CardMerchantUserTable();
        BeanUtils.copyProperties(entity, table);
        table.setMailingCountry(entity.getCountry());
        table.setMailingTown(entity.getTown());
        table.setMailingPostCode(entity.getPostCode());
        table.setMailingAddress(entity.getAddress());
        table.setMailingAddressCn(entity.getAddressCn());
        table.setMailingMobile(entity.getMobile());
        table.setMailingAreaCode(entity.getAreaCode());
        table.setUniqueId(UUID.randomUUID().toString().replace("-", ""));
        table.setAddTime(new Date());
        table.setCardCategory(Constants.CARD_CATEGORY_WASABI);
        table.setAuthStatus(0);
        merchantUserRepository.save(table);

        CardKycStatusTable kycStatusTable = new CardKycStatusTable();
        kycStatusTable.setUniqueId(table.getUniqueId());
        kycStatusTable.setStatus(1);
        kycStatusTable.setCardCategory(Constants.CARD_CATEGORY_WASABI);
        kycStatusTable.setAddTime(new Date());
        kycStatusRepository.save(kycStatusTable);

        CardOperateTable operateTable = new CardOperateTable();
        operateTable.setOperateUser(entity.getOperateUser());
        operateTable.setOperateType(CardOperateTypeEnum.REGISTER_INFO.getCode());
        operateTable.setStatus(Constants.SUCCESS);
        operateTable.setAddTime(new Date());
        operateTable.setUniqueId(table.getUniqueId());
        cardOperateRepository.save(operateTable);

        return BaseResultDto.success(Constants.SUCCESS, table.getId());

    }

    /**
     * 商户用户信息更新
     *
     * @param entity 更新请求参数
     * @return 更新结果
     * @throws ServiceException 服务异常
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public BaseResultDto updateMerchantUser(CardMerchantUserEntity entity) throws ServiceException {
        CardMerchantUserTable etable = merchantUserRepository.getByEmailAndCardCategory(entity.getEmail(),
                Constants.CARD_CATEGORY_WASABI);
        if (etable != null && !entity.getUniqueId().equals(etable.getUniqueId())) {
            return BaseResultDto.error("邮箱已存在");
        }
        CardMerchantUserTable ptable = merchantUserRepository.getByMobileAndCardCategory(entity.getMobile(),
                Constants.CARD_CATEGORY_WASABI);
        if (ptable != null && !entity.getUniqueId().equals(ptable.getUniqueId())) {
            return BaseResultDto.error("手机号已存在");
        }
        int nameLength = entity.getLastName().length() + entity.getFirstName().length();
        if (nameLength > 23 || nameLength < 2) {
            return BaseResultDto.error(Constants.PARAMETER_ERROR);
        }
        String code = entity.getCountry();
        CardIdTypeConfigTable idTypeConfigTable = cardIdTypeConfigRepository.findByCode(code);
        if (idTypeConfigTable != null) {
            List<String> idTypes;
            String idType = idTypeConfigTable.getIdType();
            if (StringUtils.isNotEmpty(idType)) {
                if (idType.contains(",")) {
                    idTypes = Arrays.asList(idType.split(","));
                } else {
                    idTypes = Collections.singletonList(idType);
                }
                if (!idTypes.contains(entity.getIdType())) {
                    return BaseResultDto.error(Constants.ID_TYPE_ERROR);
                }
            }
        }

        try {
            CardMerchantUserTable table =
                    merchantUserRepository.findFirstByCustomIdAndCardCategory(entity.getCustomId(),
                            Constants.CARD_CATEGORY_WASABI);
            BeanUtils.copyProperties(entity, table);
            table.setMailingCountry(entity.getCountry());
            table.setMailingTown(entity.getTown());
            table.setMailingPostCode(entity.getPostCode());
            table.setMailingAddress(entity.getAddress());
            table.setMailingAddressCn(entity.getAddressCn());
            table.setMailingMobile(entity.getMobile());
            table.setMailingAreaCode(entity.getAreaCode());
            table.setModifyTime(new Date());
            merchantUserRepository.save(table);

            CardKycStatusDto kycStatusTable = kycStatusMapper.getKycApproveByUniqueId(table.getUniqueId());
            if (kycStatusTable == null) {
                return BaseResultDto.error("审核记录不存在");
            }
            if (kycStatusTable.getStatus() != 1 && kycStatusTable.getStatus() != 2) {
                CardKycStatusTable statusTable = new CardKycStatusTable();
                statusTable.setUniqueId(table.getUniqueId());
                statusTable.setStatus(1);
                statusTable.setCardCategory(Constants.CARD_CATEGORY_WASABI);
                statusTable.setAddTime(new Date());
                kycStatusRepository.save(statusTable);
            }

            CardOperateTable operateTable = new CardOperateTable();
            operateTable.setOperateUser(entity.getOperateUser());
            operateTable.setOperateType(CardOperateTypeEnum.UPDATE_INFO.getCode());
            operateTable.setStatus(Constants.SUCCESS);
            operateTable.setAddTime(new Date());
            operateTable.setUniqueId(table.getUniqueId());
            cardOperateRepository.save(operateTable);

            return BaseResultDto.success();
        } catch (Exception e) {
            log.error("商户用户信息更新失败", e);
            throw new ServiceException("商户用户信息更新失败");
        }
    }

    /**
     * 更新邮寄地址
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public BaseResultDto updateUserMailingAddress(WasabiSaveUserMailingAddressEntity entity) throws ServiceException {
        if (StringUtils.isNotEmpty(entity.getMailingAddress()) && entity.getMailingAddress().length() > 200) {
            return BaseResultDto.error("邮寄地址过长");
        }
        CardMerchantUserTable userTable = merchantUserRepository.findByUniqueId(entity.getUniqueId());
        if (userTable == null) {
            return BaseResultDto.error("用户不存在");
        }
        BeanUtils.copyProperties(entity, userTable);
        merchantUserRepository.save(userTable);
        return BaseResultDto.success();
    }

    /**
     * 查看用户详情
     *
     * @param customId
     * @return
     * @throws ServiceException
     */
    @Override
    public BaseResultDto merchantUserSingle(Long customId) throws ServiceException {
        MerchantUserDto dto = merchantUserMapper.getFirstByCustomId(customId);
        if (dto == null) {
            return BaseResultDto.success("用户不存在");
        }
        CardKycStatusDto kycTable = kycStatusMapper.getKycApproveByUniqueId(dto.getUniqueId());
        if (kycTable != null) {
            dto.setApproveStatus(kycTable.getStatus());
        }

        return BaseResultDto.success(dto);
    }


    /**
     * 开卡申请
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public BaseResultDto applyCard(CardApplyEntity entity) throws Exception {
        // 查询用户信息 提交注册流程
        CardMerchantUserTable userTable = merchantUserRepository.getByUniqueId(entity.getUniqueId());
        if (null == userTable) {
            throw new ServiceException(Constants.INFO_NOT_FOUND);
        }
        CardKycStatusTable kycStatusTable = kycStatusRepository.getFirstByUniqueIdAndStatus(entity.getUniqueId(), 2);
        if (kycStatusTable == null) {
            return BaseResultDto.error("kyc审核未完成，请等待kyc审核通过");
        }

        // 查询是否存在开卡中的数据
        CardApplyTable table = cardApplyMapper.findByUniqueIdAndCardTypeId(entity.getUniqueId(),
                entity.getCardTypeId());
        if (table != null) {
            return BaseResultDto.error("已存在开卡申请记录");
        }

        table = new CardApplyTable();
        BeanUtils.copyProperties(entity, table);
        table.setLastName(userTable.getLastName());
        table.setFirstName(userTable.getFirstName());
        table.setAreaCode(userTable.getAreaCode());
        table.setMobile(userTable.getMobile());
        table.setMailingCountry(userTable.getMailingCountry());
        table.setMailingTown(userTable.getMailingTown());
        table.setMailingPostCode(userTable.getMailingPostCode());
        table.setEmail(userTable.getEmail());
        table.setMailingAddress(userTable.getMailingAddress());
        table.setMailingAddressCn(userTable.getMailingAddressCn());
        table.setMailingAreaCode(userTable.getMailingAreaCode());
        table.setMailingMobile(userTable.getMailingMobile());
        table.setAddTime(new Date());
        table.setTradeType(1);
        table.setApproveStatus(CardApproveStatusEnum.PENDING.getCode());
        CardTypeTable typeTable = cardTypeRepository.findByCardTypeId(entity.getCardTypeId());
        if (typeTable.getNeedCardHolder()) {
            // 查询记录中是否有创建持卡人成功的记录
            CardApplyTable cardApplyTable =
                    cardApplyRepository.getFirstByUniqueIdAndCardTypeIdAndHolderStatus(entity.getUniqueId(),
                            entity.getCardTypeId(), "pass_audit");

            WasabiConfig config = wasabiDocumentApiService.getWasabiConfig();
            if (cardApplyTable != null) {
                table.setHolderMerchantOrderNo(cardApplyTable.getHolderMerchantOrderNo());
                table.setHolderStatus(cardApplyTable.getHolderStatus());
                table.setHolderDescription(cardApplyTable.getHolderDescription());
                table.setStatusFlowLocation(cardApplyTable.getStatusFlowLocation());
                table.setHolderId(cardApplyTable.getHolderId());
                table.setRespMsg(cardApplyTable.getRespMsg());
            } else {
                table.setHolderMerchantOrderNo(ObjectIdUtil.genSnowFlakeIdStr(config.getMerchantTag()));
            }
        }
        //手续费
        if (entity.getDiscountType() == null) {
            table.setTradeStatus(2);
            cardApplyRepository.save(table);
            ucardEmailService.sendApplyCardReviewEmail(table);
        } else if (1 == entity.getDiscountType()) {
            // 查询卡费用 用户配置->币种配置->系统配置
            BigDecimal cardFee = queryCardFee(userTable, entity.getCardTypeId());
            if (cardFee == null || cardFee.compareTo(BigDecimal.ZERO) == 0) {
                table.setTradeStatus(2);
                table.setCardFee(BigDecimal.ZERO);
                cardApplyRepository.save(table);
            } else {
                AccountInfoListEntity accountEntity = new AccountInfoListEntity();
                accountEntity.setCustomId(userTable.getCustomId());
                accountEntity.setPlatform(entity.getPlatform());
                accountEntity.setLogin(entity.getLogin());
                AccountInfoDto dto = accountInfoFeignService.accountDropdownSingle(accountEntity);

                if (BigDecimal.valueOf(dto.getBalance()).compareTo(cardFee) < 0) {
                    throw ServiceException.exception("账户余额不足");
                }

                //金额打入交易账户
                String serial = GetRandom.getOrderNo("CARD");
                table.setTradeStatus(1);
                table.setSerial(serial);
                table.setCardFee(cardFee);
                cardApplyRepository.save(table);

                FinanceBalanceAddEntity financeBalanceAddEntity = new FinanceBalanceAddEntity();
                financeBalanceAddEntity.setAmount(cardFee.negate());
                financeBalanceAddEntity.setSerial(serial);
                financeBalanceAddEntity.setLogin(entity.getLogin());
                financeBalanceAddEntity.setCallbackMq(Constants.WASABI_CARD_APPLY_CALLBACK);
                mqSendService.send(Constants.FINANCE_BALANCE_INFO, JSONObject.toJSONString(financeBalanceAddEntity));
            }

        } else if (2 == entity.getDiscountType()) {
            CustomInfoTable infoTable = customInfoRepository.findFirstById(userTable.getCustomId());
            if (infoTable.getCardApplyReduction() == null || infoTable.getCardApplyReduction() <= 0) {
                throw ServiceException.exception("开卡减免次数不足");
            }
            infoTable.setCardApplyReduction(infoTable.getCardApplyReduction() - 1);
            customInfoRepository.save(infoTable);

            table.setTradeStatus(2);
            cardApplyRepository.save(table);
            // 发邮件通知审核人员审核
            ucardEmailService.sendApplyCardReviewEmail(table);
        }
        CardOperateTable operateTable = new CardOperateTable();
        operateTable.setOperateUser(entity.getCId());
        operateTable.setOperateType(CardOperateTypeEnum.CARD_APPLICATION.getCode());
        operateTable.setStatus(Constants.SUCCESS);
        operateTable.setAddTime(new Date());
        operateTable.setUniqueId(entity.getUniqueId());
        cardOperateRepository.save(operateTable);

        return BaseResultDto.success();
    }

    /**
     * 查询卡片费用
     */
    public BigDecimal queryCardFee(CardMerchantUserTable table, Integer cardTypeId) throws Exception {
        if (table.getCardFee() != null) {
            return table.getCardFee();
        }
        CardTypeConfigTable configTable = cardTypeConfigRepository.getByCardTypeId(cardTypeId);
        if (configTable != null) {
            if (configTable.getCardFee() != null) {
                return configTable.getCardFee();
            }
        }
        SysUcardConfigTable sysUcardConfigTable = sysUcardConfigService.getByCode(Constants.WASABI_CARD_APPLY_AMOUNT);
        if (sysUcardConfigTable == null) {
            throw ServiceException.exception(Constants.SYSTEM_ERROR);
        }
        return new BigDecimal(sysUcardConfigTable.getValue());
    }

    /**
     * 开卡申请审批
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public BaseResultDto cardApplyApprove(CardApplyApproveEntity entity) throws Exception {
        CardApplyTable cardApplyTable = cardApplyRepository.findFirstById(entity.getId());
        if (cardApplyTable == null) {
            throw new ServiceException("卡申请记录不存在");
        }
        cardApplyTable.setCardNumber(entity.getCardNumber());
        if (entity.getApproveStatus() == null) {
            throw new ServiceException("请选择审批结果");
        }
        if (entity.getApproveStatus() == 2) {
            cardApplyTable.setApproveStatus(CardApproveStatusEnum.APPROVED.getCode());
            WasabiConfig config = wasabiDocumentApiService.getWasabiConfig();
            createHolderAndOpenCard(cardApplyTable, config);
        } else if (entity.getApproveStatus() == 3) {
            cardApplyTable.setApproveStatus(CardApproveStatusEnum.REJECTED.getCode());
            cardApplyTable.setApproveDesc(entity.getApproveDesc());
            cardApplyTable.setTradeType(2);
            cardApplyTable.setStatus(Constants.FAIL);
            cardApplyTable.setHolderStatus("reject");

            failure(cardApplyTable);
            //审批失败给客户发邮件
            CardMerchantUserTable userTable = merchantUserRepository.getByUniqueId(cardApplyTable.getUniqueId());
            ucardEmailService.sendOpenCardApprovalFailEmail(userTable, Long.valueOf(entity.getApproveDesc()));
        }
        CardOperateTable operateTable = new CardOperateTable();
        operateTable.setOperateUser(entity.getCId());
        operateTable.setOperateType(CardOperateTypeEnum.CARD_APPROVAL.getCode());
        operateTable.setStatus(Constants.SUCCESS);
        operateTable.setAddTime(new Date());
        operateTable.setUniqueId(cardApplyTable.getUniqueId());
        cardOperateRepository.save(operateTable);

        return BaseResultDto.success();
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void updateCardLogisticsStatus(UcardCardTable ucardCardTable) throws ServiceException {
        UcardCardTable table = cardRepository.findFirstById(ucardCardTable.getId());
        // 获取当前时间时间戳
        long now = System.currentTimeMillis();
        long time = table.getAddTime().getTime();
        // 判断两个时间戳差值是否在1天到6天之间
        long timeDiff = now - time; // 时间差（毫秒）
        long dayInMillis = 24 * 60 * 60 * 1000L;
        if (timeDiff >= dayInMillis && timeDiff < 6 * dayInMillis && !"2".equals(table.getLogisticsStatus())) {
            // 1-6天
            table.setLogisticsStatus("2");
        } else if (timeDiff >= 6 * dayInMillis && timeDiff < 11 * dayInMillis && !"3".equals(table.getLogisticsStatus())) {
            // 6-11天
            table.setLogisticsStatus("3");
        } else if (timeDiff > 11 * dayInMillis && !"4".equals(table.getLogisticsStatus())) {
            // 11天以上
            table.setLogisticsStatus("4");
        }
        cardRepository.save(table);
        if (!"4".equals(table.getLogisticsStatus())) {
            mqSendService.send(Constants.CARD_LOGISTICS_STATUS_UPDATE, JSONObject.toJSONString(table),
                    5 * 24 * 3600 * 1000);
        }
    }

    /**
     * 用户开卡申请详情
     */
    @Override
    public BaseResultDto cardApplyDetails(BaseEntity entity) throws ServiceException {
        if (entity.getId() == null || entity.getId() <= 0) {
            return BaseResultDto.success();
        }
        CardApplyDto dto = cardApplyMapper.findById(entity);
        return BaseResultDto.success(dto);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void deductionCallback(FinanceBalanceTable entity) throws Exception {

        CardApplyTable table = cardApplyRepository.getBySerial(entity.getSerial());
        if (table == null) {
            log.error("CARD_APPLY_INFO,entity is null");
            return;
        }
        if (table.getTradeStatus() == 2) {
            return;
        }
        if (!table.getTradeStatus().equals(entity.getTradeStatus())) {
            // 判断手续费状态 1-处理中，2-成功，3-失败 数据库默认处理中，成功继续开卡流程，失败直接改变状态为失败
            if (entity.getTradeStatus() == 3) {
                table.setStatus(Constants.FAIL);
                table.setHolderStatus("reject");
                table.setTradeStatus(3);
            } else if (entity.getTradeStatus() == 2) {
                table.setTradeStatus(2);
                // 发邮件通知审核人员审核
                ucardEmailService.sendApplyCardReviewEmail(table);
            }
            cardApplyRepository.save(table);
        }
    }

    /**
     * 注册用户并开卡
     */
    @Transactional(rollbackFor = Exception.class)
    public void createHolderAndOpenCard(CardApplyTable table, WasabiConfig config) throws Exception {
        ResultData<WasabiUserDto> wasabiUserDto;
        WasabiUserDto userDto = new WasabiUserDto();
        CardTypeTable typeTable = cardTypeRepository.findByCardTypeId(table.getCardTypeId());
        if (typeTable.getNeedCardHolder()) {
            CardMerchantUserTable userTable = merchantUserRepository.getByUniqueId(table.getUniqueId());
            if (StringUtils.isEmpty(table.getHolderStatus())) {
                WasabiUserEntity userEntity = new WasabiUserEntity();
                BeanUtils.copyProperties(userTable, userEntity);
                userEntity.setCardTypeId(Long.valueOf(table.getCardTypeId()));
                userEntity.setMerchantOrderNo(table.getHolderMerchantOrderNo());

                // 查询开卡申请记录是否存在失败的记录 如果存在查询三方持卡人信息 如果存在信息则调用持卡人修改接口，否则创建持卡人
                CardApplyTable cardApplyTable =
                        cardApplyMapper.findByUniqueIdAndHolderIdNotNullAndHolderStatusIsReject(userTable.getUniqueId());
                boolean isUpdate = false;
                if (cardApplyTable != null) {
                    // 查询三方是否存在该持卡人信息
                    WasabiHolderQueryEntity queryEntity = new WasabiHolderQueryEntity();
                    queryEntity.setHolderId(cardApplyTable.getHolderId());
                    WasabiHolderQueryDto holderQueryDto = wasabiDocumentApiService.getHolderInfo(queryEntity, config).get(0);
                    if (holderQueryDto != null) {
                        isUpdate = true;
                        userEntity.setHolderId(cardApplyTable.getHolderId());
                    }
                }
                // 判断 B2B或B2C 模式
                if (StringUtils.isNotEmpty(typeTable.getCardHolderModel()) &&
                        "B2B".equals(typeTable.getCardHolderModel())) {
                    userEntity.setCardHolderModel("B2B");
                } else {
                    // 上传文件
                    String idFrontId = wasabiDocumentApiService.uploadFile(userTable.getIdFrontUrl(), "card");
                    String idBackId = wasabiDocumentApiService.uploadFile(userTable.getIdBackUrl(), "card");
                    String idHoldId = wasabiDocumentApiService.uploadFile(userTable.getIdHoldUrl(), "card");
                    userTable.setIdFrontId(idFrontId);
                    userTable.setIdBackId(idBackId);
                    userTable.setIdHoldId(idHoldId);
                    merchantUserRepository.save(userTable);
                    userEntity.setIdFrontId(idFrontId);
                    userEntity.setIdBackId(idBackId);
                    userEntity.setIdHoldId(idHoldId);
                    userEntity.setCardHolderModel("B2C");
                }
                if (isUpdate) {
                    userEntity.setMerchantOrderNo(null);
                    wasabiUserDto = wasabiDocumentApiService.updateHolderV2(userEntity, config);
                } else {
                    wasabiUserDto = wasabiDocumentApiService.createHolderV2(userEntity, config);
                }
                //创建持卡人报错直接失败并退费
                if (!wasabiUserDto.isSuccess()) {
                    ucardNumberService.saveCardNumberStatus(table.getCardNumber(), 1);
                    table.setHolderStatus("reject");
                    table.setStatus(Constants.FAIL);
                    table.setTradeType(2);
                    table.setNote(wasabiUserDto.getMsg());
                    failure(table);
                    return;
                }
                userDto = wasabiUserDto.getData();

                table.setStatusFlowLocation(userDto.getStatusFlowLocation());
                table.setHolderStatus(userDto.getStatus());
                table.setHolderId(userDto.getHolderId());
                table.setHolderDescription(userDto.getDescription());
                table.setRespMsg(userDto.getRespMsg());
                table.setStatus("reject".equals(userDto.getStatus()) ? Constants.FAIL : null);
            } else {
                userDto.setStatus(table.getHolderStatus());
            }
            if (StringUtils.isEmpty(table.getStatus()) &&
                    "pass_audit".equals(userDto.getStatus())) {
                // 开卡
                createHolderAfterOpenCard(config, table);
            }
        } else {
            if (StringUtils.isEmpty(table.getStatus())) {
                // 开卡
                createHolderAfterOpenCard(config, table);
            }
        }
        cardApplyRepository.save(table);

        if (Constants.FAIL.equals(table.getStatus())) {
            ucardNumberService.saveCardNumberStatus(table.getCardNumber(), 1);
            table.setTradeType(2);
            failure(table);
            return;
        }

        mqSendService.send(Constants.WASABICARD_CARD_APPLY_PROGRESS, JSON.toJSONString(table), 3 * 60 * 1000);
    }


    /**
     * 创建持卡人或开卡失败
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void failure(CardApplyTable table) throws Exception {
        if (table.getDiscountType() == null) {
            table.setTradeStatus(2);
            cardApplyRepository.save(table);
        } else if (table.getDiscountType() == 1) {
            if (table.getCardFee().compareTo(BigDecimal.ZERO) == 0) {
                table.setTradeStatus(2);
                cardApplyRepository.save(table);
            } else {
                String refundSerial = GetRandom.getOrderNo("CARD");
                table.setTradeStatus(1);
                table.setRefundSerial(refundSerial);
                cardApplyRepository.save(table);

                FinanceBalanceAddEntity financeBalanceAddEntity = new FinanceBalanceAddEntity();
                financeBalanceAddEntity.setAmount(table.getCardFee());
                financeBalanceAddEntity.setSerial(refundSerial);
                financeBalanceAddEntity.setLogin(table.getLogin());
                financeBalanceAddEntity.setCallbackMq(Constants.WASABI_CARD_REFUND_CALLBACK);
                mqSendService.send(Constants.FINANCE_BALANCE_INFO, JSONObject.toJSONString(financeBalanceAddEntity));
            }
        } else if (table.getDiscountType() == 2) {
            CardMerchantUserTable userTable = merchantUserRepository.getByUniqueId(table.getUniqueId());
            CustomInfoTable infoTable = customInfoRepository.findFirstById(userTable.getCustomId());
            infoTable.setCardApplyReduction(infoTable.getCardApplyReduction() + 1);
            customInfoRepository.save(infoTable);
            table.setTradeStatus(2);
            cardApplyRepository.save(table);
        }
    }

    /**
     * 手续费退费
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void refundCallback(FinanceBalanceTable balanceTable) throws Exception {

        CardApplyTable table = cardApplyRepository.getByRefundSerial(balanceTable.getSerial());
        if (table == null) {
            log.error("CARD_APPLY_INFO,entity is null");
            return;
        }
        if (table.getTradeType() != 2 || table.getTradeStatus() == 2) {
            return;
        }
        if (!table.getTradeStatus().equals(balanceTable.getTradeStatus())) {
            table.setTradeStatus(balanceTable.getTradeStatus());
            cardApplyRepository.save(table);
        }
    }

    /**
     * 在持卡人创建完成后进行开卡
     */
    private void createHolderAfterOpenCard(WasabiConfig config, CardApplyTable table) throws Exception {
        // 开卡
        WasabiOpenCardEntity cardEntity = new WasabiOpenCardEntity();
        cardEntity.setMerchantOrderNo(ObjectIdUtil.genSnowFlakeIdStr(config.getMerchantTag()));
        cardEntity.setHolderId(table.getHolderId());
        cardEntity.setCardTypeId(Long.valueOf(table.getCardTypeId()));
        cardEntity.setAmount(table.getAmount());
        cardEntity.setCardNumber(table.getCardNumber());

        ResultData<List<WasabiOpenCardDto>> resultData = wasabiDocumentApiService.openCard(cardEntity, config);
        if (resultData.isSuccess()) {
            WasabiOpenCardDto wasabiOpenCardDto = resultData.getData().get(0);
            BeanUtils.copyProperties(wasabiOpenCardDto, table);
        } else {
            table.setStatus(Constants.FAIL);
            table.setNote(resultData.getMsg());
        }
    }

    /**
     * 卡申请进度查询
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void callbackCardApplyProgress(CardApplyTable table) throws Exception {
        //如果开卡成功，判断卡片是否添加
        if (!Strings.isNullOrEmpty(table.getStatus()) && Constants.SUCCESS.equals(table.getStatus())) {
            ucardNumberService.saveCardNumberStatus(table.getCardNumber(), 3);
            UcardCardTable cardTable = cardRepository.findByCardNo(table.getCardNo());
            if (cardTable == null) {
                cardTable = new UcardCardTable();
                BeanUtils.copyProperties(table, cardTable);
                cardTable.setId(null);
                cardTable.setStatus(CardStatusTypeEnum.UN_ACTIVATE.getCode());
                cardTable.setFreezeStatus(Constants.SUCCESS);
                cardTable.setFreezeType("1");
                cardTable.setAddTime(new Date());
                cardTable.setLogisticsStatus("1");
                cardRepository.save(cardTable);
                mqSendService.send(Constants.CARD_LOGISTICS_STATUS_UPDATE, JSONObject.toJSONString(cardTable),
                        24 * 60 * 60 * 1000);
                ucardEmailService.sendOpenCardSuccessEmail(cardTable);
            }
            return;
        }

        CardApplyProgressEntity entity = new CardApplyProgressEntity();
        entity.setId(table.getId());
        queryApplyProgress(entity);

    }

    /**
     * 查询开卡进度
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public BaseResultDto queryApplyProgress(CardApplyProgressEntity request) throws Exception {
        if (request.getId() == null || request.getId() <= 0) {
            return BaseResultDto.success();
        }
        WasabiConfig config = wasabiDocumentApiService.getWasabiConfig();

        CardApplyTable table = cardApplyRepository.findFirstById(request.getId());
        if (table == null) {
            throw new ServiceException(Constants.INFO_NOT_FOUND);
        }
        if (2 != table.getTradeStatus()) {
            return BaseResultDto.success(table);
        }
        if (Constants.SUCCESS.equals(table.getStatus())) {
            return BaseResultDto.success(table);
        }
        CardTypeTable typeTable = cardTypeRepository.findByCardTypeId(table.getCardTypeId());
        if (typeTable.getNeedCardHolder()) {
            if (StringUtils.isEmpty(table.getHolderStatus())) {
                createHolderAndOpenCard(table, config);
            } else {
                // 如果持卡人未创建成功 查询持卡人最新状态
                if (!"pass_audit".equals(table.getHolderStatus())) {
                    WasabiHolderQueryEntity holderQueryEntity = new WasabiHolderQueryEntity();
                    holderQueryEntity.setPageNum(1);
                    holderQueryEntity.setPageSize(10);
                    holderQueryEntity.setMerchantOrderNo(table.getHolderMerchantOrderNo());
                    WasabiHolderQueryDto holderQueryDto = wasabiDocumentApiService.getHolderInfo(holderQueryEntity, config).get(0);
                    if (holderQueryDto == null) {
                        return BaseResultDto.success();
                    }
                    // 状态不一致更新状态，如果持卡人创建失败更新失败状态并按需退费
                    if (!holderQueryDto.getStatus().equals(table.getHolderStatus())) {
                        table.setHolderId(holderQueryDto.getHolderId());
                        table.setHolderStatus(holderQueryDto.getStatus());
                        table.setHolderDescription(holderQueryDto.getDescription());
                        cardApplyRepository.save(table);
                        if ("reject".equals(table.getHolderStatus())) {
                            ucardNumberService.saveCardNumberStatus(table.getCardNumber(), 1);
                            table.setStatus(Constants.FAIL);
                            table.setTradeType(2);
                            failure(table);
                            return BaseResultDto.success(table);
                        }
                    }
                }

                if ("pass_audit".equals(table.getHolderStatus()) && (StringUtils.isEmpty(table.getStatus()))) {
                    createHolderAfterOpenCard(config, table);
                }
            }
        } else {
            if (StringUtils.isEmpty(table.getStatus())) {
                createHolderAfterOpenCard(config, table);
            }
        }
        cardApplyRepository.save(table);

        if ("processing".equals(table.getStatus()) || "wait_process".equals(table.getStatus())) {
            // 获取卡交易记录
            WasabiTransactionEntity transactionEntity = new WasabiTransactionEntity();
            transactionEntity.setType("create");
            transactionEntity.setMerchantOrderNo(table.getMerchantOrderNo());
            List<WasabiTransactionDto> dtos = wasabiDocumentApiService.getCardTransactionList(transactionEntity);
            if (CollectionUtils.isEmpty(dtos)) {
                return BaseResultDto.success(table);
            }
            WasabiTransactionDto wasabiTransactionDto = dtos.get(0);
            if (!table.getStatus().equals(wasabiTransactionDto.getStatus())) {
                BeanUtils.copyProperties(wasabiTransactionDto, table);
                table.setModifyTime(new Date());
                cardApplyRepository.save(table);
            }
        }

        if (Constants.SUCCESS.equals(table.getStatus())) {
            ucardNumberService.saveCardNumberStatus(table.getCardNumber(), 3);
            UcardCardTable cardTable = cardRepository.findByCardNo(table.getCardNo());
            if (cardTable == null) {
                cardTable = new UcardCardTable();
                BeanUtils.copyProperties(table, cardTable);
                cardTable.setId(null);
                cardTable.setStatus(CardStatusTypeEnum.UN_ACTIVATE.getCode());
                cardTable.setFreezeType("1");
                cardTable.setFreezeStatus(Constants.SUCCESS);
                cardTable.setAddTime(new Date());
                cardTable.setLogisticsStatus("1");
                cardRepository.save(cardTable);
                ucardEmailService.sendOpenCardSuccessEmail(cardTable);
                mqSendService.send(Constants.CARD_LOGISTICS_STATUS_UPDATE, JSONObject.toJSONString(cardTable),
                        24 * 60 * 60 * 1000);
            }
        }
        if (Constants.FAIL.equals(table.getStatus())) {
            ucardNumberService.saveCardNumberStatus(table.getCardNumber(), 1);
            table.setTradeType(2);
            failure(table);
        }
        return BaseResultDto.success(table);
    }

    /**
     * 激活卡
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public BaseResultDto<WasabiActiveCardDto> activeCard(WasabiActiveCardEntity entity) throws Exception {
        UcardCardTable table = cardRepository.findByCardNo(entity.getCardNo());
        if (table.getBlocked() != null && table.getBlocked()) {
            throw new ServiceException("该卡片已被锁定");
        }
        if (StringUtils.isNotEmpty(table.getCancelStatus()) && !Constants.FAIL.equals(table.getCancelStatus())) {
            throw new ServiceException("卡片注销状态不允许操作");
        }
        if ("wait_process".equals(table.getStatus()) || "processing".equals(table.getStatus())) {
            throw new ServiceException("该卡片正在激活中");
        }
        if (Constants.SUCCESS.equals(table.getStatus())) {
            throw new ServiceException("该卡片已激活");
        }

        try {
            WasabiActiveCardDto dto = wasabiDocumentApiService.activeCard(entity);
            CardActivateTable activateTable = new CardActivateTable();
            dto.setStatus("processing");
            BeanUtils.copyProperties(entity, activateTable);
            BeanUtils.copyProperties(dto, activateTable);
            activateTable.setUniqueId(table.getUniqueId());
            activateTable.setAddTime(new Date());
            cardActivateRepository.save(activateTable);

            BeanUtils.copyProperties(entity, table);
            table.setStatus("processing");
            table.setModifyTime(new Date());
            if (StringUtils.isEmpty(table.getLogisticsStatus()) ||
                    (StringUtils.isNotEmpty(table.getLogisticsStatus())) && !"4".equals(table.getLogisticsStatus())) {
                table.setLogisticsStatus("4");
            }
            cardRepository.save(table);

            CardOperateTable operateTable = new CardOperateTable();
            operateTable.setCardNo(table.getCardNo());
            operateTable.setMerchantOrderNo(entity.getMerchantOrderNo());
            operateTable.setOperateUser(entity.getCId());
            operateTable.setOperateType(CardOperateTypeEnum.ACTIVATE_CARD.getCode());
            operateTable.setStatus(Constants.SUCCESS);
            operateTable.setAddTime(new Date());
            operateTable.setUniqueId(table.getUniqueId());
            cardOperateRepository.save(operateTable);

            return BaseResultDto.success();
        } catch (Exception e) {
            log.error("激活卡失败", e);
            throw new ServiceException("激活卡失败");
        }
    }


    /**
     * 获取卡余额
     */
    @Override
    public BaseResultDto<WasabiBalanceInfoDto> getBalanceInfo(WasabiBalanceInfoEntity entity) throws ServiceException {
        UcardCardTable cardTable = cardRepository.getByCardNo(entity.getCardNo());
        if (cardTable != null && CardStatusTypeEnum.UN_ACTIVATE.getCode().equals(cardTable.getStatus())) {
            throw new ServiceException("卡片未激活");
        }
        try {
            return wasabiDocumentApiService.getBalanceInfo(entity);
        } catch (Exception e) {
            log.error("获取卡余额失败", e);
            throw new ServiceException("获取卡余额失败");
        }
    }

    /**
     * 调整钱包余额
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public BaseResultDto updateBalance(WasabiUpdateBalanceEntity entity) throws ServiceException {
        if (entity.getType() == null) {
            return BaseResultDto.error("请选择转入转出类型");
        }
        UcardWalletTable table = ucardWalletRepository.findFirstByCId(entity.getCId());
        if (table == null) {
            throw new ServiceException("用户钱包不存在");
        }
        if (entity.getAmount() == null || entity.getAmount().compareTo(BigDecimal.ZERO) < 0) {
            throw new ServiceException("金额为空");
        }
        UcardWalletRecordTable recordTable = new UcardWalletRecordTable();
        recordTable.setFee(BigDecimal.ZERO);
        recordTable.setStatus(2);
        recordTable.setAddTime(new Date());
        recordTable.setSerial(GetRandom.getOrderNo(PayConstant.UCARD_HEAD));
        recordTable.setWalletId(table.getId());
        recordTable.setCId(entity.getCId());
        recordTable.setUniqueId(table.getUniqueId());
        if (entity.getType() == 1) {
            table.setBalance(table.getBalance().add(entity.getAmount()));
            recordTable.setType(CardWalletRecordTypeEnum.MANUAL_IN.getCode());
            recordTable.setAmount(entity.getAmount());
        } else if (entity.getType() == 2) {
            if (table.getBalance().subtract(entity.getAmount()).compareTo(BigDecimal.ZERO) < 0) {
                throw new ServiceException("用户钱包余额不足");
            }
            table.setBalance(table.getBalance().subtract(entity.getAmount()));
            recordTable.setType(CardWalletRecordTypeEnum.MANUAL_OUT.getCode());
            recordTable.setAmount(entity.getAmount().negate());
        }
        ucardWalletRepository.save(table);
        ucardWalletRecordRepository.save(recordTable);
        return BaseResultDto.success();
    }

    /**
     * 卡冻结 v2
     *
     * @author gao
     * @date 2025/8/15 14:45
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public BaseResultDto cardFreeze(WasabiFreezeAndUnfreezeEntity entity) throws Exception {
        WasabiConfig config = wasabiDocumentApiService.getWasabiConfig();

        UcardCardTable cardTable = cardRepository.findByCardNo(entity.getCardNo());
        if (cardTable == null) {
            throw new ServiceException("卡片不存在");
        }
        if (cardTable.getBlocked() != null && cardTable.getBlocked()) {
            throw new ServiceException("该卡片已被锁定");
        }
        if (StringUtils.isNotEmpty(cardTable.getCancelStatus()) && !Constants.FAIL.equals(cardTable.getCancelStatus())) {
            throw new ServiceException("卡片注销状态不允许操作");
        }
        if (!Constants.SUCCESS.equals(cardTable.getStatus())) {
            throw new ServiceException("卡片未激活");
        }
        if ("1".equals(cardTable.getFreezeType()) && !Constants.SUCCESS.equals(cardTable.getFreezeStatus())) {
            throw new ServiceException("卡片当前状态不支持冻结");
        }
        if ("2".equals(cardTable.getFreezeType())) {
            if (Constants.SUCCESS.equals(cardTable.getFreezeStatus())) {
                throw new ServiceException("卡片已冻结");
            } else if (!Constants.FAIL.equals(cardTable.getFreezeStatus())) {
                throw new ServiceException("卡片冻结处理中");
            }
        }

        entity.setMerchantOrderNo(ObjectIdUtil.genSnowFlakeIdStr(config.getMerchantTag()));
        WasabiFreezeAndUnfreezeV2Dto dto = wasabiDocumentApiService.freezeV2(entity);

        CardOperateTable table = new CardOperateTable();
        table.setCardNo(entity.getCardNo());
        table.setMerchantOrderNo(entity.getMerchantOrderNo());
        table.setOperateUser(entity.getCId());
        table.setAddTime(new Date());
        table.setStatus(dto.getStatus());
        table.setOperateType(CardOperateTypeEnum.FREEZE.getCode());
        table.setOrderNo(dto.getOrderNo());
        table.setUniqueId(cardTable.getUniqueId());
        cardOperateRepository.save(table);

        if (Constants.FAIL.equals(dto.getStatus())) {
            cardTable.setFreezeType("1");
            cardTable.setFreezeStatus(Constants.SUCCESS);
        } else {
            cardTable.setFreezeType("2");
            cardTable.setFreezeStatus(dto.getStatus());
        }
        cardTable.setModifyTime(new Date());
        cardRepository.save(cardTable);

        return BaseResultDto.success();
    }

    /**
     * 卡解冻 v2
     *
     * @author gao
     * @date 2025/8/15 14:45
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public BaseResultDto cardUnfreeze(WasabiFreezeAndUnfreezeEntity entity) throws Exception {

        UcardCardTable cardTable = cardRepository.findByCardNo(entity.getCardNo());
        if (cardTable == null) {
            throw new ServiceException("卡片不存在");
        }
        if (cardTable.getBlocked() != null && cardTable.getBlocked()) {
            throw new ServiceException("该卡片已被锁定");
        }
        if (StringUtils.isNotEmpty(cardTable.getCancelStatus()) && !Constants.FAIL.equals(cardTable.getCancelStatus())) {
            throw new ServiceException("卡片注销状态不允许操作");
        }
        if (!Constants.SUCCESS.equals(cardTable.getStatus())) {
            throw new ServiceException("卡片未激活");
        }
        if ("2".equals(cardTable.getFreezeType()) && !Constants.SUCCESS.equals(cardTable.getFreezeStatus())) {
            throw new ServiceException("卡片当前状态不支持冻结");
        }
        if ("1".equals(cardTable.getFreezeType())) {
            if (Constants.SUCCESS.equals(cardTable.getFreezeStatus())) {
                throw new ServiceException("卡片已解冻");
            } else if (!Constants.FAIL.equals(cardTable.getFreezeStatus())) {
                throw new ServiceException("卡片解冻处理中");
            }
        }
        WasabiConfig config = wasabiDocumentApiService.getWasabiConfig();
        entity.setMerchantOrderNo(ObjectIdUtil.genSnowFlakeIdStr(config.getMerchantTag()));
        WasabiFreezeAndUnfreezeV2Dto dto = wasabiDocumentApiService.unfreezeV2(entity);

        CardOperateTable table = new CardOperateTable();
        table.setCardNo(entity.getCardNo());
        table.setMerchantOrderNo(entity.getMerchantOrderNo());
        table.setOperateUser(entity.getCId());
        table.setAddTime(new Date());
        table.setStatus(dto.getStatus());
        table.setOperateType(CardOperateTypeEnum.UNFREEZE.getCode());
        table.setOrderNo(dto.getOrderNo());
        table.setUniqueId(cardTable.getUniqueId());
        cardOperateRepository.save(table);

        if (Constants.FAIL.equals(dto.getStatus())) {
            cardTable.setFreezeType("2");
            cardTable.setFreezeStatus(Constants.SUCCESS);
        } else {
            cardTable.setFreezeType("1");
            cardTable.setFreezeStatus(dto.getStatus());
        }
        cardTable.setModifyTime(new Date());
        cardRepository.save(cardTable);

        return BaseResultDto.success();
    }

    /**
     * 卡充值
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public BaseResultDto cardDeposit(WasabiBalanceEntity entity) throws Exception {
        if (entity.getAmount() == null || entity.getAmount().compareTo(BigDecimal.ZERO) <= 0) {
            return BaseResultDto.error("充值金额参数异常");
        }
        UcardCardTable cardTable = cardRepository.findByCardNo(entity.getCardNo());
        if (cardTable == null) {
            throw new ServiceException("卡片不存在");
        }
        if (cardTable.getBlocked() != null && cardTable.getBlocked()) {
            throw new ServiceException("该卡片已被锁定");
        }
        if (StringUtils.isNotEmpty(cardTable.getCancelStatus()) && !Constants.FAIL.equals(cardTable.getCancelStatus())) {
            throw new ServiceException("卡片注销状态不允许操作");
        }
        if (!Constants.SUCCESS.equals(cardTable.getStatus())) {
            throw new ServiceException("卡片未激活");
        }
        if ("2".equals(cardTable.getFreezeType())) {
            throw new ServiceException("卡片冻结中，暂不支持此操作");
        }
        if ("1".equals(cardTable.getFreezeType()) && !Constants.SUCCESS.equals(cardTable.getFreezeStatus())) {
            throw new ServiceException("卡片解冻中，暂不支持此操作");
        }
        CardTypeDto cardTypeDto = cardTypeMapper.getByCardTypeId(cardTable.getCardTypeId());

        if (entity.getAmount().compareTo(cardTypeDto.getRechargeMinQuota()) < 0 || entity.getAmount().compareTo(cardTypeDto.getRechargeMaxQuota()) > 0) {
            throw new ServiceException("充值金额超过限度！");
        }
        WasabiConfig config = wasabiDocumentApiService.getWasabiConfig();
        entity.setMerchantOrderNo(ObjectIdUtil.genSnowFlakeIdStr(config.getMerchantTag()));
        CardMerchantUserTable userTable = merchantUserRepository.getByUniqueId(cardTable.getUniqueId());
        UcardWalletTable walletTable = ucardWalletRepository.findFirstByCId(userTable.getCId());
        // 查询充值手续费
        BigDecimal rechargeFee = getRechargeFee(entity.getAmount(), cardTable.getCardTypeId(), userTable);
        // 三方充值手续费
        BigDecimal fee = getFee(entity.getAmount(), cardTable.getCardTypeId());
        BigDecimal balance = null == walletTable.getBalance() ? new BigDecimal(0) : walletTable.getBalance();
        if (balance.compareTo(entity.getAmount().add(rechargeFee)) < 0) {
            return BaseResultDto.error("余额不足！");
        }

        CardRechargeOrderTable table = new CardRechargeOrderTable();
        BeanUtils.copyProperties(entity, table);
        table.setStatus("processing");
        table.setRechargeType(CardRechargeTypeEnum.RECHARGE.getCode());
        table.setRechargeFee(rechargeFee);
        table.setFee(fee);
        table.setCurrency("USD");
        table.setApproveStatus(CardApproveStatusEnum.PENDING.getCode());
        table.setCardNumber(cardTable.getCardNumber());
        table.setUniqueId(cardTable.getUniqueId());
        table.setAddTime(new Date());
        rechargeOrderRepository.save(table);

        walletTable.setBalance(balance.subtract(entity.getAmount().add(rechargeFee)));
        ucardWalletRepository.save(walletTable);
        UcardWalletRecordTable walletRecordTable = new UcardWalletRecordTable();
        walletRecordTable.setWalletId(walletTable.getId());
        walletRecordTable.setCId(walletTable.getCId());
        walletRecordTable.setUniqueId(walletTable.getUniqueId());
        walletRecordTable.setAmount(entity.getAmount().negate());
        walletRecordTable.setFee(rechargeFee.negate());
        walletRecordTable.setSerial(GetRandom.getOrderNo(PayConstant.UCARD_HEAD));
        walletRecordTable.setOrderNo(entity.getMerchantOrderNo());
        walletRecordTable.setStatus(1);
        walletRecordTable.setType(CardWalletRecordTypeEnum.RECHARGE.getCode());
        walletRecordTable.setAddTime(new Date());
        ucardWalletRecordRepository.save(walletRecordTable);

        CardOperateTable cardOperateTable = new CardOperateTable();
        cardOperateTable.setOperateUser(entity.getCId());
        cardOperateTable.setCardNo(cardTable.getCardNo());
        cardOperateTable.setOperateType(CardOperateTypeEnum.CARD_RECHARGE_APPLICATION.getCode());
        cardOperateTable.setStatus(Constants.SUCCESS);
        cardOperateTable.setAddTime(new Date());
        cardOperateTable.setUniqueId(cardTable.getUniqueId());
        cardOperateRepository.save(cardOperateTable);

        // 充值申请给财务发邮件审批
        ucardEmailService.sendRechargeReviewEmail(userTable, cardTable.getCardNumber(), entity.getAmount(), fee, table.getAddTime());
        return BaseResultDto.success();
    }

    /**
     * 充值审批
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public BaseResultDto cardDepositApprove(WasabiDepositApproveEntity entity) throws Exception {
        List<Long> ids = entity.getIds();
        if (CollectionUtils.isEmpty(ids)) {
            throw new ServiceException("审核id为空");
        }
        for (Long id : ids) {
            CardRechargeOrderTable table = rechargeOrderRepository.getFirstById(id);
            if (table == null) {
                throw new ServiceException("充值订单不存在");
            }
            if (entity.getApproveStatus() == null) {
                throw new ServiceException("请选择审批结果");
            }
            if (table.getApproveStatus() == 2) {
                continue;
            }
            UcardCardTable cardTable = cardRepository.getByCardNo(table.getCardNo());
            if (cardTable.getBlocked() != null && cardTable.getBlocked()) {
                throw new ServiceException("该卡片已被锁定");
            }
            if (StringUtils.isNotEmpty(cardTable.getCancelStatus()) && !Constants.FAIL.equals(cardTable.getCancelStatus())) {
                throw new ServiceException("卡片注销状态不允许操作");
            }
            CardMerchantUserTable userTable = merchantUserRepository.getByUniqueId(table.getUniqueId());
            UcardWalletTable walletTable = ucardWalletRepository.findFirstByCId(userTable.getCId());
            UcardWalletRecordTable recordTable =
                    ucardWalletRecordRepository.findFirstByOrderNo(table.getMerchantOrderNo());

            if (entity.getApproveStatus() == 2) {
                WasabiConfig config = wasabiDocumentApiService.getWasabiConfig();
                WasabiBalanceEntity depositEntity = new WasabiBalanceEntity();
                depositEntity.setCardNo(table.getCardNo());
                depositEntity.setMerchantOrderNo(table.getMerchantOrderNo());
                depositEntity.setAmount(table.getAmount());

                ResultData<WasabiDepositDto> resultData = wasabiDocumentApiService.cardDeposit(depositEntity, config);
                if (!resultData.isSuccess()) {
                    return BaseResultDto.error(resultData.getMsg());
                }

                WasabiDepositDto dto = resultData.getData();

                BeanUtils.copyProperties(dto, table);
                table.setTransactionTime(DateUtil.formatTimestamp(dto.getTransactionTime()));
                table.setAddTime(new Date());
                table.setApproveStatus(CardApproveStatusEnum.APPROVED.getCode());
                table.setApproveDesc(entity.getApproveDesc());
                table.setCurrency("USD");
                table.setReceivedCurrency("USD");
                rechargeOrderRepository.save(table);
                int status;
                if (Constants.SUCCESS.equals(dto.getStatus())) {
                    status = 2;
                    // 充值成功给客户发邮件
                    ucardEmailService.sendCardRechargeSuccessEmail(userTable, table);
                } else if (Constants.FAIL.equals(dto.getStatus())) {
                    status = 3;
                    BigDecimal balance = walletTable.getBalance().add(table.getAmount()).add(table.getFee());
                    walletTable.setBalance(balance);
                    ucardWalletRepository.save(walletTable);

                    UcardWalletRecordTable walletRecordTable = new UcardWalletRecordTable();
                    walletRecordTable.setWalletId(walletTable.getId());
                    walletRecordTable.setCId(walletTable.getCId());
                    walletRecordTable.setUniqueId(walletTable.getUniqueId());
                    walletRecordTable.setAmount(table.getAmount());
                    walletRecordTable.setFee(table.getFee());
                    walletRecordTable.setSerial(GetRandom.getOrderNo(PayConstant.UCARD_HEAD));
                    walletRecordTable.setStatus(2);
                    walletRecordTable.setType(CardWalletRecordTypeEnum.REFUND.getCode());
                    walletRecordTable.setAddTime(new Date());

                    ucardWalletRecordRepository.save(walletRecordTable);

                    // 充值审核失败给客户发邮件
                    ucardEmailService.sendCardRechargeReviewFailEmail(userTable, table, Long.valueOf(entity.getApproveDesc()));
                } else {
                    status = 1;
                }

                recordTable.setStatus(status);
                recordTable.setType(CardWalletRecordTypeEnum.RECHARGE.getCode());
                ucardWalletRecordRepository.save(recordTable);
            } else if (entity.getApproveStatus() == 3) {
                // 审核拒绝-退款
                BigDecimal balance = walletTable.getBalance().add(table.getAmount()).add(table.getRechargeFee());
                walletTable.setBalance(balance);
                ucardWalletRepository.save(walletTable);

                // 更新充值订单状态
                recordTable.setStatus(3);
                ucardWalletRecordRepository.save(recordTable);
                // 新增退款订单信息记录
                UcardWalletRecordTable walletRecordTable = new UcardWalletRecordTable();
                walletRecordTable.setWalletId(walletTable.getId());
                walletRecordTable.setCId(walletTable.getCId());
                walletRecordTable.setUniqueId(walletTable.getUniqueId());
                walletRecordTable.setAmount(table.getAmount());
                walletRecordTable.setFee(table.getRechargeFee());
                walletRecordTable.setSerial(GetRandom.getOrderNo(PayConstant.UCARD_HEAD));
                walletRecordTable.setStatus(2);
                walletRecordTable.setType(CardWalletRecordTypeEnum.REFUND.getCode());
                walletRecordTable.setAddTime(new Date());
                ucardWalletRecordRepository.save(walletRecordTable);

                table.setStatus(Constants.FAIL);
                table.setApproveStatus(CardApproveStatusEnum.REJECTED.getCode());
                table.setApproveDesc(entity.getApproveDesc());
                rechargeOrderRepository.save(table);
            }
            CardOperateTable cardOperateTable = new CardOperateTable();
            cardOperateTable.setOperateUser(entity.getCId());
            cardOperateTable.setCardNo(table.getCardNo());
            cardOperateTable.setOperateType(CardOperateTypeEnum.RECHARGE_APPROVAL.getCode());
            cardOperateTable.setStatus(Constants.SUCCESS);
            cardOperateTable.setAddTime(new Date());
            cardOperateTable.setUniqueId(userTable.getUniqueId());
            cardOperateRepository.save(cardOperateTable);
        }
        return BaseResultDto.success();
    }

    /**
     * 卡扣款
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public BaseResultDto cardWithdraw(WasabiWithdrawEntity entity) throws Exception {
        if (entity.getAmount().compareTo(new BigDecimal("0.01")) < 0) {
            throw new ServiceException("金额不能小于0.01");
        }

        UcardCardTable ucardCardTable = cardRepository.getFirstById(entity.getId());
        if (ucardCardTable.getBlocked() != null && ucardCardTable.getBlocked()) {
            throw new ServiceException("该卡片已被锁定");
        }
        if (StringUtils.isNotEmpty(ucardCardTable.getCancelStatus()) && !Constants.FAIL.equals(ucardCardTable.getCancelStatus())) {
            throw new ServiceException("卡片注销状态不允许操作");
        }
        if (!Constants.SUCCESS.equals(ucardCardTable.getStatus())) {
            throw new ServiceException("卡片未激活");
        }
        if ("2".equals(ucardCardTable.getFreezeType())) {
            throw new ServiceException("卡片冻结中，暂不支持此操作");
        }
        if ("1".equals(ucardCardTable.getFreezeType()) && !Constants.SUCCESS.equals(ucardCardTable.getFreezeStatus())) {
            throw new ServiceException("卡片解冻中，暂不支持此操作");
        }
        // 查询卡信息
        WasabiCardInfoEntity infoEntity = new WasabiCardInfoEntity();
        infoEntity.setCardNo(ucardCardTable.getCardNo());

        WasabiCardInfoDto cardInfo = wasabiDocumentApiService.getCardInfo(infoEntity);
        if (cardInfo == null || !"Normal".equals(cardInfo.getStatus())) {
            throw new ServiceException("卡片非正常状态，不允许调用此接口");
        }
        // 查询卡余额
        WasabiBalanceInfoEntity balanceInfoEntity = new WasabiBalanceInfoEntity();
        balanceInfoEntity.setCardNo(ucardCardTable.getCardNo());
        WasabiBalanceInfoDto balanceInfoDto = getBalanceInfo(balanceInfoEntity).getData();
        // 判断余额是否充足
        if (balanceInfoDto.getAmount().compareTo(entity.getAmount()) < 0) {
            return BaseResultDto.error("卡余额不足");
        }

        WasabiConfig config = wasabiDocumentApiService.getWasabiConfig();
        WasabiBalanceEntity depositEntity = new WasabiBalanceEntity();
        depositEntity.setCardNo(ucardCardTable.getCardNo());
        depositEntity.setMerchantOrderNo(ObjectIdUtil.genSnowFlakeIdStr(config.getMerchantTag()));
        depositEntity.setAmount(entity.getAmount());

        ResultData<WasabiDepositDto> resultData = wasabiDocumentApiService.withdraw(depositEntity, config);
        if (!resultData.isSuccess()) {
            return BaseResultDto.error(resultData.getMsg());
        }

        WasabiDepositDto dto = resultData.getData();
        CardWithdrawTable table = new CardWithdrawTable();
        BeanUtils.copyProperties(dto, table);
        table.setAmount(entity.getAmount().negate());
        table.setType(CardWithdrawTypeEnum.CARD_WITHDRAW.getCode());
        table.setUniqueId(ucardCardTable.getUniqueId());
        table.setCardNumber(ucardCardTable.getCardNumber());
        table.setAddTime(new Date());
        withdrawRepository.save(table);
        // 保存操作记录
        CardOperateTable cardOperateTable = new CardOperateTable();
        cardOperateTable.setUniqueId(ucardCardTable.getUniqueId());
        cardOperateTable.setMerchantOrderNo(dto.getMerchantOrderNo());
        cardOperateTable.setOrderNo(dto.getOrderNo());
        cardOperateTable.setCardNo(ucardCardTable.getCardNo());
        cardOperateTable.setOperateType(CardOperateTypeEnum.DEDUCT_MONEY.getCode());
        cardOperateTable.setOperateUser(entity.getCId());
        cardOperateTable.setStatus(dto.getStatus());
        cardOperateTable.setAddTime(new Date());
        cardOperateRepository.save(cardOperateTable);

        return BaseResultDto.success(table);
    }

    /**
     * 销卡
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public BaseResultDto cardCancel(WasabiCancelEntity entity) throws Exception {

        UcardCardTable table = cardRepository.findByCardNo(entity.getCardNo());
        if (table == null) {
            return BaseResultDto.error(Constants.INFO_NOT_FOUND);
        }
        if (StringUtils.isNotEmpty(table.getCancelStatus()) && !Constants.FAIL.equals(table.getCancelStatus())) {
            throw new ServiceException("卡片注销状态不允许操作");
        }

        WasabiDepositDto dto = wasabiDocumentApiService.cardCancel(entity);

        table.setCancelStatus(dto.getStatus());
        cardRepository.save(table);
        CardApplyTable applyTable = cardApplyRepository.getByCardNo(table.getCardNo());
        if (dto.getStatus().equals(Constants.SUCCESS)) {
            applyTable.setStatus("cancel");
            cardApplyRepository.save(applyTable);
        }

        // 保存操作记录
        CardOperateTable cardOperateTable = new CardOperateTable();
        cardOperateTable.setUniqueId(table.getUniqueId());
        cardOperateTable.setMerchantOrderNo(dto.getMerchantOrderNo());
        cardOperateTable.setOrderNo(dto.getOrderNo());
        cardOperateTable.setCardNo(table.getCardNo());
        cardOperateTable.setOperateType(CardOperateTypeEnum.CARD_CANCEL.getCode());
        cardOperateTable.setOperateUser(entity.getCId());
        cardOperateTable.setStatus(dto.getStatus());
        cardOperateTable.setAddTime(new Date());
        cardOperateRepository.save(cardOperateTable);

        return BaseResultDto.success();
    }

    /**
     * 充值手续费
     */
    public BigDecimal getRechargeFee(BigDecimal amount, Integer cardTypeId, CardMerchantUserTable userTable) {
        BigDecimal cardRechargeFeeRate = null;
        if (userTable.getCardRechargeFeeRate() != null) {
            cardRechargeFeeRate = userTable.getCardRechargeFeeRate();
        } else {
            CardTypeDto cardTypeDto = cardTypeMapper.getByCardTypeId(cardTypeId);
            if (cardTypeDto.getRechargeFeeRate() != null && cardTypeDto.getRechargeFeeRate().compareTo(BigDecimal.ZERO) >= 0) {
                cardRechargeFeeRate = cardTypeDto.getRechargeFeeRate();
            }
        }
        if (cardRechargeFeeRate == null) {
            cardRechargeFeeRate = BigDecimal.ZERO;
        }
        BigDecimal scale = amount.setScale(0, RoundingMode.UP);
        BigDecimal rechargeFee = scale.multiply(cardRechargeFeeRate).divide(new BigDecimal("100"), 2,
                RoundingMode.HALF_UP);

        return rechargeFee;
    }

    /**
     * 三方充值手续费
     */
    public BigDecimal getFee(BigDecimal amount, Integer cardTypeId) {
        BigDecimal cardRechargeFeeRate = BigDecimal.ZERO;
        BigDecimal rechargeFixedFee = BigDecimal.ZERO;
        CardTypeTable table = cardTypeRepository.findByCardTypeId(cardTypeId);
        if (table.getRechargeFeeRate() != null && table.getRechargeFeeRate().compareTo(BigDecimal.ZERO) >= 0) {
            cardRechargeFeeRate = table.getRechargeFeeRate();
        }
        if (table.getRechargeFixedFee() != null && table.getRechargeFixedFee().compareTo(BigDecimal.ZERO) >= 0) {
            rechargeFixedFee = table.getRechargeFixedFee();
        }
        BigDecimal scale = amount.setScale(0, RoundingMode.UP);
        BigDecimal rechargeFee = scale.multiply(cardRechargeFeeRate).divide(new BigDecimal("100"), 2,
                RoundingMode.HALF_UP);

        return rechargeFee.add(rechargeFixedFee);
    }

    /**
     * 用户钱包余额
     */
    @Override
    public BaseResultDto<WalletBalanceDto> walletBalance(WalletBalanceEntity entity) throws ServiceException {
        UcardWalletTable table = ucardWalletRepository.getFirstByCId(entity.getCId());
        if (table == null) {
            table = new UcardWalletTable();
            CardMerchantUserTable userTable = merchantUserRepository.getFirstByCustomId(entity.getCustomId());
            table.setCustomId(entity.getCustomId());
            table.setCId(userTable.getCId());
            table.setUniqueId(userTable.getUniqueId());
            table.setBalance(BigDecimal.ZERO);
            table.setAddTime(new Date());
        }
        WalletBalanceDto dto = new WalletBalanceDto();
        dto.setCId(entity.getCId());
        dto.setCustomId(entity.getCustomId());
        dto.setBalance(table.getBalance());
        return BaseResultDto.success(dto);
    }

    /**
     * 用户钱包记录
     */
    @Override
    public ResultWithPagerDto<CardWalletRecordDto> getCardWalletRecordPageList(CardWalletRecordPageEntity entity) throws ServiceException {
        try {
            /**
             * 格式化时间
             */
            if (entity.getEndDate() != null) {
                entity.setEndDate(DateUtil.operationDay(entity.getEndDate(), 1));
            }
            // 获取总数
            Integer count = walletRecordMapper.countList(entity);
            PageDto pageDto = PageDto.format(entity, count);
            if (count == null || count <= 0) {
                return ResultWithPagerDto.success(pageDto);
            }

            List<CardWalletRecordDto> cardlist = walletRecordMapper.pageList(entity);

            return ResultWithPagerDto.success(pageDto, cardlist);
        } catch (Exception e) {
            log.error("获取钱包记录分页列表失败", e);
            throw new ServiceException("获取钱包记录分页列表失败");
        }
    }

    /**
     * 查询充值订单
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public BaseResultDto queryDepositOrder(CardRechargeOrderQueryEntity entity) throws Exception {

        try {
            CardRechargeOrderTable table = rechargeOrderRepository.findByMerchantOrderNo(entity.getMerchantOrderNo());
            if (table == null) {
                throw new ServiceException("订单不存在");
            }
            if (StringUtils.isNotEmpty(table.getStatus()) && Constants.SUCCESS.equals(table.getStatus())) {
                return BaseResultDto.success(table);
            }

            // 获取卡交易记录
            WasabiTransactionEntity transactionEntity = new WasabiTransactionEntity();
            transactionEntity.setType("deposit");
            transactionEntity.setMerchantOrderNo(entity.getMerchantOrderNo());
            List<WasabiTransactionDto> dtos = wasabiDocumentApiService.getCardTransactionList(transactionEntity);
            if (CollectionUtils.isEmpty(dtos)) {
                return BaseResultDto.success(table);
            }
            WasabiTransactionDto dto = dtos.get(0);
            if (dto == null || dto.getStatus() == null) {
                return BaseResultDto.success(table);
            }
            if (!table.getStatus().equals(dto.getStatus())) {
                BeanUtils.copyProperties(dto, table);
                table.setTransactionTime(DateUtil.formatTimestamp(dto.getTransactionTime()));
                table.setModifyTime(new Date());
                table.setCurrency("USD");
                table.setReceivedCurrency("USD");
                rechargeOrderRepository.save(table);
                UcardWalletRecordTable recordTable =
                        ucardWalletRecordRepository.findFirstByOrderNo(entity.getMerchantOrderNo());
                CardMerchantUserTable userTable = merchantUserRepository.getByUniqueId(table.getUniqueId());
                if (recordTable != null && "3".equals(table.getRechargeType())) {
                    if (Constants.SUCCESS.equals(dto.getStatus())) {
                        recordTable.setStatus(2);
                        // 充值成功给客户发邮件
                        ucardEmailService.sendCardRechargeSuccessEmail(userTable, table);
                    } else if (Constants.FAIL.equals(dto.getStatus())) {
                        UcardWalletTable walletTable = ucardWalletRepository.findFirstByCId(userTable.getCId());
                        recordTable.setStatus(3);
                        BigDecimal balance = null == walletTable.getBalance() ? new BigDecimal(0) :
                                walletTable.getBalance();
                        walletTable.setBalance(balance.add(table.getAmount()).add(table.getRechargeFee()));
                        ucardWalletRepository.save(walletTable);
                        // 新增退款订单信息记录
                        UcardWalletRecordTable walletRecordTable = new UcardWalletRecordTable();
                        walletRecordTable.setWalletId(walletTable.getId());
                        walletRecordTable.setCId(walletTable.getCId());
                        walletRecordTable.setUniqueId(walletTable.getUniqueId());
                        walletRecordTable.setAmount(table.getAmount());
                        walletRecordTable.setFee(table.getRechargeFee());
                        walletRecordTable.setSerial(GetRandom.getOrderNo(PayConstant.UCARD_HEAD));
                        walletRecordTable.setStatus(2);
                        walletRecordTable.setType(CardWalletRecordTypeEnum.REFUND.getCode());
                        walletRecordTable.setAddTime(new Date());
                        ucardWalletRecordRepository.save(walletRecordTable);
                    }
                    recordTable.setModifyTime(new Date());
                    ucardWalletRecordRepository.save(recordTable);
                }
            }
            return BaseResultDto.success(table);
        } catch (ServiceException e) {
            log.error("查询充值订单失败，错误信息：{}", e.getMessage());
            throw e;
        } catch (Exception e) {
            log.error("查询充值订单异常", e);
            throw new ServiceException("查询充值订单失败，请稍后重试");
        }
    }

    /**
     * 更新实体卡PIN
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public BaseResultDto updatePin(WasabiUpdatePinEntity entity) throws Exception {
        UcardCardTable cardTable = cardRepository.findByCardNo(entity.getCardNo());
        if (cardTable == null) {
            throw new ServiceException("卡片不存在");
        }
        if (cardTable.getBlocked() != null && cardTable.getBlocked()) {
            throw new ServiceException("该卡片已被锁定");
        }
        if (StringUtils.isNotEmpty(cardTable.getCancelStatus()) && !Constants.FAIL.equals(cardTable.getCancelStatus())) {
            throw new ServiceException("卡片注销状态不允许操作");
        }
        if (!Constants.SUCCESS.equals(cardTable.getStatus())) {
            throw new ServiceException("卡片未激活");
        }
        if (!"1".equals(cardTable.getFreezeType()) && !Constants.SUCCESS.equals(cardTable.getFreezeStatus())) {
            throw new ServiceException("当前卡状态不支持修改密码");
        }
        try {
            WasabiUpdatePinDto dto = wasabiDocumentApiService.updatePin(entity);

            CardOperateTable table = new CardOperateTable();
            table.setCardNo(entity.getCardNo());
            table.setMerchantOrderNo(entity.getMerchantOrderNo());
            table.setOperateUser(entity.getCId());
            table.setAddTime(new Date());
            table.setStatus(dto.getStatus());
            table.setOperateType(CardOperateTypeEnum.UPDATE_PASSWORD.getCode());
            table.setOrderNo(dto.getOrderNo());
            table.setUniqueId(cardTable.getUniqueId());
            cardOperateRepository.save(table);

            CardPasswordResetTable passwordResetTable = new CardPasswordResetTable();
            passwordResetTable.setCardNo(entity.getCardNo());
            passwordResetTable.setAddTime(new Date());
            passwordResetTable.setUniqueId(cardTable.getUniqueId());
            passwordResetTable.setPassword(entity.getPin());
            passwordResetTable.setMerchantOrderNo(entity.getMerchantOrderNo());
            passwordResetTable.setStatus(dto.getStatus());
            passwordResetRepository.save(passwordResetTable);

            if (Constants.SUCCESS.equals(dto.getStatus())) {
                cardTable.setPin(entity.getPin());
                cardTable.setModifyTime(new Date());
                cardRepository.save(cardTable);
                // 修改密码成功给客户发邮件
                CardMerchantUserTable userTable = merchantUserRepository.getByUniqueId(cardTable.getUniqueId());
                ucardEmailService.sendCardUpdatePasswordSuccessEmail(userTable, cardTable.getCardNumber());
            }
            return BaseResultDto.success(dto.getStatus());
        } catch (Exception e) {
            log.error("更新实体卡PIN失败", e);
            throw new ServiceException("更新实体卡PIN失败");
        }
    }

    /**
     * 获取职业信息列表
     */
    @Override
    public BaseResultDto<List<WasabiOccupationsDto>> getOccupationList() throws ServiceException {
        try {
            List<UcardOccupationsTable> tables = occupationsRepository.findAll();

            List<WasabiOccupationsDto> dtos = tables.stream()
                    .map(wasabiDto -> {
                        WasabiOccupationsDto dto = new WasabiOccupationsDto();
                        BeanUtils.copyProperties(wasabiDto, dto);
                        return dto;
                    })
                    .collect(Collectors.toList());
            return BaseResultDto.success(dtos);
        } catch (Exception e) {
            log.error("获取职业信息列表失败", e);
            throw new ServiceException("获取职业信息列表失败");
        }
    }

    /**
     * 更新职业信息列表
     */
    @Override
    public void updateOccupationList() throws Exception {
        cardOccupationsMapper.deleteAll();
        try {
            Date now = new Date();
            List<WasabiOccupationsDto> dtos = wasabiDocumentApiService.getHolderOccupations();
            // 按occupation_code去重
            Map<String, WasabiOccupationsDto> uniqueMap = dtos.stream()
                    .collect(Collectors.toMap(
                            WasabiOccupationsDto::getOccupationCode,
                            dto -> dto,
                            (existing, replacement) -> existing // 保留第一个遇到的重复项
                    ));
            List<UcardOccupationsTable> tables = uniqueMap.values().stream()
                    .map(wasabiDto -> {
                        UcardOccupationsTable dto = new UcardOccupationsTable();
                        BeanUtils.copyProperties(wasabiDto, dto);
                        dto.setAddTime(now);
                        return dto;
                    })
                    .collect(Collectors.toList());
            List<List<UcardOccupationsTable>> lists = ListSplitUtil.split(tables);
            for (List<UcardOccupationsTable> list : lists) {
                cardOccupationsMapper.batchSave(list);
            }
        } catch (Exception e) {
            log.error("更新职业信息列表失败", e);
            throw new ServiceException("更新职业信息列表失败");
        }
    }

    /**
     * 激活中数据查询卡信息并更新数据库
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void activateCallback(UcardCardTable cardTable) throws Exception {
        UcardCardTable table = cardRepository.findByCardNo(cardTable.getCardNo());
        if (Constants.SUCCESS.equals(table.getStatus())) {
            return;
        }
        String co = UUIDUtil.getUUID();
        String key = table.getId().toString() + table.getCardNo();
        if (!redisService.tryLock(key, co, 5 * 60 * 1000)) {
            log.error("激活中数据查询卡信息并更新数据库-获取锁失败, key: {}", key);
            return;
        }
        try {
            WasabiCardInfoEntity infoEntity = new WasabiCardInfoEntity();
            infoEntity.setCardNo(table.getCardNo());

            WasabiCardInfoDto cardInfo = wasabiDocumentApiService.getCardInfo(infoEntity);
            if (cardInfo == null) {
                return;
            }
            if ("Normal".equals(cardInfo.getStatus())) {
                WasabiBalanceInfoEntity balanceInfoEntity = new WasabiBalanceInfoEntity();
                balanceInfoEntity.setCardNo(cardInfo.getCardNo());
                WasabiCardSensitiveDto cardSensitiveDto = wasabiDocumentApiService.getCardSensitive(balanceInfoEntity);
                String cvv = cardSensitiveDto.getCvv();
                String expireDate = cardSensitiveDto.getExpireDate();
                String cardNumber = cardSensitiveDto.getCardNumber();
                String activateUrl = cardSensitiveDto.getActivateUrl();
                table.setCardNumber(cardNumber);
                table.setActivateUrl(activateUrl);
                table.setCvv(cvv);
                table.setExpireDate(expireDate);
                table.setBlocked(cardInfo.getBlocked());
                table.setRemark(cardInfo.getRemark());
                table.setModifyTime(new Date());
                cardRepository.save(table);
                if (StringUtils.isEmpty(cvv)) {
                    mqSendService.send(Constants.WASABICARD_CARD_INFO_REFRESH, JSONObject.toJSONString(table), 60 * 1000);
                    return;
                }
                // 查询是否存在充值默认金额订单
                CardRechargeOrderTable rechargeOrderTable =
                        rechargeOrderRepository.getFirstByCardNoAndRechargeType(table.getCardNo(), "1");
                if (rechargeOrderTable != null) {
                    log.info("存在充值默认金额订单,{}", rechargeOrderTable);
                    return;
                }
                SysUcardConfigTable sysUcardConfigTable = sysUcardConfigService.getByCode(Constants.WASABI_CARD_RECHARGE_AMOUNT);
                if (sysUcardConfigTable == null) {
                    throw ServiceException.exception(Constants.SYSTEM_ERROR);
                }
                // 充值默认金额
                WasabiConfig config = wasabiDocumentApiService.getWasabiConfig();
                WasabiBalanceEntity depositEntity = new WasabiBalanceEntity();
                depositEntity.setCardNo(table.getCardNo());
                depositEntity.setMerchantOrderNo(ObjectIdUtil.genSnowFlakeIdStr(config.getMerchantTag()));
                depositEntity.setAmount(new BigDecimal(sysUcardConfigTable.getValue()));
                if (depositEntity.getAmount().compareTo(BigDecimal.ZERO) <= 0) {

                    table.setStatus(Constants.SUCCESS);
                    table.setModifyTime(new Date());
                    cardRepository.save(table);
                    ucardEmailService.sendActivateCardSuccessEmail(table);
                    return;
                }
                ResultData<WasabiDepositDto> resultData = wasabiDocumentApiService.cardDeposit(depositEntity, config);
                if (!resultData.isSuccess()) {
                    log.error("WASABICARD_CARD_ACTIVATE_QUERY ：充值默认金额异常！{}", table);
                    return;
                }
                WasabiDepositDto depositDto = resultData.getData();

                CardRechargeOrderTable orderTable = new CardRechargeOrderTable();
                BeanUtils.copyProperties(depositDto, orderTable);
                orderTable.setRechargeFee(BigDecimal.ZERO);
                orderTable.setApproveStatus(2);
                orderTable.setUniqueId(table.getUniqueId());
                orderTable.setTransactionTime(DateUtil.formatTimestamp(depositDto.getTransactionTime()));
                orderTable.setCurrency("USD");
                orderTable.setReceivedCurrency("USD");
                orderTable.setAddTime(new Date());
                orderTable.setRechargeType(CardRechargeTypeEnum.RECHARGE_DEFAULT_AMOUNT.getCode());
                orderTable.setCardNumber(table.getCardNumber());
                rechargeOrderRepository.save(orderTable);

                CardOperateTable cardOperateTable = new CardOperateTable();
                cardOperateTable.setCardNo(table.getCardNo());
                cardOperateTable.setOperateUser(null);
                cardOperateTable.setOperateType(CardOperateTypeEnum.RECHARGE_DEFAULT_AMOUNT.getCode());
                cardOperateTable.setStatus(Constants.SUCCESS);
                cardOperateTable.setAddTime(new Date());
                cardOperateTable.setUniqueId(table.getUniqueId());
                cardOperateRepository.save(cardOperateTable);

                if (Constants.SUCCESS.equals(orderTable.getStatus())) {
                    table.setStatus(Constants.SUCCESS);
                    table.setModifyTime(new Date());
                    cardRepository.save(table);
                    // 激活成功发送邮件通知
                    ucardEmailService.sendActivateCardSuccessEmail(table);
                }
            }
        } finally {
            redisService.unlock(key, co);
        }
    }

    /**
     * 卡信息刷新
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public BaseResultDto refreshCardInfo(CardInfoRefreshEntity entity) throws Exception {
        UcardCardTable table = cardRepository.findFirstById(entity.getId());
        if (table == null) {
            return BaseResultDto.error("The card information does not exist");
        }
        if ("wait_process".equals(table.getStatus()) || "processing".equals(table.getStatus())) {
            mqSendService.send(Constants.WASABICARD_CARD_INFO_REFRESH, JSONObject.toJSONString(table));
            return BaseResultDto.success();
        }
        WasabiCardInfoEntity infoEntity = new WasabiCardInfoEntity();
        infoEntity.setCardNo(table.getCardNo());
        WasabiCardInfoDto cardInfo = wasabiDocumentApiService.getCardInfo(infoEntity);
        if (cardInfo == null) {
            return BaseResultDto.success();
        }
        String status = cardInfo.getStatus();
        if ("Normal".equals(status)) {
            if (StringUtils.isEmpty(table.getCvv())) {
                mqSendService.send(Constants.WASABICARD_CARD_INFO_REFRESH, JSONObject.toJSONString(table));
            }
        } else if ("Freeze".equals(status)) {
            if (!"2".equals(table.getFreezeType()) || !"success".equals(table.getFreezeStatus())) {
                table.setFreezeType("2");
                table.setFreezeStatus("success");
                cardRepository.save(table);
            }
        } else if ("Freezing".equals(status)) {
            if (!"2".equals(table.getFreezeType()) || !"processing".equals(table.getFreezeStatus())) {
                table.setFreezeType("2");
                table.setFreezeStatus("processing");
                cardRepository.save(table);
            }
        } else if ("UnFreezing".equals(status)) {
            if (!"1".equals(table.getFreezeType()) || !"processing".equals(table.getFreezeStatus())) {
                table.setFreezeType("1");
                table.setFreezeStatus("processing");
                cardRepository.save(table);
            }
        } else if ("cancel".equals(status)) {
            if (!Constants.SUCCESS.equals(table.getCancelStatus())) {
                table.setCancelStatus(Constants.SUCCESS);
                cardRepository.save(table);
            }
        } else if ("blocked".equals(status)) {
            if (!table.getBlocked()) {
                table.setBlocked(true);
                cardRepository.save(table);
            }
        }
        return BaseResultDto.success();
    }

    /**
     * 查询激活码
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public BaseResultDto<WasabiThird3dsTransactionDto> getActivationCode(WasabiThird3dsTransactionEntity entity) throws Exception {
        try {
            WasabiThird3dsTransactionDto dto = wasabiDocumentApiService.getActivationCode(entity);
            UcardCardTable cardTable = cardRepository.getByCardNo(entity.getCardNo());
            CardOperateTable operateTable = new CardOperateTable();
            operateTable.setCardNo(cardTable.getCardNo());
            operateTable.setOperateUser(entity.getCId());
            operateTable.setOperateType(CardOperateTypeEnum.GET_ACTIVATION_CODE.getCode());
            operateTable.setStatus(Constants.SUCCESS);
            operateTable.setAddTime(new Date());
            operateTable.setUniqueId(cardTable.getUniqueId());
            cardOperateRepository.save(operateTable);
            return BaseResultDto.success(dto);
        } catch (Exception e) {
            log.error("查询激活码失败", e);
            throw new ServiceException("查询激活码失败");
        }
    }


    /**
     * 操作记录分页列表
     */
    @Override
    public ResultWithPagerDto<CardOperateDto> queryOperatePageList(CardOperatePageEntity entity) throws ServiceException {
        try {
            /**
             * 格式化时间
             */
            if (entity.getEndDate() != null) {
                entity.setEndDate(DateUtil.operationDay(entity.getEndDate(), 1));
            }
            // 获取总数
            Integer count = operateMapper.countList(entity);
            PageDto pageDto = PageDto.format(entity, count);
            if (count == null || count <= 0) {
                return ResultWithPagerDto.success(pageDto);
            }
            List<CardOperateDto> dtos = operateMapper.pageList(entity);

            return ResultWithPagerDto.success(pageDto, dtos);
        } catch (Exception e) {
            log.error("操作记录分页查询失败", e);
            throw new ServiceException("操作记录分页查询失败");
        }
    }


    /**
     * 重新充值默认开卡金额
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public BaseResultDto rechargeDefaultAmount(CardRechargeDefaultAmountEntity entity) throws Exception {
        UcardCardTable table = cardRepository.findFirstById(entity.getId());
        if (table == null) {
            throw ServiceException.exception(Constants.INFO_NOT_FOUND);
        }
        if (Constants.SUCCESS.equals(table.getStatus())) {
            throw ServiceException.exception("卡片已激活成功！");
        }
        SysUcardConfigTable sysUcardConfigTable = sysUcardConfigService.getByCode(Constants.WASABI_CARD_RECHARGE_AMOUNT);
        if (sysUcardConfigTable == null) {
            throw ServiceException.exception(Constants.SYSTEM_ERROR);
        }
        // 查询是否存在充值处理中和充值成功的数据
        CardRechargeOrderTable rechargeOrderTable =
                rechargeOrderRepository.getFirstByCardNoAndStatusAndRechargeType(table.getCardNo(), "processing", "1");
        if (rechargeOrderTable != null) {
            return BaseResultDto.error("卡片充值处理中！");
        }
        CardRechargeOrderTable cardRechargeOrderTable =
                rechargeOrderRepository.getFirstByCardNoAndStatusAndRechargeType(table.getCardNo(), "success", "1");
        if (cardRechargeOrderTable != null) {
            table.setStatus(Constants.SUCCESS);
            table.setModifyTime(new Date());
            cardRepository.save(table);
            // 激活成功发送邮件通知
            ucardEmailService.sendActivateCardSuccessEmail(table);
            return BaseResultDto.success("卡片已充值默认金额成功！");
        }

        // 充值默认金额
        WasabiConfig config = wasabiDocumentApiService.getWasabiConfig();
        WasabiBalanceEntity depositEntity = new WasabiBalanceEntity();
        depositEntity.setCardNo(table.getCardNo());
        depositEntity.setMerchantOrderNo(ObjectIdUtil.genSnowFlakeIdStr(config.getMerchantTag()));
        depositEntity.setAmount(new BigDecimal(sysUcardConfigTable.getValue()));

        if (depositEntity.getAmount().compareTo(BigDecimal.ZERO) <= 0) {

            table.setStatus(Constants.SUCCESS);
            table.setModifyTime(new Date());
            cardRepository.save(table);
            ucardEmailService.sendActivateCardSuccessEmail(table);
            return BaseResultDto.success();
        }

        ResultData<WasabiDepositDto> resultData = wasabiDocumentApiService.cardDeposit(depositEntity, config);
        if (!resultData.isSuccess()) {
            log.error("WASABICARD_CARD_RECHARGE ：充值默认金额异常！");
            return BaseResultDto.error(resultData.getMsg());
        }
        WasabiDepositDto depositDto = resultData.getData();

        CardRechargeOrderTable orderTable = new CardRechargeOrderTable();
        BeanUtils.copyProperties(depositDto, orderTable);
        orderTable.setReceivedCurrency("USD");
        orderTable.setCurrency("USD");
        orderTable.setRechargeFee(BigDecimal.ZERO);
        orderTable.setApproveStatus(CardApproveStatusEnum.APPROVED.getCode());
        orderTable.setUniqueId(table.getUniqueId());
        orderTable.setTransactionTime(DateUtil.formatTimestamp(depositDto.getTransactionTime()));
        orderTable.setAddTime(new Date());
        orderTable.setRechargeType(CardRechargeTypeEnum.RECHARGE_DEFAULT_AMOUNT.getCode());
        orderTable.setCardNumber(table.getCardNumber());
        rechargeOrderRepository.save(orderTable);

        CardOperateTable cardOperateTable = new CardOperateTable();
        cardOperateTable.setCardNo(table.getCardNo());
        cardOperateTable.setOperateUser(null);
        cardOperateTable.setOperateType(CardOperateTypeEnum.RECHARGE_DEFAULT_AMOUNT.getCode());
        cardOperateTable.setStatus(Constants.SUCCESS);
        cardOperateTable.setAddTime(new Date());
        cardOperateTable.setUniqueId(table.getUniqueId());
        cardOperateRepository.save(cardOperateTable);

        if (Constants.SUCCESS.equals(depositDto.getStatus())) {
            table.setStatus(Constants.SUCCESS);
            table.setModifyTime(new Date());
            cardRepository.save(table);
            // 激活成功发送邮件通知
            ucardEmailService.sendActivateCardSuccessEmail(table);
        }

        return BaseResultDto.success();
    }

    /**
     * 卡扣款分页列表
     */
    @Override
    public ResultWithPagerDto<CardWithdrawDto> queryCardWithdrawPage(CardWithdrawPageEntity entity) throws ServiceException {
        try {
            // 获取总数
            Integer count = withdrawMapper.countList(entity);
            PageDto pageDto = PageDto.format(entity, count);
            if (count == null || count <= 0) {
                return ResultWithPagerDto.success(pageDto);
            }
            List<CardWithdrawDto> dtos = withdrawMapper.pageList(entity);

            return ResultWithPagerDto.success(pageDto, dtos);
        } catch (Exception e) {
            log.error("卡扣款分页列表查询失败", e);
            throw new ServiceException("卡扣款分页列表查询失败");
        }
    }

    /**
     * 卡3ds分页列表
     */
    @Override
    public ResultWithPagerDto<Card3dsTransactionDto> queryCard3dsTransactionPage(Card3dsTransactionPageEntity entity) throws ServiceException {
        try {
            // 获取总数
            Integer count = card3dsTransactionMapper.countList(entity);
            PageDto pageDto = PageDto.format(entity, count);
            if (count == null || count <= 0) {
                return ResultWithPagerDto.success(pageDto);
            }
            List<Card3dsTransactionDto> dtos = card3dsTransactionMapper.pageList(entity);

            return ResultWithPagerDto.success(pageDto, dtos);
        } catch (Exception e) {
            log.error("卡3ds分页列表查询失败", e);
            throw new ServiceException("卡3ds分页列表查询失败");
        }
    }


    /**
     * 手动上传证件照
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public BaseResultDto uploadCardPhotoManually(CardPhotoUploadManuallyEntity entity) throws ServiceException {
        CardMerchantUserTable table = merchantUserRepository.findFirstById(entity.getId());
        if (table == null) {
            throw ServiceException.exception(Constants.INFO_NOT_FOUND);
        }
        if (table.getPhotoStatus() != null && table.getPhotoStatus() == 1) {
            table.setPhotoStatus(null);
        } else {
            table.setPhotoStatus(1);
        }
        merchantUserRepository.save(table);

        CardOperateTable operateTable = new CardOperateTable();
        operateTable.setOperateUser(entity.getCId());
        operateTable.setOperateType(CardOperateTypeEnum.MANUAL_UPLOAD_PHOTO.getCode());
        operateTable.setStatus(Constants.SUCCESS);
        operateTable.setAddTime(new Date());
        operateTable.setUniqueId(table.getUniqueId());
        cardOperateRepository.save(operateTable);
        // 发邮件给客户上传证件照片
        if (table.getPhotoStatus() != null && table.getPhotoStatus() == 1) {
            ucardEmailService.sendUserUploadPhotoEmail(table);
        }
        return BaseResultDto.success();
    }

    /**
     * 配置用户汇率
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public BaseResultDto cardUserRateConfig(CardUserRateConfigEntity entity) throws ServiceException {
        if (entity.getCardFee() != null) {
            if (entity.getCardFee().compareTo(BigDecimal.ZERO) < 0) {
                throw new ServiceException("开卡费用不能小于0");
            }
            validateDecimalPlaces(entity.getCardFee(), "userCardFee", 2);
        }
        if (entity.getCardRechargeFeeRate() != null) {
            if (entity.getCardRechargeFeeRate().compareTo(BigDecimal.ZERO) < 0) {
                throw new ServiceException("卡充值费率不能小于0");
            }
            validateDecimalPlaces(entity.getCardRechargeFeeRate(), "userCardRechargeFeeRate", 2);
        }
        if (entity.getGlobalFeeRate() != null) {
            if (entity.getGlobalFeeRate().compareTo(BigDecimal.ZERO) < 0) {
                throw new ServiceException("速汇手续费率不能小于0");
            }
            validateDecimalPlaces(entity.getGlobalFeeRate(), "userGlobalFeeRate", 10);
        }
        if (entity.getGlobalFixedFee() != null) {
            if (entity.getGlobalFixedFee().compareTo(BigDecimal.ZERO) < 0) {
                throw new ServiceException("速汇固定费率不能小于0");
            }
            validateDecimalPlaces(entity.getGlobalFixedFee(), "userGlobalFixedFee", 10);
        }

        CardMerchantUserTable userTable = merchantUserRepository.findFirstById(entity.getId());
        if (userTable == null) {
            return BaseResultDto.error("用户不存在！");
        }

        BeanUtils.copyProperties(entity, userTable);
        merchantUserRepository.save(userTable);
        return BaseResultDto.success();
    }

    /**
     * 查询认证成功用户列表
     */
    @Override
    public BaseResultDto<List<MerchantUserDto>> queryUcardUserList() throws ServiceException {
        List<MerchantUserDto> dtos = merchantUserMapper.findAllByAuthSuccess();
        return BaseResultDto.success(dtos);
    }

    /**
     * 获取卡片申请列表
     */
    @Override
    public ResultWithPagerDto<CardApplyDto> getCardApplyPageList(CardApplyPageEntity entity) throws ServiceException {
        try {
            /**
             * 格式化时间
             */
            if (entity.getEndDate() != null) {
                entity.setEndDate(DateUtil.operationDay(entity.getEndDate(), 1));
            }
            // 获取总数
            Integer count = cardApplyMapper.countList(entity);
            PageDto pageDto = PageDto.format(entity, count);
            if (count == null || count <= 0) {
                return ResultWithPagerDto.success(pageDto);
            }

            List<CardApplyDto> cardlist = cardApplyMapper.pageList(entity);

            return ResultWithPagerDto.success(pageDto, cardlist);
        } catch (Exception e) {
            log.error("获取卡片申请分页列表失败", e);
            throw new ServiceException("获取卡片申请分页列表失败");
        }
    }

    /**
     * 充值记录分页查询
     *
     * @param entity
     * @return
     * @throws ServiceException
     */
    @Override
    public BaseReportResultDto<List<CardRechargeOrderDto>, CardRechargeOrderSumDto> queryRechargePageList(CardRechargePageEntity entity) throws ServiceException {
        try {
            /**
             * 格式化时间
             */
            if (entity.getEndDate() != null) {
                entity.setEndDate(DateUtil.operationDay(entity.getEndDate(), 1));
            }
            // 获取总数
            Integer count = rechargeOrderMapper.countList(entity);
            PageDto pageDto = PageDto.format(entity, count);
            if (count == null || count <= 0) {
                return new BaseReportResultDto(Constants.SUCCESS_CODE, Constants.SEARCH_SUCCESS, pageDto);
            }

            List<CardRechargeOrderDto> dtos = rechargeOrderMapper.pageList(entity);
            CardRechargeOrderSumDto sumDto = rechargeOrderMapper.rechargeOrderSum(entity);
            CardRechargeOrderSumDto dto = CardRechargeOrderSumDto.getInstance();
            if (sumDto != null) {
                BeanUtils.copyProperties(sumDto, dto);
            }
            return new BaseReportResultDto(dtos, dto, pageDto);
        } catch (Exception e) {
            log.error("充值记录分页查询失败", e);
            throw new ServiceException("充值记录分页查询失败");
        }
    }

    /**
     * 查询国家和城市
     */
    @Override
    public List<CardCountryDto> getCardCountryList(CardCountryEntity request) {
        List<CardCountryDto> list = cardCountryMapper.getCardCountryList(request);
        return list;
    }

    /**
     * 查询交易记录分页列表
     */
    @Override
    public ResultWithPagerDto<CardTransacOrderDto> getTransacOrderPageList(CardTransacOrderPageEntity entity) throws ServiceException {
        try {
            // 获取总数
            Integer count = cardTransacOrderMapper.countList(entity);
            PageDto pageDto = PageDto.format(entity, count);
            if (count == null || count <= 0) {
                return ResultWithPagerDto.success(pageDto);
            }

            List<CardTransacOrderDto> orderTables = cardTransacOrderMapper.pageList(entity);

            return ResultWithPagerDto.success(pageDto, orderTables);
        } catch (Exception e) {
            log.error("交易信息分页列表查询失败", e);
            throw new ServiceException("交易信息分页列表查询失败");
        }
    }

    /**
     * 获取卡片类型列表
     *
     * @return 卡片类型列表
     * @throws ServiceException 服务异常
     */
    @Override
    public ResultWithPagerDto<CardTypeDto> getCardTypePageList(CardTypePageEntity entity) throws Exception {
        try {
            // 获取总数
            Integer count = cardTypeMapper.countList(entity);
            PageDto pageDto = PageDto.format(entity, count);
            if (count == null || count <= 0) {
                return ResultWithPagerDto.success(pageDto);
            }

            List<CardTypeDto> cardlist = cardTypeMapper.pageList(entity);
            SysUcardConfigTable sysUcardConfigTable = sysUcardConfigService.getByCode(Constants.WASABI_CARD_APPLY_AMOUNT);
            if (sysUcardConfigTable == null) {
                throw ServiceException.exception(Constants.SYSTEM_ERROR);
            }
            BigDecimal cardFee = new BigDecimal(sysUcardConfigTable.getValue());
            cardlist.forEach(cardTypeDto -> {
                if (cardTypeDto.getCardFee() == null) {
                    cardTypeDto.setCardFee(cardFee);
                }
            });
            return ResultWithPagerDto.success(pageDto, cardlist);
        } catch (Exception e) {
            log.error("获取卡片类型分页列表失败", e);
            throw new ServiceException("获取卡片类型分页列表失败");
        }
    }

    /**
     * 商户用户分页列表
     */
    @Override
    public ResultWithPagerDto<MerchantUserDto> getMerchantUserPageList(MerchantUserPageEntity entity) throws ServiceException {
        try {
            // 获取总数
            Integer count = cardMerchantUserMapper.countList(entity);
            PageDto pageDto = PageDto.format(entity, count);
            if (count == null || count <= 0) {
                return ResultWithPagerDto.success(pageDto);
            }

            List<MerchantUserDto> pagelist = cardMerchantUserMapper.pageList(entity);
            return ResultWithPagerDto.success(pageDto, pagelist);
        } catch (Exception e) {
            log.error("获取商户用户分页列表失败", e);
            throw new ServiceException("获取商户用户分页列表失败");
        }
    }

    /**
     * 获取卡片列表
     */
    @Override
    public ResultWithPagerDto<UcardCardDto> getCardPageList(CardPageEntity entity) throws ServiceException {
        try {
            // 获取总数
            Integer count = cardMapper.countList(entity);
            PageDto pageDto = PageDto.format(entity, count);
            if (count == null || count <= 0) {
                return ResultWithPagerDto.success(pageDto);
            }

            List<UcardCardDto> cardlist = cardMapper.pageList(entity);
            return ResultWithPagerDto.success(pageDto, cardlist);
        } catch (Exception e) {
            log.error("获取卡片分页列表失败", e);
            throw new ServiceException("获取卡片分页列表失败");
        }
    }

    /**
     * 获取我的卡片列表
     */
    @Override
    public List<UcardCardDto> getCardList(CardPageEntity entity) {
        entity.setIsDisplayCancel("1");
        return cardMapper.pageList(entity);
    }

    /**
     * 获取卡片详情
     */
    @Override
    public UcardCardDto getCardSingle(SingleLongEntity entity) throws ServiceException {
        UcardCardTable table = cardRepository.getFirstById(entity.getId());
        if (table == null) {
            throw ServiceException.exception(Constants.INFO_NOT_FOUND);
        }
        UcardCardDto dto = new UcardCardDto();
        BeanUtils.copyProperties(table, dto);

        CardTypeDto typeDto = cardTypeMapper.getByCardTypeId(table.getCardTypeId());
        dto.setRechargeCurrency(typeDto.getRechargeCurrency());
        dto.setRechargeMinQuota(typeDto.getRechargeMinQuota());
        dto.setRechargeMaxQuota(typeDto.getRechargeMaxQuota());
        dto.setRechargeDigital(typeDto.getRechargeDigital());
        dto.setRechargeFixedFee(typeDto.getRechargeFixedFee());
        CardMerchantUserTable userTable = merchantUserRepository.getByUniqueId(table.getUniqueId());
        if (userTable.getCardRechargeFeeRate() != null) {
            dto.setRechargeFeeRate(userTable.getCardRechargeFeeRate());
        } else {
            dto.setRechargeFeeRate(typeDto.getRechargeFeeRate());
        }
        return dto;
    }

    /**
     * 获取交易纪录详情
     */
    @Override
    public CardTransacOrderDto getTransactionSingle(SingleLongEntity entity) throws ServiceException {
        CardTransacOrderTable table = cardTransacOrderRepository.getFirstById(entity.getId());

        if (table == null) {
            throw ServiceException.exception(Constants.INFO_NOT_FOUND);
        }
        CardTransacOrderDto dto = new CardTransacOrderDto();
        BeanUtils.copyProperties(table, dto);
        return dto;
    }

    /**
     * 查询账户信息:钱包 和 卡
     */
    @Override
    public BaseResultDto cardAccountDropdown(CardAccountDropdownEntity entity) throws Exception {
        List<CardAccountInfoDto> dtos = new ArrayList<>();
        Long cId = entity.getCId();
        CardMerchantUserTable userTable = merchantUserRepository.findByCId(cId);
        if (userTable == null) {
            return BaseResultDto.success(dtos);
        }
        // 查询钱包余额
        UcardWalletTable walletTable = ucardWalletRepository.getFirstByCId(cId);
        if (walletTable != null) {
            CardAccountInfoDto dto = new CardAccountInfoDto();
            dto.setType("2");
            dto.setBalance(walletTable.getBalance());
            dto.setCardNumber(String.valueOf(walletTable.getId()));
            dto.setEmail(userTable.getEmail());
            dto.setCountry(userTable.getCountry());
            dtos.add(dto);
        }
        List<UcardCardTable> cardTables = cardMapper.findAllByUniqueId(userTable.getUniqueId());
        if (CollectionUtils.isNotEmpty(cardTables)) {
            for (UcardCardTable table : cardTables) {
                CardAccountInfoDto dto = new CardAccountInfoDto();
                WasabiBalanceInfoEntity infoEntity = new WasabiBalanceInfoEntity();
                infoEntity.setCardNo(table.getCardNo());
                try {
                    BaseResultDto<WasabiBalanceInfoDto> balanceInfo = wasabiDocumentApiService.getBalanceInfo(infoEntity);
                    if (balanceInfo.getCode() == 200) {
                        WasabiBalanceInfoDto infoDto = balanceInfo.getData();
                        dto.setType("1");
                        dto.setBalance(infoDto.getAmount());
                        dto.setCardNumber(table.getCardNumber());
                        dto.setEmail(userTable.getEmail());
                        dto.setCountry(userTable.getCountry());
                        dtos.add(dto);
                    }

                } catch (ServiceException e) {
                    log.error("全球速汇获取账户信息失败 - cardNumber{} ", table.getCardNumber(), e);
                }
            }
        }
        return BaseResultDto.success(dtos);
    }

    /**
     * 根据卡号查询卡信息
     */
    @Override
    public BaseResultDto queryCardInfoByCardNumber(CardInfoQueryEntity entity) throws ServiceException {
        CardInfoQueryDto dto = cardMapper.cardInfoQuery(entity);
        return BaseResultDto.success(dto);
    }
    /**
     * 验证金额小数位数不能超过10位
     *
     * @param amount    待验证的金额
     * @param fieldName 字段名称（用于错误提示）
     * @throws ServiceException 当小数位数超过10位时抛出异常
     */
    private void validateDecimalPlaces(BigDecimal amount, String fieldName, int maxDecimalPlaces) throws ServiceException {
        if (amount != null) {
            String amountStr = amount.stripTrailingZeros().toPlainString();
            int decimalIndex = amountStr.indexOf(".");
            if (decimalIndex != -1) {
                int decimalPlaces = amountStr.length() - decimalIndex - 1;
                if (decimalPlaces > maxDecimalPlaces) {
                    throw new ServiceException(fieldName + "小数位数不能超过" + maxDecimalPlaces + "位");
                }
            }
        }
    }

}
