package com.hai.config;

import com.alibaba.fastjson.JSONObject;
import com.hai.common.utils.DateUtil;
import com.hai.common.utils.RequestUtils;
import com.hai.dao.HighPayRecordMapper;
import com.hai.entity.HighPayRecord;
import com.wechat.pay.contrib.apache.httpclient.util.PemUtil;
import org.apache.commons.codec.binary.Base64;
import com.hai.common.pay.util.sdk.WXPayConstants;
import com.hai.common.utils.HttpsUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import java.io.*;
import java.math.BigDecimal;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.security.*;
import java.security.spec.PKCS8EncodedKeySpec;
import java.util.*;

/**
 * 银联分期
 * @author hurui
 */
@Component
public class UnionStagingPayConfig {

    @Resource
    private HighPayRecordMapper highPayRecordMapper;


    /**
     * 银联分期支付，H5预下单-标准
     * 文档地址： https://doc.eycard.cn/web/#/222?page_id=3183
     * @param prodTrace   产品流水	 可重复，记录订单生命周期，无特殊需求同交易流水号
     * @param orgTrace  订单号
     * @param payPrice  支付金额 【单位：分】
     * @return 响应信息
     * @throws Exception
     */
    public JSONObject advancePay(String prodTrace, String orgTrace, BigDecimal payPrice, String notifyUrl, HttpServletRequest request) throws Exception {
        Map<String,Object> paramMap = new HashMap<>();
        paramMap.put("orgId", CommonSysConst.getSysConfig().getUnionStagingPayOrgId());
        paramMap.put("orgMerCode", CommonSysConst.getSysConfig().getUnionStagingPayOrgMerCode());
        paramMap.put("orgTermNo", CommonSysConst.getSysConfig().getUnionStagingPayOrgTermNo());
        paramMap.put("prodTrace", prodTrace);
        paramMap.put("orgTrace", orgTrace);
        paramMap.put("prodCode", "ISYH");
        paramMap.put("signType", "RSA");

        JSONObject terminalInfo = new JSONObject();
        terminalInfo.put("terminalip", RequestUtils.getIpAddress(request));
        paramMap.put("terminalinfo", terminalInfo.toJSONString());

        Map<String, Object> bizDataMap = new HashMap<>();
        bizDataMap.put("transAmt", payPrice.multiply(new BigDecimal("100")).intValue());
        bizDataMap.put("openId", "-");
        bizDataMap.put("notifyUrl", notifyUrl);
        paramMap.put("bizData", bizDataMap);
        paramMap.put("sign", generateSign(bizDataMap));

        // 记录请求参数
        HighPayRecord payRecord = new HighPayRecord();
        payRecord.setCreateTime(new Date());
        payRecord.setPaySerialNo(prodTrace);
        payRecord.setResType(1);
        payRecord.setPayType(4);
        payRecord.setPayMoney(payPrice);
        payRecord.setBodyInfo(JSONObject.toJSONString(paramMap));
        highPayRecordMapper.insert(payRecord);

        JSONObject responseParam = HttpsUtils.doPost(CommonSysConst.getSysConfig().getUnionStagingPayUrl()+"cashier/apply/advancePay", paramMap, new HashMap<>());

        // 记录响应参数
        payRecord = new HighPayRecord();
        payRecord.setCreateTime(new Date());
        payRecord.setPaySerialNo(prodTrace);
        payRecord.setResType(3);
        payRecord.setPayType(4);
        payRecord.setPayMoney(payPrice);
        payRecord.setBodyInfo(responseParam.toString());
        highPayRecordMapper.insert(payRecord);
        return responseParam;
    }

