/*
package com.crm.pay.service.impl.pay;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.crm.pay.dao.mapper.FinanceDepositAddressMapper;
import com.crm.pay.dao.repository.FinanceDepositAddressRepository;
import com.crm.pay.dao.repository.FinanceWithdrawRequestRepository;
import com.crm.pay.dao.repository.SysConfigRepository;
import com.crm.pay.entity.property.VaultodyPayPropertyEntity;
import com.crm.pay.entity.property.VaultodyPayWithdrawAddressPropertyEntity;
import com.crm.pay.entity.property.VaultodyPayWithdrawPropertyEntity;
import com.crm.pay.service.FinanceDepositService;
import com.crm.pay.service.SysChannelBankService;
import com.crm.pay.service.SysConfigService;
import com.crm.pay.service.VaultodyPayService;
import com.crm.pay.service.impl.base.BasePayServiceImpl;
import com.crm.rely.backend.core.constant.ConfigConstants;
import com.crm.rely.backend.core.constant.Constants;
import com.crm.rely.backend.model.constant.PayConstants;
import com.crm.rely.backend.core.dto.base.BaseResultDto;
import com.crm.rely.backend.model.dto.finance.withdraw.FinanceWithdrawDto;
import com.crm.rely.backend.core.dto.finance.withdraw.automatic.FinanceWithdrawVaultodyPayDto;
import com.crm.rely.backend.core.dto.system.remittance.channel.bank.SysChannelBankDto;
import com.crm.rely.backend.core.dto.ucard.TxResult;
import com.crm.rely.backend.model.entity.finance.deposit.FinanceDepositAddEntity;
import com.crm.pay.entity.FinanceDepositCallbackUpdateEntity;
import com.crm.pay.entity.finance.withdraw.FinanceWithdrawApproveChannelEntity;
import com.crm.pay.entity.finance.withdraw.FinanceWithdrawApproveChannelSubmitEntity;
import com.crm.pay.entity.finance.withdraw.automatic.FinanceWithdrawInfoEntity;
import com.crm.pay.entity.finance.withdraw.automatic.FinanceWithdrawVaultodyPayEntity;
import com.crm.rely.backend.core.entity.ucard.vaultody.callback.*;
import com.crm.rely.backend.core.pojo.table.SysConfigTable;
import com.crm.rely.backend.core.exception.PayValidatedException;
import com.crm.rely.backend.core.exception.ServiceException;
import com.crm.rely.backend.service.RedisService;
import com.crm.rely.backend.util.AESUtil;
import com.crm.rely.backend.util.HAMCSHA256Util;
import com.crm.rely.backend.util.HttpUtil;
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.jsoup.Connection;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
import java.math.BigDecimal;
import java.nio.charset.StandardCharsets;
import java.util.*;
import java.util.concurrent.atomic.AtomicReference;

@Slf4j
@Service
public class VaultodyPayServiceImpl extends BasePayServiceImpl implements VaultodyPayService {

    @Autowired
    private FinanceDepositService financeDepositService;
    @Autowired
    private FinanceDepositAddressRepository depositAddressRepository;
    @Autowired
    private SysChannelBankService sysChannelBankService;
    @Autowired
    private RedisService redisService;
    @Autowired
    private SysConfigService sysConfigService;
    @Autowired
    private FinanceDepositAddressMapper depositAddressMapper;
    @Autowired
    private SysConfigRepository sysConfigRepository;
    @Autowired
    private FinanceWithdrawRequestRepository withdrawRequestRepository;

    public static void main(String[] args) {
        // 入金
        System.out.println(AESUtil.encrypt("", "bfa5559109f94c78af615bcf00d52060"));

        System.out.println(AESUtil.decrypt("", "bfa5559109f94c78af615bcf00d52060"));

    }

    public static String getSignature(String message, String apiSecret) {
        try {
            byte[] decodedSecret = Base64.getDecoder().decode(apiSecret);
            Mac mac = Mac.getInstance("HmacSHA256");
            SecretKeySpec secretKeySpec = new SecretKeySpec(decodedSecret, "HmacSHA256");
            mac.init(secretKeySpec);
            byte[] hash = mac.doFinal(message.getBytes(StandardCharsets.UTF_8));

            return Base64.getEncoder().encodeToString(hash);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    public String getPath(String pathTemplate, String vaultId, String blockchain, String network) {
        String actualPath = String.format(pathTemplate, vaultId, blockchain, network);
        return actualPath;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public String pay(FinanceDepositAddEntity balanceSaveEntity) throws Exception {
        //通道配置
        SysRemittanceChannelTable channel = getPayChannel(PayConstants.VAULTODY_PAY_KEY);
        VaultodyPayPropertyEntity propertyEntity = getPayProperty(channel, VaultodyPayPropertyEntity.class);
        balanceSaveEntity.setCurrency(channel.getCurrency());

        FinanceDepositTable balanceTable = financeDepositService.save(balanceSaveEntity, channel);

        String address = reallocationAddress(propertyEntity, balanceTable);
        SysChannelBankTable bankTable = sysChannelBankService.getByCode(balanceTable.getBankCode(),
                channel.getCode());
        String url = String.format(propertyEntity.getAddressUrl(), address, propertyEntity.getSuccessUrl(),
                String.valueOf(balanceTable.getTransformAmount()), balanceSaveEntity.getTransformCurrency(),
                bankTable.getName(), bankTable.getEnName());
        balanceTable.setFormUrl(url);

        
        return AESJsUtil.encrypt(url, propertyEntity.getDecryptKey());
    }

    */
