package com.iformall.service.impl;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import com.iformall.common.ErrorCode;
import com.iformall.common.IdWorker;
import com.iformall.common.ResultData;
import com.iformall.domain.dto.WxSharingOrderDto;
import com.iformall.domain.po.*;
import com.iformall.domain.vo.WxProfitSharingOrderDetailsVo;
import com.iformall.domain.vo.WxProfitSharingOrderQueryVo;
import com.iformall.domain.vo.WxProfitSharingOrderVo;
import com.iformall.enums.*;
import com.iformall.exception.MallinkException;
import com.iformall.mapper.*;
import com.iformall.pay.*;
import com.iformall.service.WxProfitSharingOrderService;
import com.iformall.utils.BeanUtils;
import com.iformall.utils.DateUtils;
import com.iformall.utils.Utility;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Isolation;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.util.*;


@Service
public class WxProfitSharingOrderServiceImpl implements WxProfitSharingOrderService {
    private final Logger logger = LoggerFactory.getLogger(this.getClass());
	
	@Autowired
    WxProfitSharingOrderMapper wxProfitSharingOrderMapper;

    @Autowired
    WxAppinfoMapper wxAppinfoMapper;

    @Autowired
    WxPayAccountMapper wxPayAccountMapper;

    @Autowired
    WxOrderMapper wxOrderMapper;

    @Autowired
    WxProfitSharingReceiverMapper wxProfitSharingReceiverMapper;

    @Autowired
    WxProfitSharingResultMapper wxProfitSharingResultMapper;

    @Autowired
    WxCUserMapper wxCUserMapper;

    @Autowired
    WxPayOrderMapper wxPayOrderMapper;

    @Autowired
    WxCardSpendMapper wxCardSpendMapper;

    final JSONObject errorMap = JSON.parseObject("{" +
            "\"SYSTEMERROR\":{\"detail\":\"接口返回错误\",\"reason\":\"系统超时\",\"resolution\":\"系统异常，请用相同参数重新调用\"}," +
            "\"AMOUNT_OVERDUE\":{\"detail\":\"分账金额超限\",\"reason\":\"分账金额大于可分金额 或大于分账最大比例 \",\"resolution\":\"请调整分账金额\"}," +
            "\"RECEIVER_INVALID\":{\"detail\":\"分账接收方非法 \",\"reason\":\"未配置分账接收方\",\"resolution\":\"分账接收方在分账之前需要进行添加\"}," +
            "\"INVALID_TRANSACTIONID\":{\"detail\":\"无效的微信支付订单号\",\"reason\":\"请求参数未按指引进行填写\",\"resolution\":\"检查原交易单号是否存在\"}," +
            "\"PARAM_ERROR\":{\"detail\":\"参数错误\\t\",\"reason\":\"请求参数未按指引进行填写\",\"resolution\":\"请求参数错误，请重新检查再调用分账接口\"}," +
            "\"INVALID_REQUEST\":{\"detail\":\"请求不合法\",\"reason\":\"参数中APPID或MCHID不存在等 \",\"resolution\":\"请重新检查再调用分账接口\"}," +
            "\"OPENID_MISMATCH\":{\"detail\":\"Openid错误\",\"reason\":\"Openid与Appid不匹配\",\"resolution\":\"请检查openid是否正确\"}," +
            "\"FREQUENCY_LIMITED\":{\"detail\":\"频率限制\",\"reason\":\"请求过多被频率限制\",\"resolution\":\"该被请求未受理，请降低频率后原单重试，请勿更换商户分账单号\"}," +
            "\"ORDER_NOT_READY\":{\"detail\":\"订单处理中\",\"reason\":\"订单处理中暂时无法分账\",\"resolution\":\"订单处理中暂时无法分账，请稍后再试\"}," +
            "\"NOAUTH \":{\"detail\":\"无分账权限\",\"reason\":\"未开通分账权限\",\"resolution\":\"请先开通分账权限\"}," +
            "\"NOT_SHARE_ORDER\":{\"detail\":\"非分账订单\\t\",\"reason\":\"不是分账订单，无法分账\",\"resolution\":\"下单时请用合适的参数\"}}");

    final JSONObject errorMapQuery = JSON.parseObject("{" +
            "\"SYSTEMERROR\":{\"detail\":\"接口返回错误\",\"reason\":\"系统超时\",\"resolution\":\"系统异常，请用相同参数重新调用\"}," +
            "\"INVALID_TRANSACTIONID\":{\"detail\":\"无效的微信支付订单号\",\"reason\":\"请求参数未按指引进行填写\",\"resolution\":\"检查原交易单号是否存在\"}," +
            "\"PARAM_ERROR\":{\"detail\":\"参数错误\\t\",\"reason\":\"请求参数未按指引进行填写\",\"resolution\":\"请求参数错误，请重新检查再调用分账接口\"}," +
            "\"INVALID_REQUEST\":{\"detail\":\"请求不合法\",\"reason\":\"参数中APPID或MCHID不存在等 \",\"resolution\":\"请重新检查再调用分账接口\"}," +
            "\"ORDERNOTEXIST\":{\"detail\":\"分账单不存在\",\"reason\":\"订单号错误或分账单号错误\",\"resolution\":\"请检查订单号或分账单号是否有错误\"}}");


    final JSONObject statusMap = JSON.parseObject(
            "{\"ACCEPTED\":3," +
                 "\"PROCESSING\": 4," +
                    "\"FINISHED\": 5," +
                    "\"CLOSED\": 6}");

