package com.hfkj.channel.ccb;

import ccb.pay.api.util.CCBPayUtil;
import com.alibaba.fastjson.JSONObject;
import com.ccb.wlpt.RequestProcess;
import com.hfkj.channel.ccb.config.CCBConfig;
import com.hfkj.channel.ccb.utils.CCBUtils;
import com.hfkj.common.exception.ErrorCode;
import com.hfkj.common.exception.ErrorHelp;
import com.hfkj.common.exception.SysCode;
import com.hfkj.channel.weixin.utils.XmlUtil;
import com.hfkj.common.utils.HttpsUtils;
import com.hfkj.common.utils.MD5Util;
import com.hfkj.config.CommonSysConfig;
import com.hfkj.config.CommonSysConst;
import com.hfkj.entity.*;
import com.hfkj.service.*;
import com.hfkj.sysenum.*;
import org.apache.commons.collections4.MapUtils;
import org.dom4j.DocumentException;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.util.*;

/**
 * 建行交易 服务
 * @author hurui
 */
@Component
public class CCBTradeService {

    @Resource
    private BsTradeOrderService tradeOrderService;

    @Resource
    private BsTradeOrderRefundService tradeOrderRefundService;

    @Resource
    private BsTradeOrderMsgService tradeOrderMsgService;

    @Resource
    private BsMerPlatformNoService merPlatformNoService;