/**
     * 回调处理数据
     *
     * @param
     * @throws ServiceException
     *//*

    @Override
    @Transactional(rollbackFor = Exception.class)
    public BaseResultDto callback(String content, String signature) throws Exception {
        log.info("Vaultody回调通知开始：{},signature:{}", content, signature);

        if (Strings.isNullOrEmpty(content) || Strings.isNullOrEmpty(signature)) {
            log.error("Vaultody回调通知处理失败,数据为空，content:{},signature:{}", content, signature);
            return BaseResultDto.error();
        }
        SysRemittanceChannelTable channel = getPayChannel(PayConstants.VAULTODY_PAY_KEY);
        VaultodyPayPropertyEntity propertyEntity = getPayProperty(channel, VaultodyPayPropertyEntity.class);
        if (!isCallbackValid(content, propertyEntity.getWebhooksPassphrase(), signature)) {
            //打印日志 详细说明
            log.error("callback valid error");
            throw new ServiceException("callback valid error");
        }
        VaultodyCallbackEntity entity = JSON.parseObject(content, VaultodyCallbackEntity.class);
        VaultodyDataEntity dataEntity = entity.getData();
        String event = dataEntity.getEvent();
        VaultodyItemEntity itemEntity = dataEntity.getItem();
        VaultodyTokenEntity tokenEntity = itemEntity.getToken();
        String transactionId = itemEntity.getTransactionId();
        VaultodyMinedInBlockEntity blockEntity = itemEntity.getMinedInBlock();
        if (blockEntity == null || StringUtils.isEmpty(blockEntity.getHash())) {
            log.error("hash is empty，{}", JSON.toJSONString(blockEntity));
            throw new ServiceException("hash is empty");
        }
        String address = itemEntity.getAddress();
        if (StringUtils.isEmpty(address)) {
            log.error("Vaultody通知回调：address为空，{}", content);
            return BaseResultDto.error();
        }
//        String direction = itemEntity.getDirection();
        // 只处理入账
//        if (!"INCOMING_CONFIRMED_TOKEN_TX".equals(event) && !"incoming".equals(direction)) {
//            log.error("Vaultody通知回调：不是入账类型，{}", content);
//            return BaseResultDto.error();
//        }

        if (StringUtils.isEmpty(event)) {
            log.error("Vaultody通知回调：event为空，暂不处理，{}", JSON.toJSONString(entity));
            return BaseResultDto.error();
        }
        if (!"INCOMING_CONFIRMED_TOKEN_TX".equals(event)) {
            log.error("Vaultody通知回调：不是入账类型，{}", content);
            return BaseResultDto.error();
        }
        FinanceDepositAddressTable addressTable = depositAddressRepository.findByAddressOrderByAddTimeDesc(address);
        if (addressTable == null || StringUtils.isEmpty(addressTable.getSerial())) {
            log.error("Vaultody通知回调：addressTable为空，{}", content);
            return BaseResultDto.error();
        }
        FinanceDepositTable balanceTable = financeDepositService.getBySerial(addressTable.getSerial());

        if (balanceTable == null || balanceTable.getId() == null) {
            log.error("Vaultody通知回调：balanceTable为空，{}", content);
            return BaseResultDto.error();
        }
        String currency = null;
        String[] bankCodeA = balanceTable.getBankCode().split("_");
        if (bankCodeA.length >= 2) {
            currency = bankCodeA[1];
        }

        TxResult txResult;
        try {

            txResult = EncryptionHashQueryUtil.query(itemEntity.getTransactionId(), itemEntity.getBlockchain(),
                    currency);
        } catch (Exception e) {
            log.error("Vaultody通知回调：查询交易hash结果失败，{}", JSON.toJSONString(entity));
            return BaseResultDto.error();
        }

        if (txResult == null || StringUtils.isEmpty(txResult.getTo()) || StringUtils.isEmpty(itemEntity.getAddress())) {
            log.error("Vaultody通知回调：通过hash：{} 未查询到结果，{}", blockEntity.getHash(), JSON.toJSONString(entity));
            return BaseResultDto.error();
        }
        if (!txResult.getTo().equals(itemEntity.getAddress())) {
            log.error("Vaultody通知回调：通过hash：{} 比对地址不相同，{}", txResult.getTo(), itemEntity.getAddress());
            return BaseResultDto.error();
        }
        if (!txResult.getStatus().equals(itemEntity.getStatus())) {
            log.error("Vaultody通知回调：通过hash：{} 比对状态不相同，{}", txResult.getStatus(), itemEntity.getStatus());
            return BaseResultDto.error();
        }
        if (!txResult.getTimestamp().equals(blockEntity.getTimestamp())) {
            log.error("Vaultody通知回调：通过hash：{} 比对交易时间不相同，{}", txResult.getTimestamp(), blockEntity.getTimestamp());
            return BaseResultDto.error();
        }
        if (txResult.getAmount().compareTo(new BigDecimal(tokenEntity.getTokensAmount())) != 0) {
            log.error("Vaultody通知回调：通过hash：{} 比对金额不相同，{}", txResult.getAmount(), itemEntity.getAmount());
            return BaseResultDto.error();
        }

        addressTable.setContent(txResult.getContent());
        addressTable.setIsUsed(false);
        depositAddressRepository.save(addressTable);

        int status = PayConstants.CALLBACE_PROCESSING_STATUS;
        if ("success".equals(txResult.getStatus())) {
            status = PayConstants.CALLBACE_SUCCESS_STATUS;
        } else if ("failed".equals(txResult.getStatus())) {
            status = PayConstants.CALLBACE_FAIL_STATUS;
        }

        FinanceDepositCallbackUpdateEntity balanceCallbackUpdateEntity =
                getFinanceDepositCallbackUpdateEntity(addressTable.getSerial(), transactionId,
                        status, content);
        balanceCallbackUpdateEntity.setTransformAmount(new BigDecimal(tokenEntity.getTokensAmount()));

        */
