package com.izouma.nineth.service;

import cn.hutool.core.date.DateUtil;
import cn.hutool.core.date.LocalDateTimeUtil;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.anji.captcha.util.StringUtils;
import com.izouma.nineth.config.RedisKeys;
import com.izouma.nineth.config.SysConstants;
import com.izouma.nineth.domain.*;
import com.izouma.nineth.dto.pay.PayResult;
import com.izouma.nineth.enums.*;
import com.izouma.nineth.exception.BusinessException;
import com.izouma.nineth.lock.RedisLockable;
import com.izouma.nineth.repo.*;
import com.izouma.nineth.service.pay.PayHelper;
import com.izouma.nineth.utils.IPUtils;
import com.izouma.nineth.utils.SnowflakeIdWorker;
import com.izouma.nineth.utils.sandpay.SandpayClient;
import com.izouma.nineth.utils.sandpay.SandpayNewClient;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;

import javax.transaction.Transactional;
import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;

/**
 * 杉德支付服务
 */
@Service
@AllArgsConstructor
@Slf4j
public class SandpayService {


    private SandpayClient sandpayClient;

    private SandpayNewClient sandpayNewClient;

    private DivMoneyRepo divMoneyRepo;

    private OrderRepo orderRepo;

    private TransferMoneyInfoRepo transferMoneyInfoRepo;


    private SnowflakeIdWorker snowflakeIdWorker;

    private UserBankCardRepo userBankCardRepo;

    private PayHelper payHelper;

    private UserFundAccountRepo userFundAccountRepo;

    private PaymentInfoRepo paymentInfoRepo;

    private IdentityAuthRepo identityAuthRepo;

    private UserRepo userRepo;

    private SysConfigService sysConfigService;

    /**
     * 获取用户账号
     *
     * @param userId
     * @return
     */
    private String getBizUserId(Long userId) {
        User user = userRepo.findById(userId).orElseThrow(new BusinessException("用户不存在"));
        //多平台唯一ID
        String memberPrefix  = sysConfigService.getStringDefault(SysConstants.MEMBER_PREFIX);
        //多平台唯一编号,杉德限制最长10位
        String uniqueUserId = memberPrefix + user.getId().toString();
        return uniqueUserId;
    }



    /**
     * 解析结果内容
     * @param wrappedData
     * @return
     */
    public JSONObject checkSuccessBody(String wrappedData) throws Exception{
        JSONObject resBodyJson = sandpayClient.checkSuccessBody(wrappedData);
        return resBodyJson;
    }


    /**
     * 解析资金交易结果内容
     * @param wrappedData
     * @return
     */
    public JSONObject checkFundSuccessBody(String wrappedData) throws Exception{
        JSONObject resBodyJson = sandpayClient.checkFundSuccessBody(wrappedData);
        return resBodyJson;
    }


    /**
     * 一键快捷入口(需要绑卡)
     *
     * @return
     */
    public String quickPayCreate(PaymentInfo paymentInfo) throws Exception{

        String uniqueUserId = getBizUserId(paymentInfo.getUserId());

        String orderTime = DateTimeFormatter.ofPattern("yyyyMMddHHmmss").format(LocalDateTime.now());
        String totalAmount = String.format("%012d",paymentInfo.getPayAmt().multiply(new BigDecimal(100)).intValue());
        JSONObject bodyJson = new JSONObject();
        bodyJson.put("userId", uniqueUserId);
        bodyJson.put("orderCode", paymentInfo.getOrderNo());
        bodyJson.put("orderTime", orderTime);
        bodyJson.put("totalAmount", totalAmount);
        bodyJson.put("txnTimeOut", paymentInfo.getTimeExpire());
        bodyJson.put("subject", paymentInfo.getGoodsTitle());
        bodyJson.put("body", paymentInfo.getGoodsTitle());
        bodyJson.put("currencyCode", "156");//默认156
        bodyJson.put("notifyUrl", paymentInfo.getNotifyUrl());

        String returnUrl = payHelper.resolveReturnUrl(paymentInfo);
        bodyJson.put("frontUrl", returnUrl);
        //0：T1（不填则默认）, 1：T0 ,2：D0,3：D1
        bodyJson.put("clearCycle", "0");


        //分账字段
//        JSONObject accsplitInfo = new JSONObject();
//        //accsplitInfo.put("accsplitMode", "3");
//        accsplitInfo.put("accsplitFlag", "1");
//        bodyJson.put("accsplitInfo", accsplitInfo);
        String formStr = sandpayClient.generateForm("/fastPay/quickPay/index",
                "sandPay.fastPay.quickPay.index", "00000016",
                bodyJson, "");

        return formStr;
    }



