package com.izouma.nineth.service;

import cn.hutool.core.date.DateUtil;
import cn.hutool.core.date.LocalDateTimeUtil;
import cn.hutool.core.util.URLUtil;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.anji.captcha.util.StringUtils;
import com.izouma.nineth.config.GeneralProperties;
import com.izouma.nineth.config.SumpayProperties;
import com.izouma.nineth.domain.*;
import com.izouma.nineth.dto.PageQuery;
import com.izouma.nineth.dto.sumpay.*;
import com.izouma.nineth.enums.*;
import com.izouma.nineth.exception.BusinessException;
import com.izouma.nineth.repo.*;
import com.izouma.nineth.service.pay.PayHelper;
import com.izouma.nineth.service.pay.UniformPayConstants;
import com.izouma.nineth.utils.IPUtils;
import com.izouma.nineth.utils.SnowflakeIdWorker;
import com.izouma.nineth.utils.UrlUtils;
import fosun.sumpay.merchant.integration.core.context.FileContext;
import fosun.sumpay.merchant.integration.core.request.MerchantBaseRequest;
import fosun.sumpay.merchant.integration.core.request.Request;
import fosun.sumpay.merchant.integration.core.request.outer.*;
import fosun.sumpay.merchant.integration.core.request.outer.crowd.source.CdsRegisterRequest;
import fosun.sumpay.merchant.integration.core.request.outer.perfectbill.RegisterRequest;
import fosun.sumpay.merchant.integration.core.service.SignService;
import fosun.sumpay.merchant.integration.core.service.SignServiceImpl;
import fosun.sumpay.merchant.integration.core.service.SumpayService;
import fosun.sumpay.merchant.integration.core.util.ParamUtil;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.beanutils.PropertyUtils;
import org.apache.commons.io.FileUtils;
import org.apache.commons.io.FilenameUtils;
import org.apache.commons.lang3.ClassUtils;
import org.springframework.stereotype.Service;

import javax.transaction.Transactional;
import java.beans.PropertyDescriptor;
import java.beans.Transient;
import java.io.InputStream;
import java.lang.reflect.InvocationTargetException;
import java.math.BigDecimal;
import java.net.MalformedURLException;
import java.net.URL;
import java.text.SimpleDateFormat;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.*;

@Service
@AllArgsConstructor
@Slf4j
public class SumpayMerchantService {

    private static final  SignService SIGN_SERVICE = new SignServiceImpl();

    private GeneralProperties generalProperties;

    private SumpayProperties sumpayProperties;

    private SumpayService sumpayService;

    private OrderRepo orderRepo;

    private UserRepo userRepo;

    private IdentityAuthRepo identityAuthRepo;

    private SnowflakeIdWorker snowflakeIdWorker;

    private PayHelper payHelper;

    private UserAddressRepo userAddressRepo;

    private UserFundAccountRepo userFundAccountRepo;

    private DivMoneyRepo divMoneyRepo;

    private TransferMoneyInfoRepo transferMoneyInfoRepo;

