package com.yonge.cooleshow.biz.dal.sdk;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.alibaba.fastjson.JSONPath;
import com.yonge.cooleshow.common.entity.HttpResponseResult;
import com.yonge.toolset.base.exception.ThirdpartyException;
import com.yonge.toolset.thirdparty.lingxinpay.Md5EncryptUtils;
import com.yonge.toolset.thirdparty.lingxinpay.RSA;
import com.yonge.toolset.utils.date.DateUtil;
import com.yonge.toolset.utils.http.HttpUtil;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;

import java.io.IOException;
import java.math.BigDecimal;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;

/**
 * @author: cy
 * @date: 2022/5/9 11:24
 */
@Service
public class WithdrawSdk {
    private static final Logger logger = LoggerFactory.getLogger(WithdrawSdk.class);

    // 商户号
    @Value("${withdraw.memberNo}")
    private String memberNo;
    // 模板协议号
    @Value("${withdraw.contractNo}")
    private String contractNo;
    @Value("${withdraw.md5Key}")
    private String md5Key;
    @Value("${withdraw.publicKey}")
    private String publicKey;
    //签署协议回调地址
    @Value("${withdraw.contractNotifyUrl}")
    private String contractNotifyUrl;
    //签署协议url
    @Value("${withdraw.contractApiUrl}")
    private String contractApiUrl;
    //结算回调地址
    @Value("${withdraw.notifyUrl}")
    private String notifyUrl;
    //结算第三方url
    @Value("${withdraw.apiUrl}")
    private String apiUrl;
    @Value("${withdraw.privateKey}")
    private String privateKey;

    /**
     * 签署协议
     *
     * @param realName 真实姓名
     * @param idcard   身份证号
     * @param mobileNo 手机号
     * @param serialNo 唯一标识
     * @return
     */
    public boolean signContract(String realName, String idcard, String mobileNo, String serialNo) {
        JSONObject jsonObject = new JSONObject();
        jsonObject.put("signType", "RSA");
        jsonObject.put("service", "bpotop.zx.contract");
        jsonObject.put("charset", "UTF-8");
        jsonObject.put("version", "1.0");
        jsonObject.put("createTime", DateUtil.format(new Date(), DateUtil.DEFAULT_PATTERN));

        jsonObject.put("outMemberNo", memberNo);// 公司商户号
        jsonObject.put("serialNo", serialNo);// 流水号（商户唯一标识）
        jsonObject.put("contractNo", contractNo);// 合同模板号
        jsonObject.put("notifyUrl", contractNotifyUrl);// 返回结果异步通知地址

        JSONObject jsonObject2 = new JSONObject();
        jsonObject2.put("name", realName);
        jsonObject2.put("phone", mobileNo);
        jsonObject2.put("identityId", idcard);
        jsonObject2.put("citizenship", "0");
        jsonObject2.put("signTime", DateUtil.format(new Date(), DateUtil.DEFAULT_PATTERN));
        jsonObject.put("contractSignInfo", jsonObject2);
        String jsonStr = JSONObject.toJSONString(jsonObject);

        try {
            String encryptStr = RSA.encryptPub(jsonStr, publicKey);
            jsonObject.put("sign", encryptStr);
        } catch (Exception e) {
            logger.error("加密失败", e);
            throw new ThirdpartyException("加密失败：{}", e.getMessage());
        }
        logger.info("[合同签署]请求参数：{}", jsonObject.toJSONString());
        try {
            String s = HttpUtil.postForHttp(contractApiUrl + "/api/signContract", jsonObject.toJSONString(), null);
            logger.info("请求[合同签署]响应参数：{}", s);

            jsonObject = JSONObject.parseObject(s);
            if (StringUtils.equals(jsonObject.getString("return_code"), "T")) {
                return true;
            }else if(!StringUtils.isEmpty(jsonObject.getString("content"))){
                throw new ThirdpartyException("合同签署失败：{}", jsonObject.getString("content"));
            }else{
                throw new ThirdpartyException("合同签署失败：{}", jsonObject.getString("return_message"));
            }
        } catch (IOException e) {
            logger.error("请求[合同签署]接口报错", e);
            throw new ThirdpartyException("请求[合同签署]接口报错：{}", e.getMessage());
        }
    }