    /**
     * 新快捷支付入口
     *
     * @return
     */
    public String quickPayCreateNew(PaymentInfo paymentInfo){
        IdentityAuth identityAuth = identityAuthRepo.findFirstByUserIdAndStatusAndDelFalseOrderByCreatedAtDesc(paymentInfo.getUserId(), AuthStatus.SUCCESS)
                .orElseThrow(new BusinessException("用户未实名认证,请先实名认证"));

        String uniqueUserId = getBizUserId(paymentInfo.getUserId());

        String orderTime = DateTimeFormatter.ofPattern("yyyyMMddHHmmss").format(LocalDateTime.now());
        JSONObject bodyJson = new JSONObject();
        bodyJson.put("mer_order_no", paymentInfo.getOrderNo());//商户订单号
        bodyJson.put("create_time", orderTime);//订单创建时间
        bodyJson.put("expire_time", paymentInfo.getTimeExpire());
        bodyJson.put("order_amt", paymentInfo.getPayAmt());
        bodyJson.put("notify_url", paymentInfo.getNotifyUrl());
        String returnUrl = payHelper.resolveReturnUrl(paymentInfo);
        bodyJson.put("return_url", returnUrl);

        String fromIp = IPUtils.getIpAddr().replace(".","_");
        bodyJson.put("create_ip", fromIp);

        bodyJson.put("goods_name", paymentInfo.getGoodsTitle());
        bodyJson.put("store_id",  "000000");//门店号
        bodyJson.put("product_code",  "06030003");//产品编码(快捷充值)

        JSONObject payExtra = new JSONObject();
        payExtra.put("userId", uniqueUserId);
        //证件姓名
        payExtra.put("userName", identityAuth.getRealName());
        //18位身份证号
        payExtra.put("idCard", identityAuth.getIdNo());
        bodyJson.put("pay_extra", payExtra.toJSONString());//扩展域


        bodyJson.put("clear_cycle", "0");//0-T1(默认);1-T0;2-D0;3-D1

        bodyJson.put("accsplit_flag", "NO");//是否分账
        //bodyJson.put("activity_no", "");
        //bodyJson.put("benefit_amount", "");
        bodyJson.put("jump_scheme", "sandcash://scpay");
        //bodyJson.put("gh_static_url", "");
        //bodyJson.put("limit_pay", "");
        //bodyJson.put("extend_params", "");
        bodyJson.put("meta_option", "[{\"s\":\"Android\",\"n\":\"\",\"id\":\"\",\"sc\":\"\"},{\"s\":\"IOS\",\"n\":\"\",\"id\":\"\",\"sc\":\"\"}]");

        String formStr = sandpayNewClient.generateUrl("/pay/h5/quicktopup", bodyJson);

        return formStr;
    }




    /**
     * 订单查询
     * @param orderNo
     * @return
     */
    public JSONObject quickPayOrderQuery(String orderNo) {
        JSONObject bodyJson = new JSONObject();
        bodyJson.put("orderCode", orderNo);
        JSONObject resBodyJson = sandpayClient.postForm("/gateway/api/order/query",
                "sandpay.trade.query", "00000016",
                bodyJson, "");
        return resBodyJson;
    }


    /**
     *
     * 交易退款
     *
     */
    public JSONObject quickPayRefund(PaymentInfo paymentInfo, String refundReason) {
        String orderCode = String.valueOf(snowflakeIdWorker.nextId());
        String refundAmount =  String.format("%012d",
                paymentInfo.getPayAmt().multiply(new BigDecimal(100)).intValue());
        String notifyUrl = payHelper.resolveRefundNotifyUrl(paymentInfo.getOrderNo());
        JSONObject bodyJson = new JSONObject();
        bodyJson.put("orderCode", orderCode);
        bodyJson.put("oriOrderCode", paymentInfo.getOrderNo());
        bodyJson.put("refundAmount", refundAmount);
//        bodyJson.put("refundMarketAmount", "");//营销金额,可选
        bodyJson.put("notifyUrl", notifyUrl);
        bodyJson.put("refundReason", refundReason);
        JSONObject resBodyJson = sandpayClient.postForm("/gateway/api/order/refund",
                "sandpay.trade.refund", "00000016",
                bodyJson, "");
        return resBodyJson;

    }