    /**
     * 执行交易
     * @param req
     * @return
     */
    private Map<String,String>  executeTrade(MerchantBaseRequest req){
        String domain = generalProperties.getHost().replaceAll("^\\s*https?://", "");
        //设置默认参数
        String terminal_type = "wap";//web：PC方式;wap：手机WAP; api：通过api接口调用；sdk:调用我方sdk模式
        req.setTerminal_type(terminal_type);
        req.setVersion("1.0");
        req.setTimestamp(new SimpleDateFormat("yyyyMMddHHmmss").format(new Date()));
        req.setApp_id(sumpayProperties.getMerId());

        // 建立请求
        Request tradeReq = new Request();
        //提取fileParams
        List<FileContext> fileList = new ArrayList<>();
        PropertyDescriptor[] descriptors = PropertyUtils.getPropertyDescriptors(req);
        for(PropertyDescriptor desc : descriptors){
            if(FileContext.class.isAssignableFrom(desc.getPropertyType())){
                try {
                    fileList.add((FileContext) desc.getReadMethod().invoke(req));
                    desc.getWriteMethod().invoke(req, (FileContext)null);
                } catch (Exception e) {
                    throw new RuntimeException("写入文件参数失败:" + desc.getName(), e);
                }
            }
        }

        if(fileList.size() > 0){
            tradeReq.setFileParams(fileList);
            tradeReq.setUserMultipart(true);
        }


        tradeReq.setCharset("UTF-8");// 取jsp的请求编码
        tradeReq.setContent(JSON.toJSONString(req)); // 业务参数的json字段
        tradeReq.setPassword(sumpayProperties.getPrivateKeyPwd());
        tradeReq.setPrivateKeyPath(sumpayProperties.getPrivateKeyPath());
        tradeReq.setPublicKeyPath(sumpayProperties.getPublicKeyPath());
        tradeReq.setUrl(sumpayProperties.getGateWay());
        tradeReq.setDomain(domain);
        tradeReq.setAesEncodedWords(req.getAesEncodedWords());
        tradeReq.setBase64EncodedWords(req.getBase64EncodedWords());
        tradeReq.setCharsetChangeWords(req.getCharsetChangeWords());
        tradeReq.setOld(true);

        log.info("请求商盟接口发送：" + JSON.toJSONString(req));
        Map<String, String> res = sumpayService.execute(tradeReq);
        log.info("请求商盟接口响应：" + res);
        //错误检查
        String respCode = res.get("resp_code");
        String respMsg = res.get("resp_msg");
        if(!"000000".equals(respCode)){
            throw new BusinessException(respMsg + "("+respCode+")");
        }

        return res;
    }


    /**
     * 校验签名
     * @param bodyJson
     * @return
     */
    public void verifySign(JSONObject bodyJson){
        String returnSign = bodyJson.getString("sign");
        String returnSignType = bodyJson.getString("sign_type");
        bodyJson.remove("sign");
        bodyJson.remove("sign_type");
        if (null != returnSign && null != returnSignType) {
            Map<String,String> linkMap = bodyJson.toJavaObject(Map.class);
            boolean verifyResult = SIGN_SERVICE.verifyMsgOld(returnSign, ParamUtil.createLinkString(linkMap), sumpayProperties.getPublicKeyPath());

            if (!verifyResult) {
                throw new BusinessException("收到的响应验签失败");
            }
        } else {
            throw new BusinessException("响应参数不合法");
        }

    }


    /**
     * 检查快捷支付卡信息
     * @param cardNo
     * @param orderAmount
     * @return
     */
    public Map<String,String> checkCard(String cardNo, BigDecimal orderAmount){
        String orderTime = DateTimeFormatter.ofPattern("yyyyMMddHHmmss").format(LocalDateTime.now());
        CheckCardNoRequest req = new CheckCardNoRequest();
        req.setService("fosun.sumpay.api.quickpay.check.card.no");
        req.setVersion("1.0");
        req.setTimestamp(orderTime);
        req.setMer_no(sumpayProperties.getMerId());
        req.setCard_no(cardNo);
        req.setBusiness_code("03");//03-快捷

        if(orderAmount != null){
            req.setOrder_amount(orderAmount.toPlainString());
        }

        Map<String,String> res = executeTrade(req);
        return res;
    }


