package com.kmall.common.utils.wechat.wxglobal;

import com.alibaba.druid.support.json.JSONUtils;
import com.alibaba.druid.support.logging.Log;
import com.alibaba.druid.support.logging.LogFactory;
import com.kmall.common.service.pay.global.CommonWxGlobalPayPropertiesBuilder;
import com.kmall.common.utils.*;
import com.kmall.common.utils.pingan.properties.PinganPayPropertiesBuilder;
import com.kmall.common.utils.pingan.utils.HttpUtil;
import com.kmall.common.utils.pingan.utils.HttpsUtil;
import com.kmall.common.utils.wechat.*;
import com.kmall.common.utils.wechat.wxglobal.dto.*;
import net.sf.json.JSONObject;
import org.apache.commons.lang.StringUtils;
import org.apache.http.HttpEntity;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
import org.apache.http.entity.ContentType;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.util.EntityUtils;

import java.io.IOException;
import java.math.BigDecimal;
import java.math.MathContext;
import java.net.URLEncoder;
import java.text.SimpleDateFormat;
import java.util.*;

/**
 * <p>Title: 微信退款工具类</p>
 * <p>Description: 微信退款工具类，通过充值客户端的不同初始化不同的工具类，得到相应微信退款相关的appid和muchid</p>
 *
 * @author xubo
 * @date 2017年6月6日  下午5:05:03
 */
public class WechatGlobalUtil {
    private static Log logger = LogFactory.getLog(WechatGlobalUtil.class);
    private static final String EMPTY = "";
    private static final String URL_PARAM_CONNECT_FLAG = "\n";
    private static final String POST = "POST";
    private static final String GET = "GET";

    /**
     * 菜单类型
     *
     * @author Scott
     * @email
     * @date 2016年11月15日 下午1:24:29
     */
    public enum WXTradeState {
        /**
         * 支付成功
         */
        SUCCESS("SUCCESS", "支付成功"),
        /**
         * 转入退款
         */
        REFUND("REFUND", "转入退款"),

        /**
         * 未支付
         */
        NOTPAY("NOTPAY", "未支付"),

        /**
         * 已关闭
         */
        CLOSED("CLOSED", "已关闭"),

        /**
         * 已撤销（付款码支付）
         */
        REVOKED("REVOKED", "已撤销"),

        /**
         * 用户支付中（付款码支付）
         */
        USERPAYING("USERPAYING", "用户支付中"),

        /**
         * 支付失败（付款码支付）
         */
        PAYERROR("PAYERROR", "支付失败");

        private String code;
        private String codeZn;

        private WXTradeState(String code, String codeZn) {
            this.code = code;
            this.codeZn = codeZn;
        }

        public String getCode() {
            return code;
        }

        public String getCodeZn() {
            return codeZn;
        }
    }

    /**
     * 统一下单
     * @param out_trade_no 商户订单号
     * @param body 商品描述
     * @param actual_price 实付金额
     * @param openId 微信openId
     * @return
     */
    public static WechatGlobalQueryApiResult unifiedOrder(String out_trade_no,String nonceStr,String body,BigDecimal actual_price,String openId) {
        Map<Object, Object> param = new HashMap<>();
        param.put("appid", CommonWxGlobalPayPropertiesBuilder.instance().getAppId());
        param.put("mchid", CommonWxGlobalPayPropertiesBuilder.instance().getMchId());// 商家账号
        param.put("out_trade_no", out_trade_no);// 商户订单编号
        //param.put("merchant_category_code","5499");// 商户行业编码 5499各类食品店及专门食品零售店
        param.put("merchant_category_code","5977");// 商户行业编码 5977化妆品商店

        Map<Object, Object> payerParam = new TreeMap<>();
        payerParam.put("openid",openId);
        JSONObject payerobj = JSONObject.fromObject(payerParam);
        param.put("payer",payerobj);
        param.put("trade_type", CommonWxGlobalPayPropertiesBuilder.instance().getTradeType());// 交易类型APP
        //支付金额
        Map<Object, Object> amountParam = new TreeMap<>();
        amountParam.put("total", Math.round(actual_price.multiply(Constant.ONE_HUNDRED).doubleValue()));// 消费金额
        amountParam.put("currency", CommonWxGlobalPayPropertiesBuilder.instance().getFeeType());//标价币种
        JSONObject amountObj = JSONObject.fromObject(amountParam);
        param.put("amount",amountObj);
        param.put("notify_url", CommonWxGlobalPayPropertiesBuilder.instance().getNotifyUrl());// 回调地址
        if(StringUtils.isNotEmpty(body)) {
            param.put("description", body);// 商品描述
        }else{
            param.put("description", "中网国际跨境商城-支付");// 商品描述
        }
        JSONObject paramObj = JSONObject.fromObject(param);
        String data =  paramObj.toString();
        logger.debug("*******统一下单（WX Request：" + data);

        String reponseXml = sendPostToWxCommon(CommonWxGlobalPayPropertiesBuilder.instance().getUniformorder(),nonceStr,data);
        logger.debug("*******统一下单（WX Response：" + reponseXml);

        JSONObject jsonObject= JSONObject.fromObject(reponseXml);
        WechatGlobalQueryApiResult result=(WechatGlobalQueryApiResult)JSONObject.toBean(jsonObject, WechatGlobalQueryApiResult.class);

        return result;
    }