/**
         * 更新数据
         *//*

        financeDepositService.updateCallback(balanceCallbackUpdateEntity);
        return BaseResultDto.success();
    }

    @Override
    public FinanceWithdrawVaultodyPayDto withdrawInfo(FinanceWithdrawInfoEntity entity) throws Exception {
        FinanceWithdrawDto withdrawDto = null;
        if (entity.getWithdrawInfoType() == null || entity.getWithdrawInfoType().equals(1)) {
            withdrawDto = financeWithdrawService.searchSingle(entity.getId());

        } else {
            //withdrawDto = financeAgentWithdrawService.searchSingle(entity.getId());
        }

        entity.setPayType(entity.getPayType());

        SysRemitChannelTable withdrawChannel = getWithdrawChannel(entity.getPayType());

        FinanceWithdrawVaultodyPayDto dto = new FinanceWithdrawVaultodyPayDto();
        dto.setAmount(withdrawDto.getTransformAmount() == null ? null :
                withdrawDto.getTransformAmount().setScale(2, BigDecimal.ROUND_DOWN));
        dto.setBankCode(withdrawDto.getBankCode());
        dto.setAddress(withdrawDto.getAddress());
        List<SysChannelBankDto> channelBank = sysChannelBankService.getByChannelCode(entity.getPayType(), 1);
        Map<String, String> currencyMap = new HashMap<>();
        for (SysChannelBankDto channelBankDto : channelBank) {
            currencyMap.put(channelBankDto.getName(), channelBankDto.getCode());
        }
        dto.setBankCodeSelect(currencyMap);

        dto.setId(withdrawDto.getId());
        dto.setWithdrawUrl(withdrawChannel.getWithdrawUrl());
        dto.setSerial(withdrawDto.getSerial());
        dto.setPayType(entity.getPayType());

        return dto;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void withdraw(FinanceWithdrawVaultodyPayEntity entity) throws Exception {
        FinanceWithdrawDto withdrawDto = null;
        Integer withdrawInfoType;
        if (entity.getWithdrawInfoType() == null || entity.getWithdrawInfoType().equals(1)) {
            withdrawDto = financeWithdrawService.searchSingle(entity.getId());
            withdrawInfoType = 1;
        } else {
            //withdrawDto = financeAgentWithdrawService.searchSingle(entity.getId());
            withdrawInfoType = 2;
        }
        entity.setCId(withdrawDto.getCId());
        entity.setSerial(withdrawDto.getSerial());
        entity.setLogin(withdrawDto.getLogin());

        VaultodyPayWithdrawPropertyEntity withdrawProperty = getWithdrawProperty(entity.getPayType(),
                VaultodyPayWithdrawPropertyEntity.class);

        String requestId = payout(entity, withdrawProperty);
        // 保存请求id 和相关数据，回调时查询验证
        FinanceWithdrawRequestTable requestTable = new FinanceWithdrawRequestTable();
        requestTable.setAddress(withdrawDto.getAddress());
        requestTable.setAmount(withdrawDto.getTransformAmount());
        requestTable.setSerial(withdrawDto.getSerial());
        requestTable.setRequestId(requestId);
        requestTable.setAddTime(new Date());
        requestTable.setWithdrawInfoType(withdrawInfoType);
        withdrawRequestRepository.save(requestTable);

        FinanceWithdrawApproveChannelSubmitEntity financeWithdrawApproveChannelSubmitEntity =
                new FinanceWithdrawApproveChannelSubmitEntity();
        financeWithdrawApproveChannelSubmitEntity.setSubmitStatus(PayConstants.PASSED_STATUS);
        financeWithdrawApproveChannelSubmitEntity.setId(entity.getId());
        financeWithdrawApproveChannelSubmitEntity.setActualPayType(entity.getPayType());
        if (entity.getWithdrawInfoType() == null || entity.getWithdrawInfoType().equals(1)) {
            financeWithdrawService.approve(financeWithdrawApproveChannelSubmitEntity);

        } else {
            //financeAgentWithdrawService.approve(financeWithdrawApproveChannelSubmitEntity);
        }


    }

    private String payout(FinanceWithdrawVaultodyPayEntity entity, VaultodyPayWithdrawPropertyEntity propertyEntity) throws Exception {
        String blockchain = null;
        if (entity.getBankCode().contains("-")) {
            blockchain = entity.getBankCode().split("-")[0];
        }
        if (entity.getBankCode().contains("_")) {
            blockchain = entity.getBankCode().split("_")[0];
        }
        if (StringUtils.isEmpty(blockchain)) {
            blockchain = entity.getBankCode();
        }
        String requestPath = getPath(propertyEntity.getCreateTokenTransactionPathTemplate(),
                propertyEntity.getVaultId(),
                blockchain, propertyEntity.getNetwork());
        AtomicReference<String> contractAddress = new AtomicReference<>();
        AtomicReference<String> fromAddress = new AtomicReference<>();
        List<VaultodyPayWithdrawAddressPropertyEntity> withdrawAddress = propertyEntity.getWithdrawAddress();
        if (CollectionUtils.isNotEmpty(withdrawAddress)) {
            withdrawAddress.forEach(item -> {
                if (item.getBankCode().equals(entity.getBankCode())) {
                    fromAddress.set(item.getFromAddress());
                    contractAddress.set(item.getContractAddress());
                }
            });
        }

        Map<String, Object> itemMap = new HashMap<>();
        itemMap.put("amount", entity.getAmount().stripTrailingZeros().toPlainString());
        itemMap.put("contractAddress", contractAddress.get());
        itemMap.put("fromAddress", fromAddress.get());
        itemMap.put("recipientAddress", entity.getAddress());
        Map<String, Object> dataMap = new HashMap<>();
        dataMap.put("item", itemMap);
        Map<String, Object> paramMap = new HashMap<>();
        paramMap.put("data", dataMap);


        // POST JSON body
        String body = JSON.toJSONString(paramMap);
        String query = "{}"; // POST 时 query 通常为空，否则按接口要求填写

        // ------------------ 时间戳（秒） ------------------
        String timestamp = String.valueOf(System.currentTimeMillis() / 1000);

        // ------------------ 构建消息用于签名 ------------------
        String message = timestamp + propertyEntity.getMethod() + requestPath + body + query;

        String signature = getSignature(message, propertyEntity.getApiSecret());
        System.out.println("Signature: " + signature);
        Map<String, String> headers = new HashMap<>();
        headers.put("x-api-key", propertyEntity.getApiKey());
        headers.put("x-api-sign", signature);
        headers.put("x-api-timestamp", timestamp);
        headers.put("x-api-passphrase", propertyEntity.getPassphrase());
        headers.put("Content-Type", "application/json");

        Connection.Response response = HttpUtil.post(propertyEntity.getBaseUrl() + requestPath, headers, body);
        log.info(String.format("url:%s,json:%s,body:%s",
                propertyEntity.getBaseUrl() + requestPath, body, response.body()));

        // 解析 JSON 字符串
        JSONObject jsonObject = JSON.parseObject(response.body());
        if (response.statusCode() != 200
                && response.statusCode() != 201
                && (jsonObject.getJSONObject("data") == null || !"created".equals(jsonObject.getJSONObject("data").getJSONObject("item").getString("transactionRequestStatus")))
        ) {
            log.error("vaultody withdraw address: {} error: {}", entity.getAddress(), response.body());
            throw new PayValidatedException("Payment platform is abnormal, please try again later or contact " +
                    "customer service.");
        }

        String requestId = jsonObject.getJSONObject("data").getJSONObject("item").getString("transactionRequestId");   // 提取
        // transactionRequestId
        if (Strings.isNullOrEmpty(requestId)) {
            throw new PayValidatedException("Payment platform is abnormal, please try again later or contact customer" +
                    " service.");
        }

        return requestId;

    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public BaseResultDto withdrawCallback(String content, String signature) throws Exception {
        log.info("vaultody withdraw callback：{},signature:{}", content, signature);

        if (Strings.isNullOrEmpty(content) || Strings.isNullOrEmpty(signature)) {
            log.error("vaultody withdraw callback error,data is empty，content:{},signature:{}", content, signature);
            return BaseResultDto.error();
        }
        VaultodyPayWithdrawPropertyEntity withdrawProperty = getWithdrawProperty(PayConstants.VAULTODY_PAY_REMIT,
                VaultodyPayWithdrawPropertyEntity.class);

        if (!isCallbackValid(content, withdrawProperty.getWebhooksPassphrase(), signature)) {
            //打印日志 详细说明
            log.error("vaultody withdraw callback valid error");
            throw new ServiceException("vaultody withdraw callback valid error");
        }
        VaultodyCallbackEntity entity = JSON.parseObject(content, VaultodyCallbackEntity.class);
        VaultodyDataEntity dataEntity = entity.getData();
        String event = dataEntity.getEvent();
        VaultodyItemEntity itemEntity = dataEntity.getItem();
        String transactionId = itemEntity.getTransactionId();
        String requestId = itemEntity.getRequestId();
        if (StringUtils.isEmpty(requestId)) {
            log.error("vaultody withdraw callback：requestId is empty，{}", content);
            return BaseResultDto.error();
        }

        if (StringUtils.isEmpty(event)) {
            log.error("vaultody withdraw callback：event is empty，{}", JSON.toJSONString(entity));
            return BaseResultDto.error();
        }

        if (!"OUTGOING_MINED".equals(event)) {
            log.error("vaultody withdraw callback：notice type error，{}", content);
            return BaseResultDto.error();
        }

        FinanceWithdrawRequestTable requestTable = withdrawRequestRepository.findFirstByRequestId(requestId);
        if (requestTable == null || StringUtils.isEmpty(requestTable.getSerial())) {
            log.error("vaultody withdraw callback：order not exist，{}", content);
            return BaseResultDto.error();
        }

        BigDecimal transformAmount = requestTable.getAmount();
        String address = requestTable.getAddress();
        Integer withdrawInfoType = requestTable.getWithdrawInfoType();
        String bankCode = null;
        if (withdrawInfoType == null || withdrawInfoType.equals(1)) {
            FinanceWithdrawTable financeWithdrawTable = financeWithdrawService.getBySerial(requestTable.getSerial());
            if (financeWithdrawTable == null) {
                log.error("vaultody withdraw callback：order not exist，{}", requestTable.getSerial());
                return BaseResultDto.error();
            }
            bankCode = financeWithdrawTable.getBankCode();

        } else {
            FinanceAgentWithdrawTable financeAgentWithdrawTable =
                    financeAgentWithdrawService.getBySerial(requestTable.getSerial());
            if (financeAgentWithdrawTable == null) {
                log.error("vaultody withdraw callback：order not exist，{}", requestTable.getSerial());
                return BaseResultDto.error();
            }

            bankCode = financeAgentWithdrawTable.getBankCode();
        }

        String currency = null;
        String[] bankCodeA = bankCode.split("_");
        if (bankCodeA.length >= 2) {
            currency = bankCodeA[1];
        }

        TxResult txResult;
        try {
            txResult = EncryptionHashQueryUtil.query(transactionId, itemEntity.getBlockchain(), currency);
        } catch (Exception e) {
            log.error("vaultody withdraw callback：查询交易hash结果失败，{}", content);
            return BaseResultDto.error();
        }

        if (txResult == null || StringUtils.isEmpty(txResult.getTo())) {
            log.error("vaultody withdraw callback：通过hash：{} 未查询到结果，{}", transactionId, content);
            return BaseResultDto.error();
        }
        if (!txResult.getTo().equals(address)) {
            log.error("vaultody withdraw callback：通过hash：{} 比对地址不相同，{}", txResult.getTo(), address);
            return BaseResultDto.error();
        }
        if (txResult.getAmount().compareTo(transformAmount) != 0) {
            log.error("vaultody withdraw callback：通过hash：{} 比对金额不相同，{}", txResult.getAmount(), transformAmount);
            return BaseResultDto.error();
        }

        FinanceWithdrawApproveChannelEntity financeWithdrawApproveChannelEntity =
                new FinanceWithdrawApproveChannelEntity();
        financeWithdrawApproveChannelEntity.setChannelSerial(transactionId);

        if ("success".equals(txResult.getStatus())) {
            financeWithdrawApproveChannelEntity.setCallbackStatus(PayConstants.CALLBACE_SUCCESS_STATUS);
        } else if ("failed".equals(txResult.getStatus())) {
            financeWithdrawApproveChannelEntity.setCallbackStatus(PayConstants.CALLBACE_FAIL_STATUS);
        }
        financeWithdrawApproveChannelEntity.setSerial(requestTable.getSerial());

        */