    /**
     * 快捷支付申请
     * @return
     */
    public JSONObject quickpayApply(PaymentInfo paymentInfo, List<DivMoney> divMoneyList,
                                            SumBankCardDTO sumBankCardDTO){
        User user = userRepo.findById(paymentInfo.getUserId()).orElseThrow(new BusinessException("用户不存在"));
        IdentityAuth identityAuth = identityAuthRepo.findFirstByUserIdAndStatusAndDelFalseOrderByCreatedAtDesc(user.getId(),
                AuthStatus.SUCCESS)
                .orElseThrow(new BusinessException("用户未通过实名认证"));

        String orderTime = DateTimeFormatter.ofPattern("yyyyMMddHHmmss").format(LocalDateTime.now());

        NewQuickPayOrderApplyRequest req = new NewQuickPayOrderApplyRequest();
        req.setService("fosun.sumpay.api.quickpay.new.order.apply");
        req.setMer_no(sumpayProperties.getMerId());
        req.setTrade_code("T0001");//担保交易：T0001,即时交易：T0002
        req.setUser_id(user.getId().toString());
        req.setOrder_no(paymentInfo.getOrderNo());
        req.setOrder_time(orderTime);
        req.setOrder_amount(paymentInfo.getPayAmt().toPlainString());
        req.setNeed_notify("1");//0-否，1-是
        req.setNotify_url(paymentInfo.getNotifyUrl());
        req.setCurrency("CNY");
        req.setGoods_name(paymentInfo.getGoodsTitle());
        req.setGoods_type("2");//1：实物商品；2：虚拟商品

        if(StringUtils.isBlank(sumBankCardDTO.getBind_card_id())){
            //新卡绑定
            req.setCard_type(sumBankCardDTO.getCard_type());
            if("1".equals(sumBankCardDTO.getNeed_cvv())){
                req.setCvv(sumBankCardDTO.getCvv());
                req.setValid_year(sumBankCardDTO.getValidYear());
                req.setValid_month(sumBankCardDTO.getValidMonth());
            }
            req.setRealname(identityAuth.getRealName());
            req.setId_type("1");//1-身份证
            req.setId_no(identityAuth.getIdNo());
            req.setMobile_no(sumBankCardDTO.getMobileNo());

        }else{
            req.setBind_card_id(sumBankCardDTO.getBind_card_id());
        }

        req.setUser_ip_addr(IPUtils.getIpAddr());
        req.setFree_mark("0");//0-普通模式 1-仅支付免短信模式

        String returnUrl = payHelper.resolveReturnUrl(paymentInfo);
        req.setReturn_url(returnUrl);

        //分账信息
        JSONObject shareBenefit = new JSONObject();
        shareBenefit.put("share_type", "1");//1.固定金额分润，默认;2.比例分润
        shareBenefit.put("prior", "1");//.固定金额优先，默认;2.正常模式
        JSONArray benefit_bean_list = new JSONArray();
        divMoneyList.forEach(divMoney -> {
            JSONObject item  = new JSONObject();
            //item.put("mer_no", "");//商户号
            item.put("account_type", "1");//2:商户 1:个人 不传时默认为2商户
            item.put("user_id", user.getId().toString());//account_type传1时必填
            item.put("share_type", "1");//1.固定金额分润，固定值
            item.put("prior", "1");//1.固定金额优先，固定值
            item.put("amount", divMoney.getAmount());
            benefit_bean_list.add(item);
        });
        shareBenefit.put("benefit_bean_list", benefit_bean_list);

        if(benefit_bean_list.size() > 0){
            //附加分账
            req.setShare_benefit_flag("1");
            req.setShare_benefit_exp(shareBenefit.toJSONString());
        }


        // 建立请求
        Map<String,String> res = executeTrade(req);
        String response = res.get("sumpay_order_apply_response");
        return JSONObject.parseObject(response);
    }


    /**
     * 快捷支付校验
     * @return
     */
    public JSONObject  quickpayVerifyCode(String orderNo, String verifyCode){

        NewQuickPayVerifyCodeRequest req = new NewQuickPayVerifyCodeRequest();
        req.setMer_no(sumpayProperties.getMerId());
        //申请支付时返回 result_type为1时必填，为外部签约同步回调返回
        req.setOrder_no(orderNo);
        req.setVerify_code(verifyCode);//申请支付时返回 result_type为0时必填
        req.setService("fosun.sumpay.api.quickpay.submit.pay");

        // 建立请求
        Map<String,String> res = executeTrade(req);
        String response = res.get("sumpay_order_apply_response");
        return JSONObject.parseObject(response);
    }