    /**
     * 订单查询接口
     * @param orgTrace 订单号
     * @param oriOrgTrace 原机构交易流水号
     * @param prodCode 产品代码
     * @param oriBizDate 原交易日期
     * @return
     * @throws Exception
     */
    public static JSONObject query(String orgTrace, String oriOrgTrace,String prodCode,Date oriBizDate, HttpServletRequest request) throws Exception {
        Map<String,Object> paramMap = new HashMap<>();
        paramMap.put("orgId", CommonSysConst.getSysConfig().getUnionStagingPayOrgId());
        paramMap.put("orgMerCode", CommonSysConst.getSysConfig().getUnionStagingPayOrgMerCode());
        paramMap.put("orgTermNo", CommonSysConst.getSysConfig().getUnionStagingPayOrgTermNo());
        paramMap.put("orgTrace", orgTrace);
        paramMap.put("prodCode", "ISYH");
        paramMap.put("signType", "RSA");

        JSONObject terminalInfo = new JSONObject();
        terminalInfo.put("terminalip", RequestUtils.getIpAddress(request));
        paramMap.put("terminalinfo", terminalInfo.toJSONString());

        Map<String, Object> bizDataMap = new HashMap<>();
        bizDataMap.put("oriOrgTrace", oriOrgTrace);
        bizDataMap.put("oriBizDate", DateUtil.date2String(oriBizDate, "yyyyMMdd"));
        paramMap.put("bizData", bizDataMap);
        paramMap.put("sign", generateSign(bizDataMap));

        JSONObject responseParam = HttpsUtils.doPost(CommonSysConst.getSysConfig().getUnionStagingPayUrl()+"cashier/trade/query", paramMap, new HashMap<>());
        return responseParam;
    }

    /**
     * 分期交易查询
     * @param orgTrace 交易流水
     * @param oriOrgTrace 原机构交易流水号
     * @param prodCode 产品代码
     * @param oriBizDate 原交易日期
     * @return
     * @throws Exception
     */
    public static JSONObject queryStaging(String orgTrace, String oriOrgTrace, String prodCode,Date oriBizDate, HttpServletRequest request) throws Exception {
        Map<String,Object> paramMap = new HashMap<>();
        paramMap.put("orgId", CommonSysConst.getSysConfig().getUnionStagingPayOrgId());
        paramMap.put("orgMerCode", CommonSysConst.getSysConfig().getUnionStagingPayOrgMerCode());
        paramMap.put("orgTermNo", CommonSysConst.getSysConfig().getUnionStagingPayOrgTermNo());
        paramMap.put("orgTrace", orgTrace);
        paramMap.put("prodCode", "ISYH");
        paramMap.put("signType", "RSA");

        JSONObject terminalInfo = new JSONObject();
        terminalInfo.put("terminalip", RequestUtils.getIpAddress(request));
        paramMap.put("terminalinfo", terminalInfo.toJSONString());

        Map<String, Object> bizDataMap = new HashMap<>();
        bizDataMap.put("oriOrgTrace", oriOrgTrace);
        bizDataMap.put("oriBizDate", DateUtil.date2String(oriBizDate, "yyyyMMdd"));
        paramMap.put("bizData", bizDataMap);
        paramMap.put("sign", generateSign(bizDataMap));

        JSONObject responseParam = HttpsUtils.doPost(CommonSysConst.getSysConfig().getUnionStagingPayUrl()+"cashier/trade/queryStaging", paramMap, new HashMap<>());
        return responseParam;
    }

    /**
     * 交易退款
     * @param orgTrace
     * @param oriOrgTrace
     * @param transAmt
     * @param prodCode
     * @param oriBizDate
     * @return
     * @throws Exception
     */
    public static JSONObject standardRefund(String orgTrace, String oriOrgTrace, BigDecimal transAmt,String prodCode,Date oriBizDate, HttpServletRequest request) throws Exception {
        Map<String,Object> paramMap = new HashMap<>();
        paramMap.put("orgId", CommonSysConst.getSysConfig().getUnionStagingPayOrgId());
        paramMap.put("orgMerCode", CommonSysConst.getSysConfig().getUnionStagingPayOrgMerCode());
        paramMap.put("orgTermNo", CommonSysConst.getSysConfig().getUnionStagingPayOrgTermNo());
        paramMap.put("orgTrace", orgTrace);
        paramMap.put("prodCode", "ISYH");
        paramMap.put("signType", "RSA");

        JSONObject terminalInfo = new JSONObject();
        terminalInfo.put("terminalip", RequestUtils.getIpAddress(request));
        paramMap.put("terminalinfo", terminalInfo.toJSONString());

        Map<String, Object> bizDataMap = new HashMap<>();
        bizDataMap.put("oriOrgTrace", oriOrgTrace);
        bizDataMap.put("oriBizDate", DateUtil.date2String(oriBizDate, "yyyyMMdd"));
        bizDataMap.put("transAmt", transAmt.multiply(new BigDecimal("100")).intValue());
        paramMap.put("bizData", bizDataMap);
        paramMap.put("sign", generateSign(bizDataMap));

        JSONObject responseParam = HttpsUtils.doPost(CommonSysConst.getSysConfig().getUnionStagingPayUrl()+"cashier/trade/standardRefund", paramMap, new HashMap<>());
        return responseParam;
    }