    /**
     * 订单查询(新)
     * @param orderNo
     * @return
     */
    public JSONObject quickPayOrderQueryNew(String orderNo) {
        JSONObject bodyJson = new JSONObject();
        bodyJson.put("orderCode", orderNo);
        JSONObject resBodyJson = sandpayClient.postForm("/gateway/api/order/query",
                "sandpay.trade.query", "06030003",
                bodyJson, "");
        return resBodyJson;
    }


    /**
     *
     * 交易退款(新)
     *
     */
    public JSONObject quickPayRefundNew(PaymentInfo paymentInfo, String refundReason) {
        String orderCode = String.valueOf(snowflakeIdWorker.nextId());
        String refundAmount =  String.format("%012d",
                paymentInfo.getPayAmt().multiply(new BigDecimal(100)).intValue());
        String notifyUrl = payHelper.resolveRefundNotifyUrl(paymentInfo.getOrderNo());
        JSONObject bodyJson = new JSONObject();
        bodyJson.put("orderCode", orderCode);
        bodyJson.put("oriOrderCode", paymentInfo.getOrderNo());
        bodyJson.put("refundAmount", refundAmount);
//        bodyJson.put("refundMarketAmount", "");//营销金额,可选
        bodyJson.put("notifyUrl", notifyUrl);
        bodyJson.put("refundReason", refundReason);
        JSONObject resBodyJson = sandpayClient.postForm("/gateway/api/order/refund",
                "sandpay.trade.refund", "06030003",
                bodyJson, "");
        return resBodyJson;

    }

    /**
     * h5收银台
     * @param paymentInfo
     * @return
     * @
     */
    public String h5payCreate(PaymentInfo paymentInfo) throws Exception{
        String totalAmount = String.format("%012d", paymentInfo.getPayAmt().multiply(new BigDecimal(100)).intValue());
        JSONObject bodyJson = new JSONObject();
        bodyJson.put("orderCode", paymentInfo.getOrderNo());
        bodyJson.put("totalAmount", totalAmount);
        bodyJson.put("subject", paymentInfo.getGoodsTitle());
        bodyJson.put("body", paymentInfo.getGoodsTitle());
        bodyJson.put("txnTimeOut", paymentInfo.getTimeExpire());
        bodyJson.put("notifyUrl", paymentInfo.getNotifyUrl());
        //bodyJson.put("accountingMode", "02");//即时

        String returnUrl = payHelper.resolveReturnUrl(paymentInfo);

        bodyJson.put("frontUrl", returnUrl);
        //0：T1（不填则默认）, 1：T0 ,2：D0,3：D1
        bodyJson.put("clearCycle", "0");

        //分账字段
//        JSONObject accsplitInfo = new JSONObject();
//        accsplitInfo.put("accsplitMode", "3");
//        accsplitInfo.put("accsplitFlag", "1");
//        bodyJson.put("accsplitInfo", accsplitInfo);

        String formStr = sandpayClient.generateForm("/gw/web/order/create",
                "sandpay.trade.orderCreate", "00002000",
                bodyJson, "");
        return formStr;
    }

    /**
     * 订单查询
     * @param orderNo
     * @return
     */
    public JSONObject h5PayOrderQuery(String orderNo) {
        JSONObject bodyJson = new JSONObject();
        bodyJson.put("orderCode", orderNo);
        JSONObject resBodyJson = sandpayClient.postForm("/gw/api/order/query",
                "sandpay.trade.query", "00002000",
                bodyJson, "");
        return resBodyJson;
    }

