package com.jeequan.jeepay.thirdparty.channel.sandpay;

import cn.hutool.core.date.DatePattern;
import cn.hutool.core.date.DateUtil;
import com.alibaba.fastjson.JSONObject;
import com.jeequan.jeepay.core.constants.CS;
import com.jeequan.jeepay.core.entity.PayOrder;
import com.jeequan.jeepay.core.entity.RefundOrder;
import com.jeequan.jeepay.core.model.context.MchAppConfigContext;
import com.jeequan.jeepay.core.model.params.sandpay.SandpayConfig;
import com.jeequan.jeepay.core.model.params.sandpay.SandpayNormalMchParams;
import com.jeequan.jeepay.core.utils.SpringBeansUtil;
import com.jeequan.jeepay.thirdparty.channel.sandpay.kits.CertUtil;
import com.jeequan.jeepay.thirdparty.channel.sandpay.kits.CryptoUtil;
import com.jeequan.jeepay.thirdparty.channel.sandpay.kits.HttpClient;
import com.jeequan.jeepay.thirdparty.channel.sandpay.kits.SDKUtil;
import com.jeequan.jeepay.thirdparty.service.ConfigContextQueryService;
import com.jeequan.jeepay.thirdparty.util.ChannelCertConfigKitBean;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.codec.binary.Base64;

import java.io.IOException;
import java.net.URLDecoder;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;

/**
 * 【杉德】支付通道工具包
 *
 * @author xiaoyu
 *
 * @date 2021/12/22 18:08
 */
@Slf4j
public class SandPayKit {

    /** 默认配置的是UTF-8 **/
    public static String encoding = "UTF-8";
    /** 签名类型,默认01-SHA1+RSA **/
    public static String signType = "01";
    /** 版本号 默认 1.0 **/
    public static String version = "1.0";

    //http连接超时时间
    public static int connectTimeout = 300000;
    //http响应超时时间
    public static int readTimeout = 600000;

    /**
     * 加载证书
     * @param mchAppConfigContext
     */
    public static void initCert(MchAppConfigContext mchAppConfigContext) {
        try {
            ChannelCertConfigKitBean channelCertConfigKitBean = SpringBeansUtil.getBean(ChannelCertConfigKitBean.class);

            ConfigContextQueryService configContextQueryService = SpringBeansUtil.getBean(ConfigContextQueryService.class);
            SandpayNormalMchParams mchParams = (SandpayNormalMchParams)configContextQueryService.queryNormalMchParams(mchAppConfigContext.getMchNo(), mchAppConfigContext.getAppId(), CS.IF_CODE.SANDPAY);
            if (mchParams == null) {
                log.error("杉德加载证书失败，商户配置不存在");
            }
            //加载证书
            CertUtil.init(mchAppConfigContext.getAppId(), channelCertConfigKitBean.getCertFilePath(mchParams.getPublicCert()), channelCertConfigKitBean.getCertFilePath(mchParams.getPrivateCert()), mchParams.getPrivatePassword());
        }catch (Exception e) {
            log.error("杉德加载证书异常{}", e.getMessage());
        }

    }

    /**
     * 公共请求头参数
     * @param header
     * @param method
     * @param productId
     * @param mchAppConfigContext
     */
    public static void setReqHeader(JSONObject header, String method, String productId, MchAppConfigContext mchAppConfigContext) {
        ConfigContextQueryService configContextQueryService = SpringBeansUtil.getBean(ConfigContextQueryService.class);
        SandpayNormalMchParams mchParams = (SandpayNormalMchParams)configContextQueryService.queryNormalMchParams(mchAppConfigContext.getMchNo(), mchAppConfigContext.getAppId(), CS.IF_CODE.SANDPAY);

        // 加载证书
        initCert(mchAppConfigContext);

        // 版本号
        header.put("version", version);
        // 接口名称
        header.put("method", method);
        // 产品编码
        header.put("productId", productId);
        // 商户号
        header.put("mid", mchParams.getMid());
        // 接入类型 1-普通商户 2-平台商户
        header.put("accessType", "1");
        // 渠道类型：07-互联网   08-移动端
        header.put("channelType", "07");
        // 请求时间
        header.put("reqTime", DateUtil.format(new Date(), DatePattern.PURE_DATETIME_PATTERN));
    }