    /**
     * 扫码支付
     * @param paymentInfo
     * @param divMoneyList
     * @return
     */
    public JSONObject  qrCodeTrade(PaymentInfo paymentInfo, List<DivMoney> divMoneyList){
        User user = userRepo.findById(paymentInfo.getUserId()).orElseThrow(new BusinessException("用户不存在"));

        String orderTime = DateTimeFormatter.ofPattern("yyyyMMddHHmmss").format(LocalDateTime.now());

        QrCodePayRequest req = new QrCodePayRequest();

        req.setMer_no(sumpayProperties.getMerId());
        //req.setSub_mer_no("");
        //10：支付宝
        //09：微信
        //22：QQ
        //34：银联分期
        String businessCode = "09";//微信
        if(paymentInfo.getPayMethod() == PayMethod.ALIPAY){
            businessCode = "10";//支付宝
        }

        req.setBusiness_code(businessCode);
        req.setNeed_notify("1");
        if("1".equals(req.getNeed_notify())) {
            req.setNotify_url(paymentInfo.getNotifyUrl());
        }

        req.setUser_id(user.getId().toString());
        req.setOrder_no(paymentInfo.getOrderNo());
        req.setOrder_time(orderTime);
        req.setCurrency("CNY");
        req.setOrder_amount(paymentInfo.getPayAmt().toPlainString());
        req.setGoods_name(paymentInfo.getGoodsTitle());
        req.setGoods_num("1");
        req.setGoods_type("2");//1：实物商品 2：虚拟商品
        //req.setAttach("");
        if("09".equals(req.getBusiness_code())) {
            req.setService("fosun.sumpay.api.pay.new.qrcode.trade.apply");
        }else {
            req.setService("fosun.sumpay.api.pay.qrcode.trade.apply");
        }

        //分账信息
        JSONObject shareBenefit = new JSONObject();
        shareBenefit.put("share_type", "1");//1.固定金额分润，默认;2.比例分润
        shareBenefit.put("prior", "1");//.固定金额优先，默认;2.正常模式
        JSONArray benefit_bean_list = new JSONArray();
        if(divMoneyList != null){
            divMoneyList.forEach(divMoney -> {
                if(divMoney.getUserId() == null){
                    return;
                }

                //查找用户资金账户
                UserFundAccount account = userFundAccountRepo.findByUserIdAndAccountType(divMoney.getUserId(), AccountType.SUMPAY_USER)
                        .orElseThrow(new BusinessException("转让用户未注册资金账户，无法分润"));

                JSONObject item  = new JSONObject();
                //item.put("mer_no", "");//商户号
                item.put("account_type", "1");//2:商户 1:个人 不传时默认为2商户
                item.put("user_id", account.getThirdUserId());//account_type传1时必填
                item.put("share_type", "1");//1.固定金额分润，固定值
                item.put("prior", "1");//1.固定金额优先，固定值
                item.put("amount", divMoney.getAmount());
                benefit_bean_list.add(item);
            });
        }

        shareBenefit.put("benefit_bean_list", benefit_bean_list);

        //附加分账
        req.setShare_benefit_flag("1");
        req.setShare_benefit_exp(shareBenefit.toJSONString());

        Map<String,String> res = executeTrade(req);

        String response = res.get("sumpay_qrcode_pay_response");
        return JSONObject.parseObject(response);


    }


    /**
     * 退款
     * @param orderNo
     * @return
     */
    public JSONObject  tradeRefund(String orderNo, BigDecimal refundAmount, String refundReason){

        String refundNo = String.valueOf(snowflakeIdWorker.nextId());
        String notifyUrl = payHelper.resolveRefundNotifyUrl(orderNo);

        RefundRequest req = new RefundRequest();
        req.setMer_no(sumpayProperties.getMerId());
        req.setOrder_no(orderNo);
        req.setRefund_no(refundNo);
        req.setRefund_amt(refundAmount.toPlainString());
        req.setNotify_url(notifyUrl);
        req.setRemark(refundReason);
        req.setService("fosun.sumpay.api.trade.refund");

        Map<String,String> res = executeTrade(req);
        String refundResponse = res.get("sumpay_refund_response");
        return JSONObject.parseObject(refundResponse);

    }