    final JSONObject resultStatusMap = JSON.parseObject(
            "{\"PENDING\": 1," +
                    "\"SUCCESS\": 2," +
                    "\"ADJUST\": 3," +
                    "\"RETURNED\": 4," +
                    "\"CLOSED\": 5}");



    private WxAppinfo getAppinfo(Long cUserId) {
        WxAppinfo wxAppinfo = new WxAppinfo();

        WxCUser wxCUser = wxCUserMapper.selectById(cUserId);
        if (wxCUser == null)
            throw new MallinkException(ErrorCode.USER_IS_EMPTY);

        wxAppinfo.setAppId(wxCUser.getAppId());
        wxAppinfo = wxAppinfoMapper.selectOne(new QueryWrapper(wxAppinfo));
        if (wxAppinfo == null)
            throw new MallinkException(ErrorCode.APP_ID_NOT_FOUND);

        return wxAppinfo;
    }


    @Override
    @Transactional(isolation=Isolation.SERIALIZABLE, propagation = Propagation.REQUIRED, rollbackFor = {Exception.class})
    public ResultData redoSharingOrder(WxProfitSharingOrder sharingOrder) {
        final IdWorker idworker = IdWorker.get();

        if (!sharingOrder.getType().equals(EnumProfitSharingOrderType.PROFIT_SHARING_SINGLE.getCode()) &&
                !sharingOrder.getType().equals(EnumProfitSharingOrderType.PROFIT_SHARING_MULTI.getCode())) {
            return new ResultData(ErrorCode.SYS_PARAMETER_ERROR);
        }

        WxPayOrder payOrder = wxPayOrderMapper.selectById(sharingOrder.getOrderId());
        WxAppinfo appInfo = getAppinfo(payOrder.getCUserId());
        WxPayAccount payAccount = wxPayAccountMapper.selectById(appInfo.getPayId());

        List<JSONObject> receivers;

        try {
            receivers = JSONArray.parseArray(sharingOrder.getReceivers(), JSONObject.class);
            if (receivers.size() <= 0)
                return new ResultData(ErrorCode.PROFIT_SHARING_RECEIVER_INVALID);
        } catch (Exception e) {
            return new ResultData(ErrorCode.PROFIT_SHARING_RECEIVER_INVALID);
        }

        final WxProfitSharingOrder frecord = sharingOrder;
        List<WxProfitSharingResult> resultList = new ArrayList<WxProfitSharingResult>();
        try {
            receivers.stream().forEach(receiver -> {
                Date currentDate = new Date();
                WxProfitSharingResult result = new WxProfitSharingResult();
                result.setId(idworker.nextId());
                result.setTenantId(frecord.getTenantId());
                result.setMerchantId(frecord.getMerchantId());
                result.setSharingOrderId(frecord.getId());
                result.setSharingReceiverId(Long.valueOf(receiver.getString("description")));
                result.setPayAmount(receiver.getInteger("amount"));
                result.setCreateTime(currentDate);
                result.setUpdateTime(currentDate);
                result.setSharingStatus(EnumProfitSharingResultStatus.PROFIT_SHARING_RESULT_PENDING.getCode());
                resultList.add(result);
            });
        }catch (Exception e) {
            return new ResultData(ErrorCode.PROFIT_SHARING_RECEIVER_INVALID);
        }

        //分账提交
        WxProfitSharingP psCmd = new WxProfitSharingP();
        psCmd.setMch_id(payAccount.getMchId());
        psCmd.setSub_mch_id(payAccount.getSubMchId());
        psCmd.setAppid(appInfo.getParentAppId());
        psCmd.setSub_appid(appInfo.getAppId());
        psCmd.setNonce_str(Utility.generate32UUID());
        psCmd.setTransaction_id(sharingOrder.getTransactionId());
        psCmd.setOut_order_no(sharingOrder.getId().toString());
        psCmd.setSign_type("HMAC-SHA256");
        psCmd.setReceivers(sharingOrder.getReceivers());

        String response;
        try {
            psCmd.setSign(WxPayment.createSignHMAC(BeanUtils.toStringMap(psCmd), payAccount.getApiKey()));
            logger.info("request:" + psCmd.toString());
            if(sharingOrder.getType().equals(EnumProfitSharingOrderType.PROFIT_SHARING_SINGLE.getCode())) {
                response = WxProfitSharing.pushOrder(BeanUtils.toStringMap(psCmd), payAccount.getCertPath(), payAccount.getMchId());
            } else if(sharingOrder.getType().equals(EnumProfitSharingOrderType.PROFIT_SHARING_MULTI.getCode())) {
                response = WxProfitSharing.pushMultiOrder(BeanUtils.toStringMap(psCmd), payAccount.getCertPath(), payAccount.getMchId());
            } else {
                throw new MallinkException(ErrorCode.SYS_PARAMETER_ERROR);
            }
        } catch (Exception e) {
            sharingOrder.setSharingStatus(EnumProfitSharingOrderStatus.PROFIT_SHARING_REQ_FAILED.getCode());
            sharingOrder.setErrorMsg("REDO:"+ErrorCode.PROFIT_SHARING_REQUEST_FAILED.getMessage());
            sharingOrder.setUpdateTime(new Date());
            wxProfitSharingOrderMapper.updateById(sharingOrder);
            return new ResultData(ErrorCode.PROFIT_SHARING_REQUEST_FAILED);
        }

        logger.info("response: " + response);
        Map<String, String> returnMap = WxPayment.xmlToMap(response);
        String return_code = returnMap.get("return_code");

        if (!"SUCCESS".equals(return_code)) {
            sharingOrder.setSharingStatus(EnumProfitSharingOrderStatus.PROFIT_SHARING_REQ_FAILED.getCode());
            sharingOrder.setErrorMsg("REDO:"+returnMap.get("return_msg"));
            sharingOrder.setUpdateTime(new Date());
            wxProfitSharingOrderMapper.updateById(sharingOrder);
            return new ResultData(ErrorCode.PROFIT_SHARING_REQUEST_FAILED.getCode(), returnMap.get("return_msg"));
        }

        if (!WxPayment.verifyNotifyHMAC(returnMap,payAccount.getApiKey())){
            sharingOrder.setErrorMsg("REDO:"+ErrorCode.PROFIT_SHARING_RETURN_INVALID.getMessage());
            sharingOrder.setUpdateTime(new Date());
            wxProfitSharingOrderMapper.updateById(sharingOrder);
            return new ResultData(ErrorCode.PROFIT_SHARING_RETURN_INVALID.getCode());
        }

        String result_code = returnMap.get("result_code");
        if (!"SUCCESS".equals(result_code)) {
            sharingOrder.setSharingStatus(EnumProfitSharingOrderStatus.PROFIT_SHARING_APPLY_FAILED.getCode());
            sharingOrder.setUpdateTime(new Date());
            sharingOrder.setErrorMsg("REDO:"+returnMap.get("err_code_des"));
            wxProfitSharingOrderMapper.updateById(sharingOrder);
            return new ResultData(ErrorCode.PROFIT_SHARING_APPLY_FAILED.getCode(), returnMap.get("err_code_des"));
        }

        sharingOrder.setSharingOrderNo(returnMap.get("order_id"));
        sharingOrder.setSharingStatus(EnumProfitSharingOrderStatus.PROFIT_SHARING_ACCEPTED.getCode());
        sharingOrder.setErrorMsg("REDO:重试分账成功");
        sharingOrder.setUpdateTime(new Date());
        wxProfitSharingOrderMapper.updateById(sharingOrder);
        for (WxProfitSharingResult result:resultList) {
            wxProfitSharingResultMapper.insert(result);
        }

        return new ResultData(returnMap);
    }