/**
         * 更新数据
         *//*

        if (withdrawInfoType == null || withdrawInfoType.equals(1)) {
            financeWithdrawService.approve(financeWithdrawApproveChannelEntity);

        } else {
            //financeAgentWithdrawService.channel(financeWithdrawApproveChannelEntity);
        }

        return BaseResultDto.success();
    }


    */
/**
     * 获取钱包地址
     *//*

    @Transactional(rollbackFor = Exception.class)
    public String getAddress(VaultodyPayPropertyEntity propertyEntity, FinanceDepositTable balanceTable) throws Exception {
        String requestPath = getPath(propertyEntity.getAddressPathTemplate(), propertyEntity.getVaultId(),
                balanceTable.getBankCode().split("_")[0],
                propertyEntity.getNetwork());
        String apiKey = propertyEntity.getApiKey();
        String apiSecret = propertyEntity.getApiSecret();
        String passphrase = propertyEntity.getPassphrase();
        String method = propertyEntity.getMethod();
        String baseUrl = propertyEntity.getBaseUrl();

        Map<String, Object> labelMap = new HashMap<>();
        labelMap.put("label", balanceTable.getSerial());
        Map<String, Object> itemMap = new HashMap<>();
        itemMap.put("item", labelMap);
        Map<String, Object> paramMap = new HashMap<>();
        paramMap.put("data", itemMap);

        // POST JSON body
        String body = JSON.toJSONString(paramMap);
        String query = "{}"; // POST 时 query 通常为空，否则按接口要求填写

        // ------------------ 时间戳（秒） ------------------
        String timestamp = String.valueOf(System.currentTimeMillis() / 1000);

        // ------------------ 构建消息用于签名 ------------------
        String message = timestamp + method + requestPath + body + query;

        String signature = getSignature(message, apiSecret);
        System.out.println("Signature: " + signature);
        Map<String, String> headers = new HashMap<>();
        headers.put("x-api-key", apiKey);
        headers.put("x-api-sign", signature);
        headers.put("x-api-timestamp", timestamp);
        headers.put("x-api-passphrase", passphrase);
        headers.put("Content-Type", "application/json");

        Connection.Response response = HttpUtil.post(baseUrl + requestPath, headers, body);
        log.info(String.format("url:%s,json:%s,body:%s", baseUrl + requestPath, body, response.body()));
        if (response.statusCode() != 200) {
            log.error("订单: {} 钱包地址生成失败: {}", balanceTable.getSerial(), response.body());
            throw new PayValidatedException("Payment platform is abnormal, please try again later or contact customer" +
                    " service.");
        }
        // 解析 JSON 字符串
        JSONObject jsonObject = JSON.parseObject(response.body());

        // 获取 address 和 label 字段
        String address = jsonObject.getJSONObject("data").getJSONObject("item").getString("address");

        return address;
    }

    */