    /**
     * 退货查询
     * @param orgTrace 交易流水
     * @param oriOrgTrace 原机构交易流水号
     * @param prodCode 产品代码
     * @param oriBizDate 原交易日期
     * @return
     * @throws Exception
     */
    public static JSONObject mposfindrefund(String orgTrace, String oriOrgTrace,String prodCode,Date oriBizDate, HttpServletRequest request) throws Exception {
        Map<String,Object> paramMap = new HashMap<>();
        paramMap.put("orgId", CommonSysConst.getSysConfig().getUnionStagingPayOrgId());
        paramMap.put("orgMerCode", CommonSysConst.getSysConfig().getUnionStagingPayOrgMerCode());
        paramMap.put("orgTermNo", CommonSysConst.getSysConfig().getUnionStagingPayOrgTermNo());
        paramMap.put("orgTrace", orgTrace);
        paramMap.put("prodCode", "ISYH");
        paramMap.put("signType", "RSA");

        JSONObject terminalInfo = new JSONObject();
        terminalInfo.put("terminalip", RequestUtils.getIpAddress(request));
        paramMap.put("terminalinfo", terminalInfo.toJSONString());

        Map<String, Object> bizDataMap = new HashMap<>();
        bizDataMap.put("oriOrgTrace", oriOrgTrace);
        paramMap.put("bizData", bizDataMap);
        paramMap.put("sign", generateSign(bizDataMap));
        JSONObject responseParam = HttpsUtils.doPost("https://t-wapi.bhecard.com:6111/ledger/mposfindrefund", paramMap, new HashMap<>());
        return responseParam;
    }

    /**
     * 参数排序
     * @param param
     * @return
     */
    private static String paramSort(final Map<String, Object> param) {
        Set<String> keySet = param.keySet();
        String[] keyArray = keySet.toArray(new String[keySet.size()]);
        Arrays.sort(keyArray);
        StringBuilder sb = new StringBuilder();
        for (String k : keyArray) {
            if (k.equals(WXPayConstants.FIELD_SIGN)) {
                continue;
            }
            if (StringUtils.isBlank(sb.toString())) {
                sb.append(k).append("=").append(param.get(k));
            } else {
                sb.append("&").append(k).append("=").append(param.get(k));
            }
        }
        return sb.toString();
    }

    /**
     * 生成签名
     * @param data
     * @return
     * @throws Exception
     */
    private static String generateSign(final Map<String, Object> data) throws IOException {
        String paramSort = paramSort(data);
        PrivateKey privateKey = PemUtil.loadPrivateKey(new FileInputStream("/home/project/wx_cert/BZ0002toORG000000000009.key"));
        String signStr = null;
        try {
            Signature sign = Signature.getInstance("SHA256withRSA");
            sign.initSign(privateKey);
            sign.update(paramSort.getBytes("utf-8"));
            signStr = java.util.Base64.getEncoder().encodeToString(sign.sign());
        } catch (SignatureException e) {
            e.printStackTrace();
        } catch (NoSuchAlgorithmException e) {
            e.printStackTrace();
        } catch (InvalidKeyException e) {
            e.printStackTrace();
        }
        return signStr;
    }

}