    @Override
    @Transactional(isolation=Isolation.SERIALIZABLE, propagation = Propagation.REQUIRED, rollbackFor = {Exception.class})
    public ResultData createSharingOrder(WxSharingOrderDto sharingOrderDto) {
        final IdWorker idworker = IdWorker.get();

        if (!sharingOrderDto.getType().equals(EnumProfitSharingOrderType.PROFIT_SHARING_SINGLE.getCode()) &&
                !sharingOrderDto.getType().equals(EnumProfitSharingOrderType.PROFIT_SHARING_MULTI.getCode())){
            return new ResultData(ErrorCode.SYS_PARAMETER_ERROR);
        }

        WxAppinfo appInfo = getAppinfo(sharingOrderDto.getCUserId());
        WxPayAccount payAccount = wxPayAccountMapper.selectById(appInfo.getPayId());

        //准备分账列表
        WxProfitSharingReceiver psReceiverQ = new WxProfitSharingReceiver();
        psReceiverQ.setTenantId(sharingOrderDto.getTenantId());
        psReceiverQ.setMerchantId(sharingOrderDto.getMerchantId());
        psReceiverQ.setSharingType(EnumProfitSharingType.PROFIT_SHARING_TYPE_WECHAT.getCode());
        psReceiverQ.setStatus(EnumProfitSharingReceiverStatus.PROFIT_SHARING_RECEIVER_STATUS_VALID.getCode());
        List<WxProfitSharingReceiver> psReceiverList  = wxProfitSharingReceiverMapper.findList(psReceiverQ);
        if (psReceiverList.size() < 0 || psReceiverList.size() > 50) {
            return new ResultData(ErrorCode.PROFIT_SHARING_RECEIVER_INVALID);
        }

        if (psReceiverList.size() == 0) { //没有分账账户,直接结束分账
            if (sharingOrderDto.getType().equals(EnumProfitSharingOrderType.PROFIT_SHARING_SINGLE.getCode()))
                sharingOrderDto.setType(EnumProfitSharingOrderType.PROFIT_SHARING_SINGLE_FINISH.getCode());
            if (sharingOrderDto.getType().equals(EnumProfitSharingOrderType.PROFIT_SHARING_MULTI.getCode()))
                return new ResultData(ErrorCode.PROFIT_SHARING_RECEIVER_UNKNOWN);
            if(sharingOrderDto.getRateAmount() != null) {
                // 分账完结
                sharingOrderDto.setShareAmount(sharingOrderDto.getPayAmount()+sharingOrderDto.getRateAmount());
            }
            return finishSharingOrder(sharingOrderDto);
        }

        //计算分账账户合法性
        if (psReceiverList.size() > 1 &&
                psReceiverList.stream().filter(r->(r.getParameter() == null)).count() > 0) {
            return new ResultData(ErrorCode.PROFIT_SHARING_RECEIVER_INVALID);
        }

        //计算分账金额合法性
        psReceiverList.stream().forEach(r->
            {
                if (r.getParameter() == null){
                    r.setSharingAmount(sharingOrderDto.getShareAmount());
                } else {
                    r.setSharingAmount(sharingOrderDto.getShareAmount()*Integer.valueOf(r.getParameter())/10000);
                }
            });
        if (psReceiverList.stream().mapToInt(r->r.getSharingAmount()).sum() > sharingOrderDto.getShareAmount()){
            return new ResultData(ErrorCode.PROFIT_SHARING_RECEIVER_INVALID);
        }

        //单次分账检查是否已创建分账订单
        WxProfitSharingOrder record = new WxProfitSharingOrder();

        record.setOrderId(sharingOrderDto.getOrderId());
        record = wxProfitSharingOrderMapper.selectOne(new QueryWrapper(record));
        if (record == null) {
            //创建分账订单
            Date currentDate = new Date();
            record = new WxProfitSharingOrder();
            record.setId(idworker.nextId());
            record.setTenantId(sharingOrderDto.getTenantId());
            record.setTransactionId(sharingOrderDto.getTransactionId());
            record.setOrderId(sharingOrderDto.getOrderId());
            record.setPayAmount(sharingOrderDto.getPayAmount());
            record.setMerchantId(sharingOrderDto.getMerchantId());
            record.setSharingStatus(EnumProfitSharingOrderStatus.PROFIT_SHARING_UNKNOWN.getCode());
            record.setCreateTime(currentDate);
            record.setUpdateTime(currentDate);
            record.setPayTimeStart(sharingOrderDto.getPayTimeStart());
            record.setPayTimeEnd(sharingOrderDto.getPayTimeEnd());
            record.setType(sharingOrderDto.getType());

            wxProfitSharingOrderMapper.insert(record);
        }


        // 添加分账接收方

        final WxProfitSharingOrder frecord = record;
        JSONArray receivers = new JSONArray();
        List <WxProfitSharingResult> resultList = new ArrayList<WxProfitSharingResult>();
        psReceiverList.stream().forEach(receiver->{
            Date currentDate = new Date();
            JSONObject jo = new JSONObject();
            jo.put("type",EnumProfitSharingReceiverType.getEnum(receiver.getReceiverType()).getMessage());
            jo.put("account",receiver.getReceiverAccount());
            jo.put("amount", receiver.getSharingAmount());
            //jo.put("description",receiver.getReceiverComments()); //改为存ID,
            jo.put("description",receiver.getId().toString());      //为重试做准备
            receivers.add(jo);

            WxProfitSharingResult result = new WxProfitSharingResult();

            result.setId(idworker.nextId());
            result.setTenantId(frecord.getTenantId());
            result.setMerchantId(frecord.getMerchantId());
            result.setSharingOrderId(frecord.getId());
            result.setSharingReceiverId(receiver.getId());
            result.setPayAmount(receiver.getSharingAmount());
            result.setCreateTime(currentDate);
            result.setUpdateTime(currentDate);
            result.setSharingStatus(EnumProfitSharingResultStatus.PROFIT_SHARING_RESULT_PENDING.getCode());
            resultList.add(result);
        });


        //分账提交
        WxProfitSharingP psCmd = new WxProfitSharingP();
        psCmd.setMch_id(payAccount.getMchId());
        psCmd.setSub_mch_id(payAccount.getSubMchId());
        psCmd.setAppid(appInfo.getParentAppId());
        psCmd.setSub_appid(appInfo.getAppId());
        psCmd.setNonce_str(Utility.generate32UUID());
        psCmd.setTransaction_id(sharingOrderDto.getTransactionId());
        psCmd.setOut_order_no(record.getId().toString());
        psCmd.setSign_type("HMAC-SHA256");
        psCmd.setReceivers(receivers.toJSONString());

        record.setReceivers(receivers.toJSONString());
        wxProfitSharingOrderMapper.updateById(record);
        
        String response;
        try {
            psCmd.setSign(WxPayment.createSignHMAC(BeanUtils.toStringMap(psCmd), payAccount.getApiKey()));
            logger.info("request:" + psCmd.toString());
            if(sharingOrderDto.getType().equals(EnumProfitSharingOrderType.PROFIT_SHARING_SINGLE.getCode())) {
                response = WxProfitSharing.pushOrder(BeanUtils.toStringMap(psCmd), payAccount.getCertPath(), payAccount.getMchId());
            } else if(sharingOrderDto.getType().equals(EnumProfitSharingOrderType.PROFIT_SHARING_MULTI.getCode())) {
                response = WxProfitSharing.pushMultiOrder(BeanUtils.toStringMap(psCmd), payAccount.getCertPath(), payAccount.getMchId());
            } else {
                throw new MallinkException(ErrorCode.SYS_PARAMETER_ERROR);
            }
        } catch (Exception e) {
            record.setSharingStatus(EnumProfitSharingOrderStatus.PROFIT_SHARING_REQ_FAILED.getCode());
            record.setErrorMsg(ErrorCode.PROFIT_SHARING_REQUEST_FAILED.getMessage());
            record.setUpdateTime(new Date());
            wxProfitSharingOrderMapper.updateById(record);
            return new ResultData(ErrorCode.PROFIT_SHARING_REQUEST_FAILED);
        }

        logger.info("response: " + response);
        Map<String, String> returnMap = WxPayment.xmlToMap(response);
        String return_code = returnMap.get("return_code");

        if (!"SUCCESS".equals(return_code)) {
            record.setSharingStatus(EnumProfitSharingOrderStatus.PROFIT_SHARING_REQ_FAILED.getCode());
            record.setErrorMsg(returnMap.get("return_msg"));
            record.setUpdateTime(new Date());
            wxProfitSharingOrderMapper.updateById(record);
            return new ResultData(ErrorCode.PROFIT_SHARING_REQUEST_FAILED.getCode(), returnMap.get("return_msg"));
        }

        if (!WxPayment.verifyNotifyHMAC(returnMap,payAccount.getApiKey())){
            record.setErrorMsg(ErrorCode.PROFIT_SHARING_RETURN_INVALID.getMessage());
            record.setUpdateTime(new Date());
            wxProfitSharingOrderMapper.updateById(record);
            return new ResultData(ErrorCode.PROFIT_SHARING_RETURN_INVALID.getCode());
        }

        String result_code = returnMap.get("result_code");
        if (!"SUCCESS".equals(result_code)) {
            record.setSharingStatus(EnumProfitSharingOrderStatus.PROFIT_SHARING_APPLY_FAILED.getCode());
            record.setUpdateTime(new Date());
            record.setErrorMsg(returnMap.get("err_code_des"));
            wxProfitSharingOrderMapper.updateById(record);
            return new ResultData(ErrorCode.PROFIT_SHARING_APPLY_FAILED.getCode(), returnMap.get("err_code_des"));
        }

        record.setSharingOrderNo(returnMap.get("order_id"));
        record.setSharingStatus(EnumProfitSharingOrderStatus.PROFIT_SHARING_ACCEPTED.getCode());
        record.setUpdateTime(new Date());
        wxProfitSharingOrderMapper.updateById(record);
        for (WxProfitSharingResult result:resultList) {
            wxProfitSharingResultMapper.insert(result);
        }

        return new ResultData(returnMap);
    }