    private FileContext generateFileContext(String url, String fieldName){
        if(!url.startsWith("http")){
            //url = generalProperties.getHost() + url;
            url = "http://localhost:8080" + url;
        }
        String originalName = FilenameUtils.getName(url);
        try {
            URL urlObj = new URL(url);
            InputStream inputStream = urlObj.openStream();
            byte[] data = inputStream.readAllBytes();
            inputStream.close();

            FileContext fileContext = new FileContext();
            fileContext.setOriginalFilename(originalName);
            fileContext.setFieldName(fieldName);
            fileContext.setFileBytes(data);

            return fileContext;
        } catch (Exception e) {
            throw new RuntimeException("读取证件资料失败:" + url , e);
        }

    }


    /**
     * 注册会员
     * @return
     */
    public Map<String,String> register(IdentityAuth identityAuth){
        if(identityAuth.getIdStartDate() == null || identityAuth.getIdEndDate() == null){
            throw new BusinessException("缺失身份证有效期信息");
        }

        Long userId = identityAuth.getUserId();
        PersonalRegister req = new PersonalRegister();
        req.setPartner_id(sumpayProperties.getMerId());
        req.setRealname(identityAuth.getRealName());
        req.setId_type("1");//1 身份证
        req.setId_no(identityAuth.getIdNo());
        req.setMobile_no(identityAuth.getPhone());
        String idFrontUrl = identityAuth.getIdFront();
        String idBackUrl = identityAuth.getIdBack();

        req.setId_card_front(generateFileContext(idFrontUrl, "id_card_front"));
        req.setId_card_back(generateFileContext(idBackUrl, "id_card_back"));
        String idStartDate = DateTimeFormatter.ofPattern("yyyyMMdd").format(identityAuth.getIdStartDate());
        String idEndDate = DateTimeFormatter.ofPattern("yyyyMMdd").format(identityAuth.getIdEndDate());
        req.setId_start_date(idStartDate);
        req.setId_end_date(idEndDate);
        req.setLogin_password(sumpayProperties.getMemberLoginPassword());
        req.setPay_password(sumpayProperties.getMemberPayPassword());
        req.setCareer("其他");
        req.setAddress("广州省广州市番禺区番禺大道东537号");

        List<UserAddress> userAddressList = userAddressRepo.findByUserIdAndDelFalse(userId);
        if(userAddressList.size() > 0){
            //使用用户地址
            UserAddress userAddress = userAddressList.get(0);
            if(userAddress != null){
                String  fullAddress = userAddress.getProvinceName() + userAddress.getCityName()
                        + userAddress.getDistrictName() + userAddress.getAddress();
                req.setAddress(fullAddress);
            }
        }

        req.setService("cn.sumpay.scene.c2c.user.register");
        Map<String,String> res = executeTrade(req);

        return res;
    }

    /**
     * 注册
     * @param userId
     * @return
     */
    public Map<String,String> register(Long userId){
        IdentityAuth identityAuth = identityAuthRepo.findFirstByUserIdAndStatusAndDelFalseOrderByCreatedAtDesc(userId, AuthStatus.SUCCESS)
                .orElseThrow(new BusinessException("用户未通过实名认证"));
        Map<String,String> res = register(identityAuth);
        return res;
    }

    /**
     * 用户注册结果查询
     * @param userId
     * @return
     */
    public Map<String,String>  registerQuery(Long userId){
        IdentityAuth identityAuth = identityAuthRepo.findFirstByUserIdAndStatusAndDelFalseOrderByCreatedAtDesc(userId, AuthStatus.SUCCESS)
                .orElseThrow(new BusinessException("用户未通过实名认证"));

        RegisterQuery req = new RegisterQuery();
        req.setPartner_id(sumpayProperties.getMerId());
        req.setId_type("1");//1 身份证
        req.setId_no(identityAuth.getIdNo());
        req.setService("cn.sumpay.scene.c2c.user.query.register.info");
        Map<String,String> res = executeTrade(req);
        return res;
    }