    /**
     * 微信境外查询订单
     * @param
     * @return
     */
    public static WechatGlobalUniformNotifyResult wxOrderQuery(String out_trade_no) {
        String orderQueryUrl = String.format(CommonWxGlobalPayPropertiesBuilder.instance().getOrderquery(),
                out_trade_no,
                CommonWxGlobalPayPropertiesBuilder.instance().getMchId());

        String reponseXml = sendGetToWxCommon(orderQueryUrl);

        JSONObject jsonObject= JSONObject.fromObject(reponseXml);
        WechatGlobalUniformNotifyResult result=(WechatGlobalUniformNotifyResult)JSONObject.toBean(jsonObject, WechatGlobalUniformNotifyResult.class);
        return result;
    }
    /**
     * 微信境外根据支付单查询订单
     * @param
     * @return
     */
    public static WechatGlobalUniformNotifyResult wxOrderQueryByTransactionId(String payTransactionId) {
        String orderQueryUrl = String.format(CommonWxGlobalPayPropertiesBuilder.instance().getOrderqueryById(),
                payTransactionId,
                CommonWxGlobalPayPropertiesBuilder.instance().getMchId());

        String reponseXml = sendGetToWxCommon(orderQueryUrl);

        JSONObject jsonObject= JSONObject.fromObject(reponseXml);
        WechatGlobalUniformNotifyResult result=(WechatGlobalUniformNotifyResult)JSONObject.toBean(jsonObject, WechatGlobalUniformNotifyResult.class);
        return result;
    }

    /**
     * 微信查询汇率
     * @param out_trade_no
     * @return
     */
    public static WechatGlobalQueryRateResult wxQueryexchagerate(String out_trade_no) {
        //初始化请求微信服务器的配置信息包括appid密钥等
        //构建请求参数
        Map<Object, Object> params = new HashMap<Object, Object>();
        params.put("appid", CommonWxGlobalPayPropertiesBuilder.instance().getAppId());//微信分配的公众账号ID（企业号corpid即为此appId）
        params.put("mch_id", CommonWxGlobalPayPropertiesBuilder.instance().getMchId());//微信支付分配的商户号
        params.put("fee_type", CommonWxGlobalPayPropertiesBuilder.instance().getFeeType());//外币币种
        params.put("date", DateUtils.format(new Date(),DateUtils.DATE_TIME_PATTERN_YYYY_MM_DD));//格式为yyyyMMdd
        //签名前必须要参数全部写在前面
        params.put("sign", WechatUtil.arraySign(params, CommonWxGlobalPayPropertiesBuilder.instance().getPaySignKey()));//签名
        String mapToXml = MapUtils.convertMap2Xml(params);
        //请求微信
        String reponseXml = WechatUtil.sendSSLPostToWx(mapToXml, WechatConfig.getSslcsf(), CommonWxGlobalPayPropertiesBuilder.instance().getRatequery());

        WechatGlobalQueryRateResult result =
                (WechatGlobalQueryRateResult) XmlUtil.xmlStrToBean(reponseXml, WechatGlobalQueryRateResult.class);
        return result;
    }