    /**
     *
     * 交易退款
     *
     */
    public JSONObject h5Refund(PaymentInfo paymentInfo, String refundReason) {
        String orderCode = String.valueOf(snowflakeIdWorker.nextId());
        String refundAmount =  String.format("%012d",
                paymentInfo.getPayAmt().multiply(new BigDecimal(100)).intValue());
        String notifyUrl = payHelper.resolveRefundNotifyUrl(paymentInfo.getOrderNo());
        JSONObject bodyJson = new JSONObject();
        bodyJson.put("orderCode", orderCode);
        bodyJson.put("oriOrderCode", paymentInfo.getOrderNo());
        bodyJson.put("refundAmount", refundAmount);
//        bodyJson.put("refundMarketAmount", "");//营销金额,可选
        bodyJson.put("notifyUrl", notifyUrl);
        bodyJson.put("refundReason", refundReason);
        JSONObject resBodyJson = sandpayClient.postForm("/gw/api/order/refund",
                "sandpay.trade.refund", "00002000",
                bodyJson, "");
        return resBodyJson;

    }

    /**
     * 云账户下单
     * @param paymentInfo
     * @return
     */
    public JSONObject accountPayCreate(PaymentInfo paymentInfo) {
        String totalAmount = String.format("%012d", paymentInfo.getPayAmt().multiply(new BigDecimal(100)).intValue());
        JSONObject bodyJson = new JSONObject();
        bodyJson.put("payTool", "0409");//固定值0409
        bodyJson.put("orderCode", paymentInfo.getOrderNo());
        //会员账号
        Long userFundAccountId = paymentInfo.getUserFundAccountId();
        if(userFundAccountId == null){
            throw new BusinessException("缺失云账户参数信息");
        }

        UserFundAccount account = userFundAccountRepo.findById(userFundAccountId).orElseThrow(new BusinessException("钱包账户未找到"));
        bodyJson.put("masterAccount", account.getThirdUserId());
        bodyJson.put("totalAmount", totalAmount);
        bodyJson.put("subject", paymentInfo.getGoodsTitle());
        bodyJson.put("body", paymentInfo.getGoodsTitle());
        //bodyJson.put("accountAmt", "");
        //bodyJson.put("byfAmt", "");
        bodyJson.put("txnTimeOut", paymentInfo.getTimeExpire());
        bodyJson.put("notifyUrl", paymentInfo.getNotifyUrl());
        //bodyJson.put("bizExtendParams", "");//扩展业务参数

        String returnUrl = payHelper.resolveReturnUrl(paymentInfo);

        bodyJson.put("frontUrl", returnUrl);
        //0：T1（不填则默认）, 1：T0 ,2：D0,3：D1
        bodyJson.put("clearCycle", "0");

        //分账字段
//        JSONObject accsplitInfo = new JSONObject();
//        accsplitInfo.put("accsplitMode", "3");
//        accsplitInfo.put("accsplitFlag", "1");
//        bodyJson.put("accsplitInfo", accsplitInfo);

        //云账户合作电子支付户余额支付：00002046
        //云账户合作电子宝易付支付：00002047
        //云账户组合支付：00002048
        JSONObject res = sandpayClient.postForm("/gw/cloudAcc/createOrder",
                "sandPay.cloud.acc.pay.createOrder", "00002046",
                bodyJson, "");
        return res;
    }


    /**
     * 账户支付短信验证确认
     * @param orderNo
     * @param smsCode
     * @return
     * @throws Exception
     */
    @RedisLockable(prefix = RedisKeys.WALLET_PAY_CONFIRM_LOCK, key = "#orderNo")
    @Transactional(rollbackOn = Exception.class)
    public JSONObject accountPayConfirm(String orderNo, String smsCode) {
        PaymentInfo paymentInfo = paymentInfoRepo.findByOrderNo(orderNo).orElseThrow(new BusinessException("订单记录不存在"));
        if(paymentInfo.getStatus() != PayStatus.UNPAID){
            throw new BusinessException("支付状态不正确");
        }

        String totalAmount = String.format("%012d", paymentInfo.getPayAmt().multiply(new BigDecimal(100)).intValue());
        JSONObject bodyJson = new JSONObject();
        //会员账号
        Long userFundAccountId = paymentInfo.getUserFundAccountId();
        if(userFundAccountId == null){
            throw new BusinessException("缺失云账户参数信息");
        }

        UserFundAccount account = userFundAccountRepo.findById(userFundAccountId).orElseThrow(new BusinessException("钱包账户未找到"));
        bodyJson.put("masterAccount", account.getThirdUserId());
        bodyJson.put("oriCustomerOrderNo", paymentInfo.getOrderNo());
        bodyJson.put("oriTotalAmount", totalAmount);
        bodyJson.put("smsCode", smsCode);

        JSONObject res = sandpayClient.postForm("/gw/cloudAcc/balancePay",
                "sandPay.cloud.acc.pay.confirm", "00002046",
                bodyJson, "");
        return res;

    }