/**
     * 回调请求
     *
     * @param
     * @return
     * @throws ServiceException
     *//*

    private boolean isCallbackValid(String message, String apiSecret, String signature) {
        String _signature = HAMCSHA256Util.sha256_HMAC(message, apiSecret);

        //打印签名 两个签名数据和比对结果
        log.info("isCallbackValid,_signature：{}，signature：{}", _signature, signature);

        return _signature.equals(signature);
    }


    */
/**
     * 分配地址
     *//*

    @Transactional(rollbackFor = Exception.class)
    public String reallocationAddress(VaultodyPayPropertyEntity propertyEntity, FinanceDepositTable balanceTable) throws Exception {
        SysConfigTable configTable = sysConfigService.getByCode(ConfigConstants.VAULTODY_ADDRESS_TOTAL_NUMBER);
        if (configTable == null || configTable.getValue() == null || Long.parseLong(configTable.getValue()) <= 0) {
            throw ServiceException.exception(Constants.SYSTEM_ERROR);
        }
        long addressTotalNumber = Long.parseLong(configTable.getValue());

        long addressNumber = updateConfigTableInNewTransaction();

        String address;
        if (addressNumber > addressTotalNumber) {
            //计算查询数据下标
            int index = Math.toIntExact((addressNumber - 1) % addressTotalNumber);
            address = depositAddressMapper.getTableByIndex(index);
        } else {
            address = getAddress(propertyEntity, balanceTable);
        }
        // 保存数据
        FinanceDepositAddressTable table = new FinanceDepositAddressTable();
        table.setAddress(address);
        table.setSerial(balanceTable.getSerial() + "_" + balanceTable.getLogin());
        table.setLastUsendTime(new Date());
        table.setAddTime(new Date());
        table.setIsUsed(true);
        depositAddressRepository.save(table);
        return address;
    }

    @Transactional(rollbackFor = Exception.class, propagation = Propagation.REQUIRES_NEW)
    public long updateConfigTableInNewTransaction() throws ServiceException {
        Long number = redisService.incr(ConfigConstants.ADDRESS_ID_CONTROL_AUTO_NUMBER);
        SysConfigTable sysConfigTable = sysConfigRepository.getByCode(ConfigConstants.ADDRESS_ID_CONTROL_AUTO_NUMBER);
        sysConfigTable.setValue(String.valueOf(number));
        sysConfigRepository.save(sysConfigTable);
        return number;
    }


}



*/