    @Override
    @Transactional(propagation = Propagation.REQUIRED, readOnly = false, rollbackFor = {Exception.class})
    public ResultData querySharingOrder(WxProfitSharingOrder wxProfitSharingOrder) {

        WxProfitSharingOrder record = new WxProfitSharingOrder();

        WxAppinfo appInfo;
        if (wxProfitSharingOrder.getType().equals(EnumProfitSharingOrderType.PROFIT_SHARING_SINGLE.getCode())
                ||wxProfitSharingOrder.getType().equals(EnumProfitSharingOrderType.PROFIT_SHARING_SINGLE_FINISH.getCode())){
            WxPayOrder wxPayOrder = wxPayOrderMapper.selectById(wxProfitSharingOrder.getOrderId());
            if (wxPayOrder == null)
                return new ResultData(ErrorCode.ORDER_IS_NOT_FIND);
            appInfo = getAppinfo(wxPayOrder.getCUserId());
        } else if(wxProfitSharingOrder.getType().equals(EnumProfitSharingOrderType.PROFIT_SHARING_MULTI.getCode())
                ||wxProfitSharingOrder.getType().equals(EnumProfitSharingOrderType.PROFIT_SHARING_MULTI_FINISH.getCode())){
            WxCardSpend wxCardSpend = wxCardSpendMapper.selectById(wxProfitSharingOrder.getOrderId());
            if (wxCardSpend == null)
                return new ResultData(ErrorCode.ORDER_IS_NOT_FIND);
            appInfo = getAppinfo(wxCardSpend.getOwnerId());
        } else {
            return new ResultData(ErrorCode.PROFIT_SHARING_QUERY_UNKNOWN_TYPE);
        }
        WxPayAccount payAccount = wxPayAccountMapper.selectById(appInfo.getPayId());

        //是否已创建分账订单
        record.setOrderId(wxProfitSharingOrder.getOrderId());
        record = wxProfitSharingOrderMapper.selectOne(new QueryWrapper(record));
        if (record == null)
            return new ResultData(ErrorCode.ORDER_IS_NOT_FIND);

        //分账查询提交
        WxProfitSharingQueryP wxProfitSharingQueryP = new WxProfitSharingQueryP();;
        wxProfitSharingQueryP.setMch_id(payAccount.getMchId());
        wxProfitSharingQueryP.setSub_mch_id(payAccount.getSubMchId());
        wxProfitSharingQueryP.setNonce_str(Utility.generate32UUID());
        wxProfitSharingQueryP.setTransaction_id(wxProfitSharingOrder.getTransactionId());
        wxProfitSharingQueryP.setOut_order_no(record.getId().toString());
        wxProfitSharingQueryP.setSign_type("HMAC-SHA256");
        String response;
        try {
            wxProfitSharingQueryP.setSign(WxPayment.createSignHMAC(BeanUtils.toStringMap(wxProfitSharingQueryP),payAccount.getApiKey()));
            response = WxProfitSharing.queryOrder(BeanUtils.toStringMap(wxProfitSharingQueryP), payAccount.getCertPath(), payAccount.getMchId());
        }catch (Exception e){
            return new ResultData(ErrorCode.PROFIT_SHARING_QUERY_REQUEST_FAILED.getCode(), ErrorCode.PROFIT_SHARING_QUERY_REQUEST_FAILED.getMessage()+e.getMessage());
        }
        Map<String, String> returnMap = WxPayment.xmlToMap(response);
        String return_code = returnMap.get("return_code");
        if (!"SUCCESS".equals(return_code)) {
            return new ResultData(ErrorCode.PROFIT_SHARING_QUERY_REQUEST_FAILED.getCode(), returnMap.get("return_msg"));
        }

        if (!WxPayment.verifyNotifyHMAC(returnMap,payAccount.getApiKey())){
            return new ResultData(ErrorCode.PROFIT_SHARING_QUERY_RETURN_INVALID);
        }

        String result_code = returnMap.get("result_code");
        if (!"SUCCESS".equals(result_code)) {
            return new ResultData(ErrorCode.PROFIT_SHARING_QUERY_APPLY_FAILED.getCode(), returnMap.get("err_code_des"));
        }

        String out_order_no = returnMap.get("out_order_no");
        if (StringUtils.isBlank(out_order_no) || !out_order_no.equals(record.getId().toString())){
            return new ResultData(ErrorCode.PROFIT_SHARING_QUERY_RETURN_INVALID);
        }

        record.setSharingStatus((Integer) statusMap.get(returnMap.get("status")));
        record.setUpdateTime(new Date());
        wxProfitSharingOrderMapper.updateById(record);

        String receivers = returnMap.get("receivers");

        if (receivers != null) {
            JSONArray jReceivers = JSONArray.parseArray(receivers);

            WxProfitSharingResult result = new WxProfitSharingResult();
            result.setSharingOrderId(record.getId());
            List <WxProfitSharingResult> wxProfitSharingResultList = wxProfitSharingResultMapper.findList(result);

            for(int j = 0; j < jReceivers.size() ; j++) {
                JSONObject res = (JSONObject) jReceivers.get(j);
                JSONObject des = new JSONObject();
                des.put("type", res.getString("type"));
                des.put("account", res.getString("account"));
                des.put("description", res.getString("description"));
                des.put("amount", res.getString("amount"));

                int i = 0;
                for (i = 0; i < wxProfitSharingResultList.size(); i++) {
                    WxProfitSharingResult wxProfitSharingResult = wxProfitSharingResultList.get(i);
                    WxProfitSharingReceiver wxProfitSharingReceiver = wxProfitSharingReceiverMapper
                            .selectById(wxProfitSharingResult.getSharingReceiverId());
                    if (wxProfitSharingReceiver == null) continue;

                    if (res.getString("type").equals(EnumProfitSharingReceiverType.getEnum(wxProfitSharingReceiver.getReceiverType()).getMessage())
                            && res.getString("account").equals(wxProfitSharingReceiver.getReceiverAccount())) {
                        wxProfitSharingResult.setFinishTime(res.getString("finish_time"));
                        wxProfitSharingResult.setUpdateTime(new Date());
                        wxProfitSharingResult.setSharingStatus(resultStatusMap.getIntValue(res.getString("result")));
                        wxProfitSharingResult.setFailedReason(res.getString("fail_reason"));
                        wxProfitSharingResult.setDescription(des.toJSONString());
                        wxProfitSharingResultMapper.updateById(wxProfitSharingResult);
                        break;
                    }
                }
                if (i == wxProfitSharingResultList.size()) {

                    WxProfitSharingResult wxProfitSharingResult = new WxProfitSharingResult();

                    wxProfitSharingResult.setTenantId(record.getTenantId());
                    wxProfitSharingResult.setMerchantId(record.getMerchantId());
                    wxProfitSharingResult.setSharingOrderId(record.getId());
                    wxProfitSharingResult.setSharingReceiverId(0L); //剩余钱分给特约商户,没有相应的接受者

                    List<WxProfitSharingResult> list = wxProfitSharingResultMapper.findList(wxProfitSharingResult);
                    if (list.size() > 0) {
                        wxProfitSharingResult = list.get(0);
                    }

                    wxProfitSharingResult.setPayAmount(Integer.valueOf(res.getString("amount")));
                    wxProfitSharingResult.setFinishTime(res.getString("finish_time"));
                    wxProfitSharingResult.setSharingStatus(resultStatusMap.getIntValue(res.getString("result")));
                    wxProfitSharingResult.setFailedReason(res.getString("fail_reason"));
                    wxProfitSharingResult.setDescription(des.toJSONString());
                    if (wxProfitSharingResult.getId() != null) {
                        wxProfitSharingResult.setUpdateTime(new Date());
                        wxProfitSharingResultMapper.updateById(wxProfitSharingResult);
                    } else {
                        wxProfitSharingResult.setCreateTime(new Date());
                        wxProfitSharingResult.setUpdateTime(new Date());
                        wxProfitSharingResult.setId(IdWorker.get().nextId());
                        wxProfitSharingResultMapper.insert(wxProfitSharingResult);
                    }
                }
            }
        }
        return new ResultData(returnMap);
    }