    /**
     * 云账户支付订单查询
     * @param orderNo
     * @return
     */
    public JSONObject accountPayOrderQuery(String orderNo) {
        JSONObject bodyJson = new JSONObject();
        bodyJson.put("orderCode", orderNo);
        JSONObject res = sandpayClient.postForm("/gw/api/order/query",
                "sandpay.trade.query", "00002046",
                bodyJson, "");
        return res;
    }

    /**
     *
     * 交易退款
     *
     */
    public JSONObject accountPayRefund(PaymentInfo paymentInfo, String refundReason) {
        String orderCode = String.valueOf(snowflakeIdWorker.nextId());
        String refundAmount =  String.format("%012d",
                paymentInfo.getPayAmt().multiply(new BigDecimal(100)).intValue());
        String notifyUrl = payHelper.resolveRefundNotifyUrl(paymentInfo.getOrderNo());
        JSONObject bodyJson = new JSONObject();
        bodyJson.put("orderCode", orderCode);
        bodyJson.put("oriOrderCode", paymentInfo.getOrderNo());
        bodyJson.put("refundAmount", refundAmount);
        bodyJson.put("notifyUrl", notifyUrl);
        bodyJson.put("refundReason", refundReason);
        JSONObject resBodyJson = sandpayClient.postForm("/gw/api/order/refund",
                "sandpay.trade.refund", "00002046",
                bodyJson, "");
        return resBodyJson;

    }

    /**
     * 新增接收方
     * @return
     */
    public String addReceiveCustomer(String memberId, String realName, String idNo, String bankNo) throws  Exception{
        JSONObject params = new JSONObject();
        JSONArray accsplitMerList = new JSONArray();
        JSONObject customerItem = new JSONObject();
        customerItem.put("accsplitMerName", memberId);
        customerItem.put("merType", "01");//01-个人 02-企业
//        customerItem.put("businessLicenseType", "");//企业必填
//        customerItem.put("businessLicense", "");//企业必填
        //1：身份证
        //2：护照
        //3：港澳台证
        //4：军官证
        //5：户口薄
        //6：驾驶证
        customerItem.put("userPapersType", "1");//证件类型
        customerItem.put("papersNo", idNo);
        //0-T1(默认)
        //1-T0
        //2-D0
        //3-D1
        customerItem.put("clearCycle", "0");
        //1：对公 2：对私
        customerItem.put("accountNature", "2");
        //01：个人银行卡账户
        //02：对公银行账户
        //03：对私支付账户
        //04：对公支付账户
        //05：存折
        //06：预付费卡钱包
        //07：预付费卡主账户
        customerItem.put("accountType", "01");
        customerItem.put("account", bankNo);
        customerItem.put("accountName", realName);
        String effectiveDate = LocalDateTimeUtil.format(LocalDateTime.now(), "YYYYMMddHHmmss");
        customerItem.put("effectiveDate", effectiveDate);
        customerItem.put("expiryDate", "20991231235959");
        accsplitMerList.add(customerItem);
        params.put("accsplitMerList", accsplitMerList);

        JSONObject resBodyJson = sandpayClient.postForm("/multipart/customer/save",
                "sandpay.multipart.customer.save",
                "00000016", params, "");
        JSONArray resMerList = resBodyJson.getJSONArray("accsplitMerList");
        JSONObject resMerItem = resMerList.getJSONObject(0);
        String accsplitMerNo = resMerItem.getString("accsplitMerNo");//接收方编号
        String accsplitMerName = resMerItem.getString("accsplitMerName");//接收方名称
        return accsplitMerNo;
    }