    /**
     * B扫C支付
     * @param tradeNo  交易订单号
     * @param authCode  授权码、条码
     * @return
     */
    public Map<String, Object> b2cPay(String tradeNo,String authCode) {
        try {
            // 查询交易订单
            BsTradeOrder order = tradeOrderService.getOrderByOutTradeNo(tradeNo);
            if (order == null) {
                throw ErrorHelp.genException(SysCode.System, ErrorCode.COMMON_ERROR, "未找到交易订单");
            }
            if (!order.getStatus().equals(TradeOrderStatusEnum.status1.getNumber())) {
                throw ErrorHelp.genException(SysCode.System, ErrorCode.COMMON_ERROR, "订单不处于待支付状态");
            }
            // 查询商户号
            BsMerPlatformNo platformNo = merPlatformNoService.getPlatformNo(order.getMerId(), PlatformTypeEnum.type3);
            if (platformNo == null) {
                throw ErrorHelp.genException(SysCode.System, ErrorCode.COMMON_ERROR, "未找到商户号");
            }

            Map<String, Object> param = new HashMap<>();
            param.put("MERCHANTID", platformNo.getPlatformNo());
            param.put("POSID", platformNo.getPosId());
            param.put("BRANCHID", platformNo.getBranchId());
            param.put("TXCODE", "PAY100");
            param.put("MERFLAG", "1");
            param.put("ORDERID", order.getOutTradeNo());
            param.put("QRCODE", authCode);
            param.put("AMOUNT", order.getTradeAmount());
            param.put("PROINFO", "二维码支付");

            // 参数加密
            CCBPayUtil ccbPayUtil = new CCBPayUtil();
            String paramStr = ccbPayUtil.makeCCBParam(CCBUtils.paramSort(param), platformNo.getMerPublicKey());

            // 组装请求地址和参数
            String merInfo = "MERCHANTID="+param.get("MERCHANTID")+"&POSID="+param.get("POSID")+"&BRANCHID="+param.get("BRANCHID");
            String url = CCBConfig.B2C_HOST + merInfo + "&ccbParam=" + paramStr;

            // 记录请求消息
            BsTradeOrderMsg orderMsg = new BsTradeOrderMsg();
            orderMsg.setOutTradeNo(order.getOutTradeNo());
            orderMsg.setType(TradeOrderMsgTypeEnum.type1.getNumber());
            orderMsg.setRequestContent(url);
            tradeOrderMsgService.editTradeOrderMsg(orderMsg);

            // 请求接口
            JSONObject requestBody = HttpsUtils.doPost(url);

            // 记录响应消息
            orderMsg.setResponseContent(requestBody.toJSONString());
            tradeOrderMsgService.editTradeOrderMsg(orderMsg);

            if (requestBody.getString("RESULT").equals("N")) {
                throw ErrorHelp.genException(SysCode.System, ErrorCode.COMMON_ERROR, requestBody.getString("ERRCODE"));
            }

            // 1：龙支付 2：微信  3：支付宝 4：银联
            if (requestBody.getInteger("QRCODETYPE").equals(1)) {
                order.setPayMode(TradeOrderPayModeEnum.DRAGON.getCode());
            }
            if (requestBody.getInteger("QRCODETYPE").equals(2)) {
                order.setPayMode(TradeOrderPayModeEnum.WECHAT.getCode());
            }
            if (requestBody.getInteger("QRCODETYPE").equals(3)) {
                order.setPayMode(TradeOrderPayModeEnum.ALIPAY.getCode());
            }
            if (requestBody.getInteger("QRCODETYPE").equals(4)) {
                order.setPayMode(TradeOrderPayModeEnum.UQRCODEPAY.getCode());
            }
            if (requestBody.getString("RESULT").equals("Y")) {
                order.setPlatformType(PlatformTypeEnum.type3.getNumber());
                order.setPlatformMerNo(platformNo.getPlatformNo());
                order.setPlatformTradeNo(requestBody.getString("TRACEID"));
                order.setTradeActualAmount(requestBody.getBigDecimal("AMOUNT"));
                order.setStatus(TradeOrderStatusEnum.status3.getNumber());
                order.setPayTime(new Date());
                order.setAccPaymentCode(authCode);
                tradeOrderService.editOrder(order);
            }

            if (requestBody.getString("RESULT").equals("Q")) {
                order.setPlatformType(PlatformTypeEnum.type3.getNumber());
                order.setPlatformMerNo(platformNo.getPlatformNo());
                order.setPlatformTradeNo(requestBody.getString("TRACEID"));
                order.setTradeActualAmount(requestBody.getBigDecimal("AMOUNT"));
                order.setStatus(TradeOrderStatusEnum.status2.getNumber());
                order.setAccPaymentCode(authCode);
                tradeOrderService.editOrder(order);

                for (int num = 0; num <= 5; num++) {
                    System.out.println(num+"次");
                    order = rotationQueryTrade(order.getOutTradeNo());
                    if (!order.getStatus().equals(TradeOrderStatusEnum.status3.getNumber())) {
                        // 休眠5秒
                        Thread.sleep(5000);
                    }
                }

            }

            Map<String, Object> returnMap = new HashMap<>();
            returnMap.put("order", order);
            return returnMap;

        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    /**
     * 轮训查询订单
     * @param tradeNo  交易订单号
     * @return
     */
    public BsTradeOrder rotationQueryTrade(String tradeNo) {
        try {
            // 查询交易订单
            BsTradeOrder order = tradeOrderService.getOrderByOutTradeNo(tradeNo);
            if (order == null) {
                throw ErrorHelp.genException(SysCode.System, ErrorCode.COMMON_ERROR, "未找到交易订单");
            }
            // 查询商户号
            BsMerPlatformNo platformNo = merPlatformNoService.getPlatformNo(order.getMerId(), PlatformTypeEnum.type3);
            if (platformNo == null) {
                throw ErrorHelp.genException(SysCode.System, ErrorCode.COMMON_ERROR, "未找到商户号");
            }

            Map<String, Object> param = new HashMap<>();
            param.put("MERCHANTID", platformNo.getPlatformNo());
            param.put("POSID", platformNo.getPosId());
            param.put("BRANCHID", platformNo.getBranchId());
            param.put("TXCODE", "PAY101");
            param.put("MERFLAG", "1");
            param.put("ORDERID", order.getOutTradeNo());
            param.put("QRYTIME", 1);
            param.put("QRCODE", order.getAccPaymentCode());

            // 参数加密
            CCBPayUtil ccbPayUtil = new CCBPayUtil();
            String paramStr = ccbPayUtil.makeCCBParam(CCBUtils.paramSort(param), platformNo.getMerPublicKey());

            // 组装请求地址和参数
            String merInfo = "MERCHANTID="+param.get("MERCHANTID")+"&POSID="+param.get("POSID")+"&BRANCHID="+param.get("BRANCHID");
            String url = CCBConfig.B2C_HOST + merInfo + "&ccbParam=" + paramStr;

            // 请求接口
            JSONObject requestBody = HttpsUtils.doPost(url);
            if (requestBody.getString("RESULT").equals("N")) {
                throw ErrorHelp.genException(SysCode.System, ErrorCode.COMMON_ERROR, requestBody.getString("ERRCODE"));
            }

            if (requestBody.getString("RESULT").equals("Y")) {
                order.setTradeActualAmount(requestBody.getBigDecimal("AMOUNT"));
                order.setStatus(TradeOrderStatusEnum.status3.getNumber());
                order.setPayTime(new Date());
                tradeOrderService.editOrder(order);
            }

            return order;

        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    /**
     * 交易订单退款
     * @param refundNo
     * @param refundMoney
     * @return
     */
    public Map<String, Object> refund(String refundNo, BigDecimal refundMoney) {
        // 查询交易订单
        BsTradeOrderRefund orderRefund = tradeOrderRefundService.getRefundByRefundNo(refundNo);
        if (orderRefund == null) {
            throw ErrorHelp.genException(SysCode.System, ErrorCode.COMMON_ERROR, "未找到订单");
        }
        if (!orderRefund.getStatus().equals(TradeOrderRefundStatusEnum.status1.getNumber())) {
            throw ErrorHelp.genException(SysCode.System, ErrorCode.COMMON_ERROR, "订单不处于退款中状态");
        }
        // 查询交易订单
        BsTradeOrder order = tradeOrderService.getOrderByOutTradeNo(orderRefund.getOutTradeNo());
        if (order == null) {
            throw ErrorHelp.genException(SysCode.System, ErrorCode.COMMON_ERROR, "未找到交易订单");
        }
        // 查询商户号
        BsMerPlatformNo platformNo = merPlatformNoService.getPlatformNo(orderRefund.getMerId(), PlatformTypeEnum.type3);
        if (platformNo == null) {
            throw ErrorHelp.genException(SysCode.System, ErrorCode.COMMON_ERROR, "未找到商户号");
        }

        Map<Object, Object> body = new LinkedHashMap<>();

        // 操作人员
        Map<Object, Object> param = new LinkedHashMap<>();
        param.put("REQUEST_SN", System.currentTimeMillis()+"");
        param.put("CUST_ID", platformNo.getPlatformNo());
        param.put("USER_ID", platformNo.getPlatformOperatorId());
        param.put("PASSWORD", platformNo.getPlatformOperatorPwd());
        param.put("TX_CODE", "5W1004");
        param.put("LANGUAGE", "CN");

        // 退款订单信息
        Map<String, String> info = new LinkedHashMap<>();
        info.put("MONEY", refundMoney.toString());
        info.put("ORDER", order.getOutTradeNo());
        info.put("REFUND_CODE", refundNo);
        param.put("TX_INFO", info);

        body.put("TX", param);

        // 组装XML参数
        String requestXml = "<?xml version=\"1.0\" encoding=\"GB2312\" standalone=\"yes\" ?>";
        requestXml += CCBUtils.mapToXml(body);

        BsTradeOrderMsg orderMsg = new BsTradeOrderMsg();
        orderMsg.setOutTradeNo(refundNo);
        orderMsg.setType(TradeOrderMsgTypeEnum.type1.getNumber());
        orderMsg.setRequestContent(requestXml);
        tradeOrderMsgService.editTradeOrderMsg(orderMsg);

        // 初始化证书
        String sRet = RequestProcess.initFileCert(
                platformNo.getPlatformNo(),
                platformNo.getPlatformOperatorId(),
                CommonSysConst.getSysConfig().getFile_url() + platformNo.getRefundCertUrl() ,
                platformNo.getRefundCertPwd(),
                CCBConfig.CONFIG_HOST
        );

        if ("".equals(sRet)) {
            String resultXml = RequestProcess.sendRequest(CCBConfig.HOST, requestXml);
            orderMsg.setResponseContent(resultXml);
            tradeOrderMsgService.editTradeOrderMsg(orderMsg);

            try {
                Map<String, Object> resultMap = CCBUtils.xml2map(resultXml);
                Map<String, Object> tx = (Map<String, Object>) MapUtils.getMap(resultMap, "TX");

                if (!MapUtils.getString(tx, "RETURN_CODE").equals("000000")) {
                    throw ErrorHelp.genException(SysCode.System, ErrorCode.COMMON_ERROR, MapUtils.getString(tx, "RETURN_MSG"));
                }

                Map<String, Object> txInfo = (Map<String, Object>) MapUtils.getMap(tx, "TX_INFO");
                orderRefund.setPayerAmount(new BigDecimal(MapUtils.getString(txInfo, "AMOUNT")));

            } catch (DocumentException e) {
                e.printStackTrace();
            }
            orderRefund.setRefundTime(new Date());
            orderRefund.setStatus(TradeOrderRefundStatusEnum.status2.getNumber());
            tradeOrderRefundService.editOrderRefund(orderRefund);

            order.setStatus(TradeOrderStatusEnum.status6.getNumber());
            tradeOrderService.editOrder(order);

            Map<String, Object> returnMap = new HashMap<>();
            returnMap.put("order", order);
            returnMap.put("orderRefund", orderRefund);
            return returnMap;
        }
        orderMsg.setResponseContent(sRet);
        tradeOrderMsgService.editTradeOrderMsg(orderMsg);

        throw ErrorHelp.genException(SysCode.System, ErrorCode.COMMON_ERROR, sRet);
    }

}