    /**
     * 查询协议
     *
     * @param serialNo 唯一标识
     * @return
     */
    public String querySignContractResult(String serialNo) {
        JSONObject jsonObject = new JSONObject();
        jsonObject.put("outMemberNo", memberNo);
        jsonObject.put("serialNo", serialNo);
        jsonObject.put("contractNo", contractNo);
        try {
            String encryptStr = RSA.encryptPub(JSONObject.toJSONString(jsonObject), publicKey);
            jsonObject.put("sign", encryptStr);
        } catch (Exception e) {
            logger.error("加密失败", e);
            throw new ThirdpartyException("加密失败：{}", e.getMessage());
        }
        jsonObject.put("signType", "RSA");
        jsonObject.put("service", "bpotop.zx.contract");
        jsonObject.put("charset", "UTF-8");
        jsonObject.put("version", "1.0");
        jsonObject.put("createTime", DateUtil.format(new Date(), DateUtil.DEFAULT_PATTERN));
        try {
            String s = HttpUtil.postForHttp(contractApiUrl + "/api/queryContractInfo", jsonObject.toJSONString(), null);
            logger.info("[合同查询]响应参数：{}", s);

            jsonObject = JSONObject.parseObject(s);
            if (StringUtils.equals(jsonObject.getString("return_code"), "T")) {
                return (String) JSONPath.eval(jsonObject, "$.content.contractUrl");
            }
        } catch (IOException e) {
            logger.error("请求[合同查询]接口报错", e);
        }
        return null;
    }

    /**
     * 单笔结算
     *
     * @param outerOrderNo  商户唯一订单号
     * @param name          收款方姓名（银行预留姓名等）
     * @param mobile        收款方电话
     * @param certificateNo 收款方身份证号
     * @param predictAmount 应发金额（单位为：分，范围： 1~10000000000）
     * @param payAccount    收款方账号（银行卡号/支付宝账号 /open_id）以实际业务为准
     * @param remark        备注（扩展字段） 只针对测试环境：只要参数合规都会返回交易成功，如果想要模拟交易失败，该字段值中含有“失败”二字即会失败。
     * @return
     */
    public HttpResponseResult<Boolean> withdraw(String outerOrderNo, String name, String mobile, String certificateNo, Integer predictAmount,
                                                String payAccount, String remark) {
        Map<String, Object> map = new HashMap<>();
        map.put("outMemberNo", memberNo);
        map.put("outerOrderNo", outerOrderNo);
        map.put("name", name);
        map.put("certificateNo", certificateNo);
        map.put("predictAmount", predictAmount);
        String signs = Md5EncryptUtils.sign(map, md5Key);

        map.put("charset", "UTF-8");
        map.put("mobile", mobile);
        map.put("version", "1.1");
        map.put("service", "bpotop.zx.pay.order");
        map.put("Md5Key", signs);
        map.put("notifyUrl", notifyUrl);
        map.put("cardType", "DC");
        map.put("salaryType", "4");
        map.put("projectName", name + "-" + DateUtil.getStrDate());
        map.put("payType", "1");
        map.put("cardAttribute", "C");
        map.put("payAccount", payAccount);
        String jsonStr = JSONObject.toJSONString(map);
        logger.info("单笔请求请求参数：{}", JSONObject.toJSONString(jsonStr));

        //签名
        JSONObject mapParam = new JSONObject();
        try {
            //使用公钥加密
            String encryptStr = RSA.encryptPub(jsonStr, publicKey);
            mapParam.put("outMemberNo", memberNo);
            mapParam.put("signType", "RSA");
            mapParam.put("sign", encryptStr);
        } catch (Exception e) {
            logger.info("加密失败：{}", e);
        }

        //发送
        try {
            String resultJsonStr = HttpUtil.postForHttp(apiUrl + "/bpotop_trade/single", JSONObject.toJSONString(mapParam), null);
            logger.info("单笔请求返回参数：{}", resultJsonStr);

            Map<String, Object> mapTypes = JSON.parseObject(resultJsonStr);
            String returnCode = String.valueOf(mapTypes.get("return_code"));
            if (returnCode.equals("T")) {
                return HttpResponseResult.succeed(true);
            } else {
                if(null != mapTypes.get("content")){
                    return HttpResponseResult.failed(String.valueOf(mapTypes.get("content")));
                }else{
                    return HttpResponseResult.failed(String.valueOf(mapTypes.get("return_message")));
                }
            }
        } catch (IOException e) {
            logger.info("发送失败：{}", e);
        }
        return HttpResponseResult.failed("结算失败");
    }