    /**
     * 下单请求参数
     * @param body
     * @param payOrder
     * @param notifyUrl
     * @param returnUrl
     */
    public static void setPayBody(JSONObject body, PayOrder payOrder, String notifyUrl, String returnUrl) {

        // 支付订单号
        body.put("orderCode", payOrder.getPayOrderId());
        // 订单金额
        body.put("totalAmount", String.format("%12d", payOrder.getFindAmt()).replace(" ", "0"));
        // 订单标题
        body.put("subject", payOrder.getSubject());
        // 订单描述
        body.put("body", payOrder.getBody());
        // 订单超时时间
        body.put("txnTimeOut", "");
        // 客户端IP
        body.put("clientIp", payOrder.getClientIp());
        // 限定支付方式	送1-限定不能使用贷记卡送	4-限定不能使用花呗	送5-限定不能使用贷记卡+花呗
        body.put("limitPay", "");
        // 异步通知地址
        body.put("notifyUrl", notifyUrl);
        // 前台通知地址
        body.put("frontUrl", returnUrl);
        // 商户门店编号
        body.put("storeId", "");
        // 商户终端编号
        body.put("terminalId", "");
        // 操作员编号
        body.put("operatorId", "");
        // 清算模式
        body.put("clearCycle", "");
        // 分账信息
        body.put("royaltyInfo", "");
        // 风控信息域
        body.put("riskRateInfo", "");
        // 业务扩展参数
        body.put("bizExtendParams", "");
        // 商户扩展参数
        body.put("merchExtendParams", "");
        // 扩展域
        body.put("extend", "");
        // 分账域
        body.put("accsplitInfo", "");
//
//        JSONObject payExtra=new JSONObject();
//        payExtra.put("userId", "otvxTs_JZ6SEiP0imdhpi50fuSZg");					  //付款支付宝用户号

//        body.put("payMode", "sand_alipay");										  //支付模式
//        body.put("payExtra", payExtra.toJSONString());							  //支付扩展域
    }

    /**
     * 退款请求参数
     */
    public static void setRefundBody(JSONObject body, RefundOrder refundOrder, PayOrder payOrder, String notifyUrl) {
        // 商户订单号
        body.put("orderCode", refundOrder.getRefundOrderId());
        // 原商户订单号
        body.put("oriOrderCode", payOrder.getPayOrderId());
        // 退货金额
        body.put("refundAmount", String.format("%12d", refundOrder.getRefundAmount()).replace(" ", "0"));
        // 异步通知地址
        body.put("notifyUrl", notifyUrl);
        // 退货原因
        body.put("refundReason", "退货测试");
        // 扩展域
        body.put("extend", "");
    }


    public static JSONObject requestServer(JSONObject body, String reqAddr, String method, String productId, MchAppConfigContext mchAppConfigContext) {

        JSONObject header = new JSONObject();
        setReqHeader(header, method, productId, mchAppConfigContext);

        Map<String, String> reqMap = new HashMap<String, String>();
        JSONObject reqJson = new JSONObject();
        reqJson.put("head", header);
        reqJson.put("body", body);
        String reqStr=reqJson.toJSONString();
        String reqSign;
        // 签名
        try {
            reqSign = new String(Base64.encodeBase64(CryptoUtil.digitalSign(reqStr.getBytes(encoding), CertUtil.getPrivateKey(mchAppConfigContext.getAppId()), "SHA1WithRSA")));
        } catch (Exception e) {
            log.error(e.getMessage());
            return null;
        }
        //整体报文格式
        reqMap.put("charset", encoding);
        reqMap.put("data", reqStr);
        reqMap.put("signType", signType);
        reqMap.put("sign", reqSign);
        reqMap.put("extend", "");

        String result;
        try {
            log.info("请求报文：\n, {}", JSONObject.toJSONString(reqJson));
            log.info("请求报文：\n, {}", JSONObject.toJSONString(reqSign));
            result = HttpClient.doPost(SandpayConfig.REQ_URL + reqAddr, reqMap, connectTimeout, readTimeout);
            log.info("响应报文：\n, {}", result);
            result = URLDecoder.decode(result, encoding);
        } catch (IOException e) {
            log.error(e.getMessage());
            return null;
        }

        Map<String, String> respMap = SDKUtil.convertResultStringToMap(result);
        String respData = respMap.get("data");
        String respSign = respMap.get("sign");

        // 验证签名
        boolean valid;
        try {
            valid = CryptoUtil.verifyDigitalSign(respData.getBytes(encoding), Base64.decodeBase64(respSign), CertUtil.getPublicKey(mchAppConfigContext.getAppId()),"SHA1WithRSA");
            if(!valid) {
                log.error("verify sign fail.");
                return null;
            }
            log.info("verify sign success");
            JSONObject respJson = JSONObject.parseObject(respData);
            if(respJson!=null) {
                log.info("响应码：[{}]", respJson.getJSONObject("head").getString("respCode"));
                log.info("响应描述：[{}]", respJson.getJSONObject("head").getString("respMsg"));
                log.info("响应报文：\n, {}", JSONObject.toJSONString(respJson,true));
            }else {
                log.error("服务器请求异常！！！");
            }
            return respJson;

        }  catch (Exception e) {
            log.error(e.getMessage());
            return null;
        }
    }


}