    // 分账完结
    @Override
    @Transactional(propagation = Propagation.REQUIRED, readOnly = false, rollbackFor = {Exception.class})
    public ResultData finishSharingOrder(WxSharingOrderDto sharingOrderDto) {
        final IdWorker idworker = IdWorker.get();

        if (!sharingOrderDto.getType().equals(EnumProfitSharingOrderType.PROFIT_SHARING_SINGLE_FINISH.getCode())
                &&
            !sharingOrderDto.getType().equals(EnumProfitSharingOrderType.PROFIT_SHARING_MULTI_FINISH.getCode())){
            return new ResultData(ErrorCode.SYS_PARAMETER_ERROR);
        }

        WxAppinfo appInfo = getAppinfo(sharingOrderDto.getCUserId());
        WxPayAccount payAccount = wxPayAccountMapper.selectById(appInfo.getPayId());


        //分账检查是否已创建分账订单
        WxProfitSharingOrder record = new WxProfitSharingOrder();
        //创建分账订单
        Date currentDate = new Date();
        record.setId(idworker.nextId());
        record.setTenantId(sharingOrderDto.getTenantId());
        record.setTransactionId(sharingOrderDto.getTransactionId());
        record.setPayAmount(sharingOrderDto.getPayAmount());
        record.setMerchantId(sharingOrderDto.getMerchantId());
        record.setOrderId(sharingOrderDto.getOrderId());
        record.setSharingStatus(EnumProfitSharingOrderStatus.PROFIT_SHARING_UNKNOWN.getCode());
        record.setCreateTime(currentDate);
        record.setUpdateTime(currentDate);
        record.setPayTimeStart(sharingOrderDto.getPayTimeStart());
        record.setPayTimeEnd(sharingOrderDto.getPayTimeEnd());
        record.setType(sharingOrderDto.getType());
        wxProfitSharingOrderMapper.insert(record);

        //分账提交
        WxProfitSharingFinishP psFCmd = new WxProfitSharingFinishP();
        psFCmd.setMch_id(payAccount.getMchId());
        psFCmd.setSub_mch_id(payAccount.getSubMchId());
        psFCmd.setAppid(appInfo.getParentAppId());
        psFCmd.setNonce_str(Utility.generate32UUID());
        psFCmd.setTransaction_id(sharingOrderDto.getTransactionId());
        psFCmd.setOut_order_no(record.getId().toString());
        psFCmd.setAmount(sharingOrderDto.getShareAmount());
        psFCmd.setDescription("分账已完结");
        psFCmd.setSign_type("HMAC-SHA256");

        String response;
        try {
            psFCmd.setSign(WxPayment.createSignHMAC(BeanUtils.toStringMap(psFCmd), payAccount.getApiKey()));
            logger.info("request:" + psFCmd.toString());
            response = WxProfitSharing.finishOrder(BeanUtils.toStringMap(psFCmd), payAccount.getCertPath(), payAccount.getMchId());
        } catch (Exception e) {
            record.setSharingStatus(EnumProfitSharingOrderStatus.PROFIT_SHARING_REQ_FAILED.getCode());
            record.setErrorMsg(ErrorCode.PROFIT_SHARING_REQUEST_FAILED.getMessage());
            record.setUpdateTime(new Date());
            wxProfitSharingOrderMapper.updateById(record);
            return new ResultData(ErrorCode.PROFIT_SHARING_REQUEST_FAILED);
        }

        logger.info("response: " + response);
        Map<String, String> returnMap = WxPayment.xmlToMap(response);
        String return_code = returnMap.get("return_code");

        if (!"SUCCESS".equals(return_code)) {
            record.setSharingStatus(EnumProfitSharingOrderStatus.PROFIT_SHARING_REQ_FAILED.getCode());
            record.setErrorMsg(returnMap.get("return_msg"));
            record.setUpdateTime(new Date());
            wxProfitSharingOrderMapper.updateById(record);
            return new ResultData(ErrorCode.PROFIT_SHARING_REQUEST_FAILED.getCode(), returnMap.get("return_msg"));
        }

        if (!WxPayment.verifyNotifyHMAC(returnMap,payAccount.getApiKey())){
            record.setErrorMsg(ErrorCode.PROFIT_SHARING_RETURN_INVALID.getMessage());
            record.setUpdateTime(new Date());
            wxProfitSharingOrderMapper.updateById(record);
            return new ResultData(ErrorCode.PROFIT_SHARING_RETURN_INVALID.getCode());
        }

        String result_code = returnMap.get("result_code");
        if (!"SUCCESS".equals(result_code)) {
            record.setSharingStatus(EnumProfitSharingOrderStatus.PROFIT_SHARING_APPLY_FAILED.getCode());
            record.setUpdateTime(new Date());
            record.setErrorMsg(returnMap.get("err_code_des"));
            wxProfitSharingOrderMapper.updateById(record);
            return new ResultData(ErrorCode.PROFIT_SHARING_APPLY_FAILED.getCode(), returnMap.get("err_code_des"));
        }

        record.setSharingOrderNo(returnMap.get("order_id"));
        record.setSharingStatus(EnumProfitSharingOrderStatus.PROFIT_SHARING_ACCEPTED.getCode());
        record.setUpdateTime(new Date());
        wxProfitSharingOrderMapper.updateById(record);
        return new ResultData(returnMap);
    }