    /**
     * 用户信息查询
     * @return
     */
    public Map<String,String>  userQuery(PageQuery pageQuery){
        int page = pageQuery.getPage();
        if(page <=0 ){
            page = 1;
        }

        UserQuery req = new UserQuery();
        req.setService("cn.sumpay.scene.c2c.user.query.user.status");
        req.setPartner_id(sumpayProperties.getMerId());
        req.setPage_index(String.valueOf(page));

        String user_id = Objects.toString(pageQuery.getQuery().get("user_id"),"");
        String user_status = Objects.toString(pageQuery.getQuery().get("user_status"),"");
        String start_time = Objects.toString(pageQuery.getQuery().get("start_time"),"");
        String end_time = Objects.toString(pageQuery.getQuery().get("end_time"),"");

        req.setUser_id(user_id);
        req.setUser_status(user_status);
        req.setStart_time(start_time);
        req.setEnd_time(end_time);

        Map<String,String> result = executeTrade(req);

        return result;

    }


    /**
     * 会员信息修改
     * @param userId
     * @return
     */
    public Map<String,String> userModify(Long userId){
        IdentityAuth identityAuth = identityAuthRepo.findFirstByUserIdAndStatusAndDelFalseOrderByCreatedAtDesc(userId, AuthStatus.SUCCESS)
                .orElseThrow(new BusinessException("用户未通过实名认证"));

        if(identityAuth.getIdStartDate() == null || identityAuth.getIdEndDate() == null){
            throw new BusinessException("缺失身份证有效期信息");
        }


        //查询资金账户信息
        UserFundAccount account  = userFundAccountRepo.findByUserIdAndAccountType(userId, AccountType.SUMPAY_USER)
                .orElseThrow(new BusinessException("资金账户不存在"));



        UserModify req = new UserModify();
        req.setPartner_id(sumpayProperties.getMerId());
        req.setUser_id(account.getThirdUserId());
        String idFrontUrl = identityAuth.getIdFront();
        String idBackUrl = identityAuth.getIdBack();

        req.setId_card_front(generateFileContext(idFrontUrl, "id_card_front"));
        req.setId_card_back(generateFileContext(idBackUrl, "id_card_back"));
        String idStartDate = DateTimeFormatter.ofPattern("yyyyMMdd").format(identityAuth.getIdStartDate());
        String idEndDate = DateTimeFormatter.ofPattern("yyyyMMdd").format(identityAuth.getIdEndDate());
        req.setId_start_date(idStartDate);
        req.setId_end_date(idEndDate);
        req.setService("cn.sumpay.scene.c2c.user.modify");


        List<UserAddress> userAddressList = userAddressRepo.findByUserIdAndDelFalse(userId);
        if(userAddressList.size() > 0){
            //使用用户地址
            UserAddress userAddress = userAddressList.get(0);
            if(userAddress != null){
                req.setCareer("其他");
                String  fullAddress = userAddress.getProvinceName() + userAddress.getCityName()
                        + userAddress.getDistrictName() + userAddress.getAddress();
                req.setAddress(fullAddress);
            }
        }



        Map<String,String> res = executeTrade(req);
        return res;
    }

    /**
     * 用户余额查询
     * @param userId
     * @return
     */
    public Map<String,String>  balanceQuery(Long userId){
        //查询资金账户信息
        UserFundAccount account  = userFundAccountRepo.findByUserIdAndAccountType(userId, AccountType.SUMPAY_USER)
                .orElseThrow(new BusinessException("资金账户不存在"));

        BalanceQuery req = new BalanceQuery();
        req.setPartner_id(sumpayProperties.getMerId());
        req.setUser_id(account.getThirdUserId());
        req.setService("cn.sumpay.scene.c2c.user.query.balance");
        Map<String,String> res = executeTrade(req);
        return res;
    }