    /**
     * 分账处理
     * @param tradeNo
     * @param orderNo
     * @param thirdAccountId
     * @param amount
     * @return
     * @throws Exception
     */
    public JSONObject mutipart(String tradeNo, String orderNo, String thirdAccountId, BigDecimal amount) {
        JSONObject params = new JSONObject();
        params.put("orderCode", tradeNo);
        params.put("oriOrderCode", orderNo);
        JSONObject accsplitInfo = new JSONObject();
        accsplitInfo.put("accsplitMode", "0");//0 - 各分账接收方指定金额
        accsplitInfo.put("accsplitMore", "0");//0-单次(默认)
        JSONObject accsplitRules = new JSONObject();
        accsplitRules.put("accsplitRule", "0");//指定金额
        String totalAmt = String.format("%012d", amount.multiply(new BigDecimal(100)).intValue());
        accsplitRules.put("accsplitTotalAmt", totalAmt);
        JSONArray accsplitRuleMerchantList = new JSONArray();
        JSONObject divItem = new JSONObject();
        divItem.put("accsplitMerNo", thirdAccountId);
        divItem.put("fixedAmt", "000000000000");
        divItem.put("accsplitAmt", totalAmt);
        accsplitRuleMerchantList.add(divItem);
        accsplitRules.put("accsplitRuleMerchantList", accsplitRuleMerchantList);
        accsplitInfo.put("accsplitRules", accsplitRules);
        params.put("accsplitInfo", accsplitInfo);

        JSONObject res = sandpayClient.postForm("/multipart/create", "sandpay.multipart.create", "00000016",
                params, "");
        return res;
    }


    /**
     * 实时转账
     * @param tradeNo
     * @param userBankCard
     * @param amount
     * @return
     */
    public JSONObject realTransfer(String tradeNo, UserBankCard userBankCard, BigDecimal amount, LocalDateTime createdAt) {
        JSONObject params = new JSONObject();
        String tranTime = LocalDateTimeUtil.format(createdAt, "YYYYMMddHHmmss");

        params.put("version", "01");
        //付款对私：00000004
        //付款对公：00000003
        params.put("productId", "00000004");
        params.put("tranTime", tranTime);
        params.put("orderCode", tradeNo);

//        params.put("timeOut", "");//不填默认24小时
        String totalAmt = String.format("%012d", amount.multiply(new BigDecimal(100)).intValue());
        params.put("tranAmt", totalAmt);
        params.put("currencyCode", "156");//固定156
        //0-对私
        //1-对公
        //注：accAttr选择对私时，accType选银行卡
        params.put("accAttr", "0");
        //3-公司账户
        //4-银行卡
        params.put("accType", "4");
        params.put("accNo", userBankCard.getBankNo());
        params.put("accName", userBankCard.getRealName());
        //如需发送交易结果至收款方，则必填
        //params.put("phone", userBankCard.getPhone());

        JSONObject res = sandpayClient.fundPostForm("/agent-main/openapi/agentpay", "RTPM", params);
        return res;
    }

    /**
     * 转账交易结果查询
     * @return
     */
    public JSONObject realTransferQuery(String tradeNo, LocalDateTime createdAt) {
        JSONObject params = new JSONObject();
        String tranTime = LocalDateTimeUtil.format(createdAt, "YYYYMMddHHmmss");

        params.put("version", "01");
        //付款对私：00000004
        //付款对公：00000003
        params.put("productId", "00000004");
        params.put("tranTime", tranTime);
        params.put("orderCode", tradeNo);

        JSONObject res = sandpayClient.fundPostForm("/agent-main/openapi/queryOrder", "ODQU", params);
        return res;
    }

    /**
     * 账户余额
     * @return
     * @throws Exception
     */
    public JSONObject queryBalance() {
        String tradeNo = String.valueOf(snowflakeIdWorker.nextId());
        JSONObject params = new JSONObject();
        String tranTime = LocalDateTimeUtil.format(LocalDateTime.now(), "YYYYMMddHHmmss");

        params.put("version", "01");
        //付款对私：00000004
        //付款对公：00000003
        params.put("productId", "00000004");
        params.put("tranTime", tranTime);
        params.put("orderCode", tradeNo);
        //07-互联网, 08-移动端
        params.put("channelType", "08");

        JSONObject res = sandpayClient.fundPostForm("/agent-main/openapi/queryBalance", "MBQU", params);
        return res;
    }