    @Override
    public PageInfo<WxProfitSharingOrderVo> listAsPage(WxProfitSharingOrderQueryVo order, Integer pageIndex, Integer pageSize) {
        return PageHelper.startPage(pageIndex, pageSize).doSelectPageInfo(() -> wxProfitSharingOrderMapper.findOrderList(order));

    }

    @Override
    public Map<String, Object> queryOrderSummary(String tenantId) {
        Map<String, Object> result = new HashMap<>();
        queryMerchantCount(tenantId, result);
        queryOrderSummary(tenantId,result);
        return result;
    }

    @Override
    public ResultData findOrderDetails(Long id) {
        Map<String,Object> result=new HashMap<>(2);
        WxProfitSharingOrderQueryVo wxProfitSharingOrderQueryVo = new WxProfitSharingOrderQueryVo();
        wxProfitSharingOrderQueryVo.setId(id);
        WxProfitSharingOrderVo wxProfitSharingOrderVo = wxProfitSharingOrderMapper.findOrderList(wxProfitSharingOrderQueryVo).get(0);
        List<WxProfitSharingOrderDetailsVo> orderDetails = wxProfitSharingOrderMapper.findOrderDetails(id);
        result.put("order",wxProfitSharingOrderVo);
        result.put("details",orderDetails);
        return new ResultData(result);
    }