    /**
     * 查询接口
     *
     * @param outerOrderNo 商户唯一订单号
     * @throws Exception
     */
    public String query(String outerOrderNo) {
        Map<String, Object> requestMap = new HashMap<>();
        requestMap.put("outMemberNo", memberNo);
        requestMap.put("outerOrderNo", outerOrderNo);
        requestMap.put("service", "bpotop.zx.pay.order");
        requestMap.put("version", "1.0");
        requestMap.put("signType", "RSA");
        requestMap.put("charset", "UTF-8");
        String jsonStr = JSONObject.toJSONString(requestMap);
        String encryptStr = null;
        try {
            encryptStr = RSA.encryptPub(jsonStr, publicKey);
        } catch (Exception e) {
            throw new ThirdpartyException("加密失败：{}", e.getMessage());
        }

        Map<String, Object> requestMap2 = new HashMap<>();
        requestMap2.put("outMemberNo", memberNo);
        requestMap2.put("sign", encryptStr);
        logger.info("单笔查询请求参数：{}", JSONObject.toJSONString(requestMap2));
        String resultJsonStr = null;
        try {
            resultJsonStr = HttpUtil.postForHttp(apiUrl + "/bpotop_trade/order_query", JSONObject.toJSONString(requestMap2), null);
            logger.info("单笔查询响应参数：{}", resultJsonStr);
            return resultJsonStr;
        } catch (IOException e) {
            e.printStackTrace();
        }
        return null;
    }

    /**
     * 查询商户余额（单位为：分，范围：1~10000000000）
     *
     * @return
     */
    public BigDecimal balanceQuery() {
        Map<String, Object> requestMap = new HashMap<>();
        requestMap.put("outMemberNo", memberNo);
        requestMap.put("charset", "UTF-8");
        requestMap.put("service", "bpotop.zx.pay.order");
        requestMap.put("version", "2.0");
        requestMap.put("signType", "RSA");

        String jsonStr = JSONObject.toJSONString(requestMap);
        String encryptStr = null;
        try {
            encryptStr = RSA.encryptPub(jsonStr, publicKey);
            requestMap.put("sign", encryptStr);
            logger.info("查询余额请求参数：{}", requestMap);
        } catch (Exception e) {
            throw new ThirdpartyException("加密失败：{}", e.getMessage());
        }
        String resultJsonStr = null;
        try {
            resultJsonStr = HttpUtil.postForHttp(apiUrl + "/bpotop_trade/balance_query", JSONObject.toJSONString(requestMap), null);
            logger.info("查询余额响应参数(未解析)：{}", resultJsonStr);
            JSONObject resData = JSONObject.parseObject(resultJsonStr);
            if("100".equals(resData.getString("code"))){
                String sign = resData.getJSONObject("details").getJSONObject("data").getString("sign");
                String decryptStr = RSA.decryptPri(sign, privateKey);
                logger.info("查询余额响应参数(已解析)：{}", decryptStr);
                Map stringToMap = JSONObject.parseObject(decryptStr);
                return new BigDecimal(String.valueOf(stringToMap.get("balance"))).divide(new BigDecimal("100"));
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return BigDecimal.ZERO;
    }
}