    /**
     * 微信境外申请退款
     * @param out_trade_no 商户订单编号
     * @param orderMoney 订单总金额
     * @param refundMoney 申请退款金额
     * @return
     */
    public static WechatGlobalRefundApiResult wxRefund(String out_trade_no, Double orderMoney, Double refundMoney) {
        //初始化请求微信服务器的配置信息包括appid密钥等
        //转换金钱格式
        BigDecimal bdOrderMoney = new BigDecimal(orderMoney, MathContext.DECIMAL32);
        BigDecimal bdRefundMoney = new BigDecimal(refundMoney, MathContext.DECIMAL32);
        //构建请求参数
        Map<Object, Object> params = new HashMap<Object, Object>();
        params.put("appid", CommonWxGlobalPayPropertiesBuilder.instance().getAppId());//微信分配的公众账号ID（企业号corpid即为此appId）
        params.put("mchid", CommonWxGlobalPayPropertiesBuilder.instance().getMchId());//微信支付分配的商户号
        params.put("out_trade_no", out_trade_no);//商户传给微信的订单号
        params.put("out_refund_no", String.valueOf(System.currentTimeMillis()));//商户系统内部的退款单号，商户系统内部唯一，同一退款单号多次请求只退一笔

        Map<Object, Object> amountParam = new TreeMap<>();
        amountParam.put("refund", Math.round(bdRefundMoney.multiply(Constant.ONE_HUNDRED).doubleValue()));//退款总金额，订单总金额，单位为分，只能为整数
        amountParam.put("total", Math.round(bdOrderMoney.multiply(Constant.ONE_HUNDRED).doubleValue()));//订单总金额，单位为分，只能为整数
        amountParam.put("currency", CommonWxGlobalPayPropertiesBuilder.instance().getFeeType());//标价币种
        JSONObject amountObj = JSONObject.fromObject(amountParam);
        params.put("amount",amountObj);

        params.put("notify_url", CommonWxGlobalPayPropertiesBuilder.instance().getRefundNotifyUrl());
        String nonceStr = CharUtil.getRandomString(16).toUpperCase();

        JSONObject paramObj = JSONObject.fromObject(params);
        String data =  paramObj.toString();
        logger.debug("*******申请退款（WX Request：" + data);
        String reponseXml = sendPostToWxCommon(CommonWxGlobalPayPropertiesBuilder.instance().getRefundUrl(), nonceStr, data);
        logger.debug("*******申请退款（WX Response：" + reponseXml);

        JSONObject jsonObject= JSONObject.fromObject(reponseXml);
        WechatGlobalRefundApiResult result= (WechatGlobalRefundApiResult)JSONObject.toBean(jsonObject, WechatGlobalRefundApiResult.class);

        result.setOut_refund_no((String) params.get("out_refund_no"));
        return result;
    }
    /**
     * 微信境外查询退款
     * @param
     * @return
     */
    public static WechatGlobalRefundQueryResult wxRefundquery(String out_trade_no) {
        String refundQueryUrl = String.format(CommonWxGlobalPayPropertiesBuilder.instance().getRefundqueryUrl(),
                out_trade_no,
                CommonWxGlobalPayPropertiesBuilder.instance().getMchId());
        String reponseXml = sendGetToWxCommon(refundQueryUrl);
        JSONObject obj = JSONObject.fromObject(reponseXml);
        Map<String, Class<WechatGlobalRefundQueryDto>> refundQueryMap = new HashMap<String, Class<WechatGlobalRefundQueryDto>>();
        refundQueryMap.put("data", WechatGlobalRefundQueryDto.class);
        WechatGlobalRefundQueryResult result = (WechatGlobalRefundQueryResult) JSONObject.toBean(obj, WechatGlobalRefundQueryResult.class, refundQueryMap);
        return result;
    }