    /**
     * 转账给分账用户
     * @param divMoneyId
     * @return
     */
    @Transactional
    public TransferMoneyInfo transferDivMoney(Long divMoneyId, String reason){
        DivMoney divMoney = divMoneyRepo.findById(divMoneyId).orElseThrow(new BusinessException("分账记录不存在"));
        if(divMoney.getUserId() == null){
            throw new BusinessException("分账的用户ID不存在");
        }

        Order order = orderRepo.findById(divMoney.getOrderId()).orElseThrow(new BusinessException("分账订单未找到"));
        if(order.getStatus() != OrderStatus.FINISH){
            throw new BusinessException("订单状态不正确");
        }

        if(divMoney.getAmount().compareTo(order.getPrice()) > 0){
            throw new BusinessException("分账金额不正确");
        }

        UserBankCard userBankCard = userBankCardRepo.findByUserId(divMoney.getUserId()).stream()
                .findAny().orElseThrow(new BusinessException("未绑定银行卡，无法分账"));


        //无论成功与否，直接标记已处理
        divMoney.setStatus(DivStatus.PROCESSED);
        divMoney.setProcessTime(LocalDateTime.now());


        if(divMoney.getTransferMoneyId() != null){
            //历史记录
            TransferMoneyInfo transferMoneyInfo = transferMoneyInfoRepo.findById(divMoney.getTransferMoneyId()).orElseThrow(new BusinessException("历史转账记录不存在"));
            //是否卡号不重复
            if(transferMoneyInfo.getAccountNo().equals(userBankCard.getBankNo())){
                throw new BusinessException("不允许对重复的卡号重新转账");
            }
        }

        //保存新的转账记录
        String tradeNo = String.valueOf(snowflakeIdWorker.nextId());
        TransferMoneyInfo.TransferMoneyInfoBuilder builder = TransferMoneyInfo.builder();
        builder.tradeNo(tradeNo).toUserId(divMoney.getUserId()).transferMethod(TransferMethod.THIRD_ACCOUNT)
                .accountType(AccountType.BANK_CARD.name())
                .accountNo(userBankCard.getBankNo())
                .accountName(userBankCard.getRealName())
                .thirdAccountId(userBankCard.getThirdAccountId())
                .amount(divMoney.getAmount())
                .payPlatform(divMoney.getPayPlatform())
                .reason(reason)
                .divMoneyId(divMoneyId);
        TransferMoneyInfo transferMoneyInfo = transferMoneyInfoRepo.save(builder.build());


        //记录转账记录ID
        divMoney.setTransferMoneyId(transferMoneyInfo.getId());

        try {
            JSONObject res = realTransfer(transferMoneyInfo.getTradeNo(), userBankCard, transferMoneyInfo.getAmount(), transferMoneyInfo.getCreatedAt());
            String orderCode = res.getString("orderCode");
            String resultFlag = res.getString("resultFlag");
            String sandSerial = res.getString("sandSerial");
            String tranTime = res.getString("tranTime");
            String tranDate = res.getString("tranDate");

            String resultStr = "默认成功";
            //0-  成功
            //1-  失败
            //2-  处理中(等银行返回明确结果)
            if("0".equals(resultFlag)){
                transferMoneyInfo.setStatus(TransferStatus.SUCCESS);
                divMoney.setStatus(DivStatus.PROCESSED);
            }else if("1".equals(resultFlag)){
                transferMoneyInfo.setStatus(TransferStatus.FAILED);
                divMoney.setStatus(DivStatus.ERROR);
                resultStr = "响应状态为失败：" + resultFlag;
            }else{
                transferMoneyInfo.setStatus(TransferStatus.PROCESSING);
                resultStr = "处理中";
            }




            transferMoneyInfo.setTransferOrderId(orderCode);
            transferMoneyInfo.setTransactionId(sandSerial);
            transferMoneyInfo.setTransferDate(tranTime);
            transferMoneyInfo.setResult(resultStr);

            divMoney.setTransferResult(resultStr);

        }catch(Exception e){
            log.error("转账失败，分账ID:" + divMoneyId, e);
            transferMoneyInfo.setStatus(TransferStatus.FAILED);
            transferMoneyInfo.setResult(e.getMessage());
            divMoney.setStatus(DivStatus.ERROR);
            divMoney.setTransferResult(e.getMessage());
        }

        transferMoneyInfoRepo.save(transferMoneyInfo);
        divMoneyRepo.save(divMoney);

        return transferMoneyInfo;
    }