    public void queryMerchantCount(String tenantId, Map<String, Object> result) {
        String systemTime = DateUtils.getSystemTime("yyyy-MM-dd");
        //全部商户个数
        Map<String, Object> params = new HashMap<>();
        params.put("tenantId", tenantId);
        String thirtyTime = DateUtils.getTimeBefore(29, new Date());
        params.put("startdate", thirtyTime + " 00:00:00");
        params.put("enddate", systemTime + " 23:59:59");
        Long allMerchantCount=wxProfitSharingOrderMapper.queryOrderForMerchantCount(params);
        result.put("allMerchantCount",allMerchantCount);
        //今日
        params.put("startdate", systemTime + " 00:00:00");
        params.put("enddate", systemTime + " 23:59:59");
        Long todayMerchantCount=wxProfitSharingOrderMapper.queryOrderForMerchantCount(params);
        result.put("todayMerchantCount",todayMerchantCount);
        //昨日
        String yesterday = DateUtils.getTimeBefore(1, new Date());
        params.put("startdate", yesterday + " 00:00:00");
        params.put("enddate", yesterday + " 23:59:59");
        Long yesterdayMerchantCount=wxProfitSharingOrderMapper.queryOrderForMerchantCount(params);
        result.put("yesterdayMerchantCount",yesterdayMerchantCount);
        //上周
        String lastweek = DateUtils.getTimeBefore(7, new Date());
        params.put("startdate", lastweek + " 00:00:00");
        params.put("enddate", lastweek + " 23:59:59");
        Long lastweekMerchantCount=wxOrderMapper.queryOrderForMerchantCount(params);
        result.put("lastweekMerchantCount",lastweekMerchantCount);
        //商户数日环比
        if (yesterdayMerchantCount > 0) {
            double hbd = (double) (todayMerchantCount - yesterdayMerchantCount) / yesterdayMerchantCount * 100;
            double hb = new BigDecimal(hbd).setScale(2, BigDecimal.ROUND_HALF_UP).doubleValue();
            result.put("increasedPercentMerchant", hb+"%");
        } else {
            result.put("increasedPercentMerchant", "--");
        }
        //商户数周同比
        if (lastweekMerchantCount > 0) {
            double hbd = (double) (todayMerchantCount - lastweekMerchantCount) / lastweekMerchantCount * 100;
            double hb = new BigDecimal(hbd).setScale(2, BigDecimal.ROUND_HALF_UP).doubleValue();
            result.put("increasedPercentWeekMerchant", hb+"%");
        } else {
            result.put("increasedPercentWeekMerchant", "--");
        }
    }