    /**
     * 绑卡
     * @param userId
     * @param cardNo
     * @param mobileNo
     * @return
     */
    public Map<String,String> bindCard(Long userId, String cardNo, String mobileNo){
        IdentityAuth identityAuth = identityAuthRepo.findFirstByUserIdAndStatusAndDelFalseOrderByCreatedAtDesc(userId, AuthStatus.SUCCESS)
                .orElseThrow(new BusinessException("用户未通过实名认证"));
        //查询资金账户信息
        UserFundAccount account  = userFundAccountRepo.findByUserIdAndAccountType(userId, AccountType.SUMPAY_USER)
                .orElseThrow(new BusinessException("资金账户不存在"));

        BindCard req = new BindCard();
        req.setPartner_id(sumpayProperties.getMerId());
        req.setUser_id(account.getThirdUserId());
        req.setCard_no(cardNo);
        req.setMobile_no(mobileNo);
        req.setId_type("1");//身份证
        req.setId_no(identityAuth.getIdNo());
        req.setRealname(identityAuth.getRealName());
        req.setService("cn.sumpay.scene.c2c.user.bind.card");

        Map<String,String> res = executeTrade(req);
        return res;
    }


    /**
     * 提现
     * @param userId
     * @param tradeNo
     * @param amount
     * @return
     */
    public JSONObject withdraw(Long userId, String tradeNo, BigDecimal amount){
        //查询资金账户信息
        UserFundAccount account  = userFundAccountRepo.findByUserIdAndAccountType(userId, AccountType.SUMPAY_USER)
                .orElseThrow(new BusinessException("资金账户不存在"));
        Withdraw req = new Withdraw();
        req.setPartner_id(sumpayProperties.getMerId());
        req.setUser_id(account.getThirdUserId());
        req.setBind_card_id(account.getThirdBankId());
        req.setPay_password(sumpayProperties.getMemberPayPassword());
        req.setNeed_notify("0");//不需要通知
//        req.setNeed_notify("1");//需要通知
//        String notifyUrl = payHelper.resolveTransferNotifyUrl(tradeNo);
//        req.setNotify_url(notifyUrl);
        req.setOrder_no(tradeNo);
        req.setOrder_amount(amount.toPlainString());
        req.setOrder_time(new SimpleDateFormat("yyyyMMddHHmmss").format(new Date()));
        req.setService("cn.sumpay.scene.c2c.trade.withdraw");

        Map<String,String> res = executeTrade(req);
        String response = res.get("sumpay_withdraw_response");
        return JSONObject.parseObject(response);
    }


    /**
     * 转账交易查询
     *
     */
    public JSONObject withdrawQuery(String orderNo){

        WithdrawQuery req = new WithdrawQuery();
        req.setPartner_id(sumpayProperties.getMerId());
        req.setOrder_no(orderNo);
        req.setService("cn.sumpay.scene.c2c.trade.query.order.status");

        Map<String,String> res = executeTrade(req);
        String response = res.get("sumpay_order_search_merchant_response");
        return JSONObject.parseObject(response);
    }


    /**
     * 提现分账给会员
     * @param divMoneyId
     * @return
     */
    @Transactional
    public TransferMoneyInfo withdrawDivMoney(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("分账金额不正确");
        }


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


        //查询资金账户信息
        UserFundAccount account  = userFundAccountRepo.findByUserIdAndAccountType(divMoney.getUserId(), AccountType.SUMPAY_USER)
                .orElseThrow(new BusinessException("资金账户不存在"));