    /**
     * 检查支付结果
     * @param orderNo
     * @return
     */
    public PayResult checkPayResult(String orderNo){
        PayResult.PayResultBuilder builder = PayResult.builder();
        PaymentInfo paymentInfo = paymentInfoRepo.findByOrderNo(orderNo).orElseThrow(new BusinessException("支付信息不存在"));
        //根据支付渠道识别
        JSONObject res;
        if("quickpay".equals(paymentInfo.getPayChannel())){
            //res = this.quickPayOrderQuery(orderNo);
            res = this.quickPayOrderQueryNew(orderNo);
        }else if("wallet".equals(paymentInfo.getPayChannel())){
            res = this.accountPayOrderQuery(orderNo);
        }else{
            res = this.h5PayOrderQuery(orderNo);
        }

        //设置结果
        String oriOrderCode = res.getString("oriOrderCode");
        String totalAmount = res.getString("totalAmount");
        String orderStatus = res.getString("orderStatus");
        String payTime = res.getString("payTime");
        String orderMsg= res.getString("orderMsg");
        String accNo = res.getString("accNo");
        String accLogonNo = res.getString("accLogonNo");

        BigDecimal totalAmountObj = new BigDecimal(totalAmount).divide(new BigDecimal("100")).setScale(2);
        PayStatus payStatus = PayStatus.UNPAID;
        if("00".equals(orderStatus)){
            payStatus = PayStatus.HAVE_PAID;
        }else if("01".equals(orderStatus)){
            payStatus = PayStatus.PENDING;
        }else if("02".equals(orderStatus)){
            payStatus = PayStatus.FAILED_PAID;
        }else if("04".equals(orderStatus)){
            payStatus = PayStatus.REFUNDED;
        }else if("05".equals(orderStatus)){
            payStatus = PayStatus.REFUNDING;
        }

        LocalDateTime payTimeObj = null;
        if(StringUtils.isNotEmpty(payTime)){
            payTimeObj = DateUtil.parse(payTime).toLocalDateTime();
        }

        builder.orderNo(orderNo)
                .totalAmount(totalAmountObj)
                .status(payStatus)
                .transactionNo(oriOrderCode)
                .payTime(payTimeObj)
                .orderMsg(orderMsg)
                .accNo(accNo)
                .accLogonNo(accLogonNo);
        return builder.build();
    }

    /**
     * 检查转账结果
     * @param transferMoneyId
     */
    @Transactional(rollbackOn = Exception.class)
    public TransferMoneyInfo checkTransferResult(Long transferMoneyId) {

        TransferMoneyInfo transferMoneyInfo = transferMoneyInfoRepo.findById(transferMoneyId).orElseThrow(new BusinessException("转账记录不存在"));
        JSONObject res = realTransferQuery(transferMoneyInfo.getTradeNo(), transferMoneyInfo.getCreatedAt());
        String orderCode = res.getString("orderCode");
        String resultFlag = res.getString("resultFlag");
        String sandSerial = res.getString("sandSerial");
        String tranTime = res.getString("tranTime");
        String tranDate = res.getString("tranDate");

        String resultStr = "查询结果成功";
        //0-  成功
        //1-  失败
        //2-  处理中(等银行返回明确结果)
        if("0".equals(resultFlag)){
            transferMoneyInfo.setStatus(TransferStatus.SUCCESS);
        }else if("1".equals(resultFlag)){
            transferMoneyInfo.setStatus(TransferStatus.FAILED);
            resultStr = "响应状态为失败：" + resultFlag;
        }else{
            transferMoneyInfo.setStatus(TransferStatus.PROCESSING);
            resultStr = "处理中:" + resultFlag;
        }

        transferMoneyInfo.setTransferOrderId(orderCode);
        transferMoneyInfo.setTransactionId(sandSerial);
        transferMoneyInfo.setTransferDate(tranTime);
        transferMoneyInfo.setResult(resultStr);
        transferMoneyInfoRepo.save(transferMoneyInfo);

        return transferMoneyInfo;


    }




}