    public void queryOrderSummary(String tenantId, Map<String, Object> result) {
        String systemTime = DateUtils.getSystemTime("yyyy-MM-dd");
        //全部分账总数
        Map<String, Object> params = new HashMap<>();
        params.put("tenantId", tenantId);
        String thirtyTime = DateUtils.getTimeBefore(29, new Date());
        params.put("startdate", thirtyTime + " 00:00:00");
        params.put("enddate", systemTime + " 23:59:59");
        Long allOrderSummary=wxProfitSharingOrderMapper.queryOrderForSum(params);
        result.put("allOrderSummary",allOrderSummary);
        //今日
        params.put("startdate", systemTime + " 00:00:00");
        params.put("enddate", systemTime + " 23:59:59");
        Long todayOrderSummary=wxProfitSharingOrderMapper.queryOrderForSum(params);
        result.put("todayOrderSummary",todayOrderSummary);
        //昨日
        String yesterday = DateUtils.getTimeBefore(1, new Date());
        params.put("startdate", yesterday + " 00:00:00");
        params.put("enddate", yesterday + " 23:59:59");
        Long yesterdayOrderSummary=wxProfitSharingOrderMapper.queryOrderForSum(params);
        result.put("yesterdayOrderSummary",yesterdayOrderSummary);
        //上周
        String lastweek = DateUtils.getTimeBefore(7, new Date());
        params.put("startdate", lastweek + " 00:00:00");
        params.put("enddate", lastweek + " 23:59:59");
        Long lastweekOrderSummary=wxProfitSharingOrderMapper.queryOrderForSum(params);
        result.put("lastweekOrderSummary",lastweekOrderSummary);
        //商户数日环比
        if (yesterdayOrderSummary > 0) {
            double hbd = (double) (todayOrderSummary - yesterdayOrderSummary) / yesterdayOrderSummary * 100;
            double hb = new BigDecimal(hbd).setScale(2, BigDecimal.ROUND_HALF_UP).doubleValue();
            result.put("increasedPercentSummary", hb+"%");
        } else {
            result.put("increasedPercentSummary", "--");
        }
        //商户数周同比
        if (lastweekOrderSummary > 0) {
            double hbd = (double) (todayOrderSummary - lastweekOrderSummary) / lastweekOrderSummary * 100;
            double hb = new BigDecimal(hbd).setScale(2, BigDecimal.ROUND_HALF_UP).doubleValue();
            result.put("increasedPercentWeekSummary", hb+"%");
        } else {
            result.put("increasedPercentWeekSummary", "--");
        }
    }


}