    /**
     * get加密以及组装请求微信认证头返回json串
     * @param orderQueryUrl
     * @return
     */
    private static String sendGetToWxCommon(String orderQueryUrl){
        long timestamp = System.currentTimeMillis() / 1000L;
        //去除域名
        String urlStr = orderQueryUrl.replace(CommonWxGlobalPayPropertiesBuilder.instance().getDomainname(),"");
        String nonceStr = CharUtil.getRandomString(16).toUpperCase();
        //组装待签名串
        String signStr = toSignStr(GET, urlStr, nonceStr, timestamp, "");
        //计算签名值
        String signature = SignUtil.signData(signStr, CommonWxGlobalPayPropertiesBuilder.instance().getCertName(), CommonWxGlobalPayPropertiesBuilder.instance().getMchId());
        //组装http认证头签名信息
        String authorization = authorization(CommonWxGlobalPayPropertiesBuilder.instance().getMchId(), nonceStr, signature,
                timestamp, CommonWxGlobalPayPropertiesBuilder.instance().getSerialno());
        //请求
        String reponseXml = sendSSLGetToWx(authorization,null, orderQueryUrl);
        return reponseXml;
    }
    /**
     * post加密以及组装请求微信认证头返回json串
     * @param orderQueryUrl
     * @return
     */
    private static String sendPostToWxCommon(String orderQueryUrl,String nonceStr,String data){
        long timestamp = System.currentTimeMillis() / 1000L;
        //去除域名
        String urlStr = orderQueryUrl.replace(CommonWxGlobalPayPropertiesBuilder.instance().getDomainname(),"");
        //组装待签名串
        String signStr = toSignStr(POST, urlStr, nonceStr, timestamp, data);
        //计算签名值
        String signature = SignUtil.signData(signStr,CommonWxGlobalPayPropertiesBuilder.instance().getCertName(),CommonWxGlobalPayPropertiesBuilder.instance().getMchId());
        //组装http认证头签名信息
        String authorization = authorization(CommonWxGlobalPayPropertiesBuilder.instance().getMchId(), nonceStr, signature,
                timestamp, CommonWxGlobalPayPropertiesBuilder.instance().getSerialno());
        //请求
        String reponseXml = sendSSLPostToWx(data, authorization,WechatConfig.getSslcsf(), orderQueryUrl);
        return reponseXml;
    }

    public static String sendRefundQerutySSLPostToWx(String mapToXml, SSLConnectionSocketFactory sslcsf) {
        logger.debug("*******退款查询（WX Request：" + mapToXml);
        String xmlStr = WechatUtil.sendSSLPostToWx(mapToXml, sslcsf, CommonWxGlobalPayPropertiesBuilder.instance().getRefundqueryUrl());
        logger.debug("*******退款查询（WX Response：" + xmlStr);
        return xmlStr;
    }

    private static String toSignStr(String requestType, String url,String nonce_str,long timestamp, String data){
        logger.debug("******组装待签名串开始*****timestamp："+timestamp+"；nonce_str："+nonce_str+"；url："+url+"；data："+data);
        String signStr = requestType + URL_PARAM_CONNECT_FLAG + url + URL_PARAM_CONNECT_FLAG + timestamp + URL_PARAM_CONNECT_FLAG
                + nonce_str + URL_PARAM_CONNECT_FLAG + data + URL_PARAM_CONNECT_FLAG;
        logger.debug("******组装待签名串结束*****signStr："+signStr);
        return signStr;
    }

    private static String authorization(String mchid,String nonce_str,String signature,long timestamp,String serial_no){
        logger.debug("******mchid："+mchid+"；nonce_str："+nonce_str+"；signature："+signature+"；timestamp："+timestamp+"；serial_no："+serial_no);
        String authorizationStr = "WECHATPAY2-SHA256-RSA2048 mchid=\""+mchid+"\",nonce_str=\""+nonce_str+"\",signature=\""+
                signature+"\",timestamp=\""+timestamp+"\",serial_no=\""+serial_no+"\"";
        logger.debug("******authorization："+authorizationStr);
        return authorizationStr;
    }
    /**
     * 请求微信https
     **/
    public static String sendSSLPostToWx(String mapToXml,String authorization, SSLConnectionSocketFactory sslcsf, String requestUrl) {
        HttpPost httPost = new HttpPost(requestUrl);
        httPost.addHeader("Host", "api.mch.weixin.qq.com");
        httPost.addHeader("Accept", "application/json");
        httPost.addHeader("Connection", "close");
        httPost.addHeader("User-Agent", "curl/7.54.0");
        httPost.addHeader("Content-Type", "application/json");
        httPost.addHeader("Authorization", authorization);
        httPost.setEntity(new StringEntity(mapToXml, ContentType.APPLICATION_JSON));

        CloseableHttpClient httpClient = null;
        if (sslcsf != null) {
            httpClient = HttpClients.custom().setSSLSocketFactory(sslcsf).build();
        } else {
            httpClient = HttpClients.createDefault();
        }

        CloseableHttpResponse response = null;
        try {
            response = httpClient.execute(httPost);
            HttpEntity entity = response.getEntity();
            String xmlStr = EntityUtils.toString(entity, "UTF-8");
            System.out.println("xmlStr:"+xmlStr);
            return xmlStr;
        } catch (Exception e) {
            logger.error(e.getMessage(), e);
            return null;
        } finally {
            try {
                if (response != null) {
                    response.close();
                }
            } catch (IOException e) {
                logger.error(e.getMessage(), e);
            }
        }
    }