        if(divMoney.getTransferMoneyId() != null){
            //历史记录
            TransferMoneyInfo transferMoneyInfo = transferMoneyInfoRepo.findById(divMoney.getTransferMoneyId()).orElseThrow(new BusinessException("历史转账记录不存在"));
            //是否账户不重复
            if(transferMoneyInfo.getAccountNo().equals(account.getAccountNo())){
                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(account.getAccountType().name())
                .accountNo(account.getAccountNo())
                .accountName(account.getAccountName())
                .thirdAccountId(account.getThirdUserId())
                .amount(divMoney.getAmount())
                .payPlatform(divMoney.getPayPlatform())
                .reason(reason)
                .divMoneyId(divMoneyId);
        TransferMoneyInfo transferMoneyInfo = transferMoneyInfoRepo.save(builder.build());


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

        try {
            //提现操作
            JSONObject withdrawResponse = withdraw(divMoney.getUserId(), transferMoneyInfo.getTradeNo(), divMoney.getAmount());
            String status = withdrawResponse.getString("status");
            String error_code = withdrawResponse.getString("error_code");
            String error_msg = withdrawResponse.getString("error_msg");
            //支付方交易流水
            String withdrawTradeNo = withdrawResponse.getString("trade_no");
            String orderNo = withdrawResponse.getString("order_no");
            //交易完成时间
            String finish_time = withdrawResponse.getString("finish_time");
            transferMoneyInfo.setTransferOrderId(orderNo);
            transferMoneyInfo.setTransactionId(withdrawTradeNo);
            transferMoneyInfo.setTransferDate(finish_time);

            String resultStr = "默认成功";

            //0失败 1 成功 2 处理中
            if("1".equals(status)){
                resultStr = "交易成功";
                transferMoneyInfo.setStatus(TransferStatus.SUCCESS);
            }else if("2".equals(status)){
                resultStr = "处理中:" + status;
                transferMoneyInfo.setStatus(TransferStatus.PROCESSING);
            }else{
                if(StringUtils.isNotEmpty(error_msg) || StringUtils.isNotEmpty(error_code)){
                    resultStr = error_msg + "("+error_code+")";
                }else{
                    resultStr = "交易失败:" + status;
                }
                transferMoneyInfo.setStatus(TransferStatus.FAILED);
                divMoney.setStatus(DivStatus.ERROR);
            }

            transferMoneyInfo.setResult(resultStr);
            divMoney.setTransferResult(resultStr);

            transferMoneyInfoRepo.save(transferMoneyInfo);

        }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 transferMoneyId
     */
    @Transactional
    public TransferMoneyInfo checkTransferResult(Long transferMoneyId){

        TransferMoneyInfo transferMoneyInfo = transferMoneyInfoRepo.findById(transferMoneyId).orElseThrow(new BusinessException("转账记录不存在"));
        JSONObject withdrawResponse = withdrawQuery(transferMoneyInfo.getTradeNo());
        String status = withdrawResponse.getString("status");
        String error_code = withdrawResponse.getString("error_code");
        String error_msg = withdrawResponse.getString("error_msg");
        //支付方交易流水
        String withdrawTradeNo = withdrawResponse.getString("trade_no");
        String orderNo = withdrawResponse.getString("order_no");
        //交易完成时间
        String finish_time = withdrawResponse.getString("finish_time");
        transferMoneyInfo.setTransferOrderId(orderNo);
        transferMoneyInfo.setTransactionId(withdrawTradeNo);
        transferMoneyInfo.setTransferDate(finish_time);

        String resultStr = "默认成功";

        //0失败 1 成功 2 处理中
        if("1".equals(status)){
            resultStr = "交易成功";
            transferMoneyInfo.setStatus(TransferStatus.SUCCESS);
        }else if("2".equals(status)){
            resultStr = "处理中";
            transferMoneyInfo.setStatus(TransferStatus.PROCESSING);
        }else{
            if(StringUtils.isNotEmpty(error_msg) || StringUtils.isNotEmpty(error_code)){
                resultStr = error_msg + "("+error_code+")";
            }else{
                resultStr = "交易失败";
            }
            transferMoneyInfo.setStatus(TransferStatus.FAILED);
        }

        transferMoneyInfo.setResult(resultStr);
        transferMoneyInfoRepo.save(transferMoneyInfo);

        return transferMoneyInfo;


    }


}