    /**
     * get请求
     * @param authorization
     * @param sslcsf
     * @param requestUrl
     * @return
     */
    public static String sendSSLGetToWx(String authorization, SSLConnectionSocketFactory sslcsf, String requestUrl) {
        HttpGet httGet = new HttpGet(requestUrl);
        httGet.addHeader("Host", "api.mch.weixin.qq.com");
        httGet.addHeader("Accept", "application/json");
        httGet.addHeader("Connection", "close");
        httGet.addHeader("User-Agent", "curl/7.54.0");
        httGet.addHeader("Content-Type", "application/json");
        httGet.addHeader("Authorization", authorization);

        CloseableHttpClient httpClient = null;
        if (sslcsf != null) {
            httpClient = HttpClients.custom().setSSLSocketFactory(sslcsf).build();
        } else {
            httpClient = HttpClients.createDefault();
        }

        CloseableHttpResponse response = null;
        try {
            response = httpClient.execute(httGet);
            HttpEntity entity = response.getEntity();
            String xmlStr = EntityUtils.toString(entity, "UTF-8");
            System.out.println("xmlStr:\n"+xmlStr);
            return xmlStr;
        } catch (Exception e) {
            logger.error(e.getMessage(), e);
            return null;
        } finally {
            try {
                if (response != null) {
                    response.close();
                }
            } catch (IOException e) {
                logger.error(e.getMessage(), e);
            }
        }
    }

    public static void main(String[] args) throws Exception {
//        Map<Object, Object> parame = new TreeMap<Object, Object>();
//        parame.put("mch_id", "");//
//        String randomStr = CharUtil.getRandomNum(18).toUpperCase();
//        parame.put("nonce_str", randomStr);//
//        String sign = WechatUtil.arraySign(parame, "");
//        parame.put("sign", sign);// 数字签证
//
//        String xml = MapUtils.convertMap2Xml(parame);
//        logger.debug("xml:" + xml);
//        Map<String, Object> resultUn = XmlUtil.xmlStrToMap(
//                WechatUtil.requestOnce("https://apitest.mch.weixin.qq.com/sandboxnew/pay/getsignkey", xml));
//        System.out.print(resultUn);
//
//        SimpleDateFormat formatter = new SimpleDateFormat(
//                "yyyy-MM-dd'T'HH:mm:ssXXX");
//        Date date = formatter.parse("2018-12-28T14:20:38+08:00");
////        Date timeEnd = DateUtils.convertStringToDate("2018-12-28T14:20:38+08:00","yyyy-MM-dd'T'HH:mm:ss.SSSXXX");
//        System.out.println(date);

//        long timestamp = System.currentTimeMillis() / 1000L;
//        //去除域名
//        String urlStr = "/hk/v3/certificates";
//        String nonceStr = CharUtil.getRandomString(32).toUpperCase();
//        //组装待签名串
//        String signStr = toSignStr(GET, urlStr, nonceStr, timestamp, "");
//        //计算签名值
//        String signature = SignUtil.signData(signStr,"D:/cert2/WXCertUtil_En/cert/103106626_20181227_cert.p12","103106626");
//        //组装http认证头签名信息
//        String authorization = authorization("103106626", nonceStr, signature,
//                timestamp, "3B080713F47ACCE27BAC6454C7E201CE76EFA1B6");
//        //请求
//        String reponseXml = sendSSLGetToWx(authorization,null, "https://api.weixin.qq.com/hk/v3/certificates");
//        logger.debug("*******查询订单（WX Response：" + reponseXml);

        long s =10/100;

        System.out.println(new BigDecimal(10).divide(Constant.ONE_HUNDRED).doubleValue());
        System.out.println(new BigDecimal(8).divide(Constant.ONE_HUNDRED));
    }
}
