package com.cftech.order.pay;

import com.alibaba.fastjson.JSONObject;
import com.cftech.core.util.StringUtils;
import com.cftech.core.util.SystemConfig;
import com.cftech.order.model.Order;
import com.cftech.order.service.OrderService;
import lombok.extern.slf4j.Slf4j;
import org.apache.http.HttpEntity;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpPost;
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 org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.DocumentHelper;
import org.dom4j.Element;
import org.dom4j.io.SAXReader;
import org.mp.api.core.common.util.MessageUtil;
import org.springframework.beans.factory.annotation.Autowired;

import javax.servlet.http.HttpServletRequest;
import java.io.IOException;
import java.io.InputStream;
import java.util.*;

/**
 * Created by 16444 on 2020/11/30.
 */
@Slf4j
public class WechatPayUtils {

    public static String retSucXml = "<xml><return_code><![CDATA[SUCCESS]]></return_code><return_msg><![CDATA[OK]]></return_msg></xml>";

    public static String retFailXml = "<xml><return_code><![CDATA[FAIL]]></return_code><return_msg><![CDATA[SYSTEMERROR]]></return_msg></xml>";

    @Autowired
    private MessageUtil messageUtil;

    @Autowired
    private OrderService orderService;

    /**
     * 生成随机数
     * @return
     */
    private static String generateRandomNumber() {
        return UUID.randomUUID().toString().replace("-", "");
    }


    /**
     * 生成签名
     * @param params
     * @return
     */
    public static String getSign(SortedMap<String, String> params, boolean isKey) {
        String secretKey = SystemConfig.p.getProperty("mch.secret_key");//key为商户平台设置的密钥key

        Map<String, String> map = new TreeMap<>();
        map.putAll(params);

        StringBuffer stringBuffer = new StringBuffer();

        for (Map.Entry<String, String> s : map.entrySet()) {
            String key = s.getKey();
            String value = s.getValue();

            if (StringUtils.isBlank(value)) {
                continue;
            }

            stringBuffer.append(key).append("=").append(value).append("&");
        }
        System.out.println(stringBuffer.toString());
        if (isKey)
            stringBuffer.append("key=" + secretKey);

        String md5Str = HashKit.md5(stringBuffer.toString()).toUpperCase();
        return md5Str;
    }

    /**
     * 封装参数且排序
     * @param order
     * @param randomStr
     * @return
     */
    public static SortedMap<String, String> generateOrderMap(Order order, String randomStr) {
        SortedMap<String, String> params = new TreeMap<>();
        params.put("appid", SystemConfig.p.getProperty("WX_MP_SERVER_APPID"));
        params.put("mch_id", SystemConfig.p.getProperty("mch.mch_id"));
        params.put("nonce_str", randomStr);
        params.put("body", SystemConfig.p.getProperty("mch.title"));
        params.put("out_trade_no", order.getNumber());
        Double total = order.getOrderAmount() * 100;
        params.put("total_fee", String.valueOf(total.intValue()));
        params.put("spbill_create_ip", SystemConfig.p.getProperty("mch.spbill_id"));
        params.put("notify_url", SystemConfig.p.getProperty("mch.notify_url"));
        params.put("trade_type", "JSAPI");
        params.put("openid", order.getOpenid());
        return params;
    }

    public static JSONObject genenatePay(Order order) {
        String randomStr = generateRandomNumber();
        SortedMap<String, String> params = generateOrderMap(order, randomStr);

        String sign = getSign(params, true);
        params.put("sign", sign);
        String xmlObj = parseXML(params);

        System.out.print(xmlObj);
        try {
            String result = sendPost(HttpClients.createDefault(), "https://api.mch.weixin.qq.com/pay/unifiedorder", xmlObj);
            log.info("商户号订单：" + result);
            return xmlToStr(result);
        } catch (IOException e) {
            e.printStackTrace();
        }
        return null;
    }

    public static String sendPost(CloseableHttpClient httpclient, String url, String xmlObj) throws IOException {
        String result;
        HttpPost httpPost = new HttpPost(url);
        // 得指明使用UTF-8编码，否则到API服务器XML的中文不能被成功识别
        StringEntity postEntity = new StringEntity(xmlObj, "UTF-8");
        httpPost.addHeader("Content-Type", "text/xml");
        httpPost.setEntity(postEntity);
        log.info(xmlObj);
        try {
            CloseableHttpResponse response = httpclient.execute(httpPost);
            try {
                HttpEntity entity = response.getEntity();
                result = EntityUtils.toString(entity, "UTF-8");
            } finally {
                response.close();
            }
        } finally {
            httpclient.close();
        }
        return result;
    }

    public static String parseXML(Map<String, String> parameters) {
        StringBuffer sb = new StringBuffer();
        sb.append("<xml>");
        Set es = parameters.entrySet();
        Iterator it = es.iterator();
        while (it.hasNext()) {
            Map.Entry entry = (Map.Entry) it.next();
            String k = (String) entry.getKey();
            String v = (String) entry.getValue();
            if (null != v && !"".equals(v) && !"appkey".equals(k)) {
                sb.append("<" + k + ">" + parameters.get(k) + "</" + k + ">\n");
            }
        }
        sb.append("</xml>");
        return sb.toString();
    }

    public static JSONObject xmlToStr(String str) {
        JSONObject retObj = new JSONObject();
        try {
            Document doc = DocumentHelper.parseText(str);
            Element rootElt = doc.getRootElement();
            String result_code = rootElt.elementTextTrim("result_code");
            String return_code =  rootElt.elementTextTrim("return_code");

            if (StringUtils.equals(result_code, "SUCCESS") && StringUtils.equals(return_code, "SUCCESS")) {
                String code_url =  rootElt.elementTextTrim("code_url");
                String prepay_id = rootElt.elementTextTrim("prepay_id");
                retObj.put("code_url", code_url);
                retObj.put("prepay_id", prepay_id);
                return retObj;
            }

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

    public static TreeMap<String, String> parseXml(HttpServletRequest request) throws Exception {
        //将解析结果存储在HashMap中
        TreeMap<String, String> map = new TreeMap<>();
        // 从request中取得输入流
        InputStream inputStream = request.getInputStream();
        System.out.println(inputStream.toString());
        // 读取输入流
        SAXReader reader = new SAXReader();
        Document document = reader.read(inputStream);
        // 得到xml根元素
        Element root = document.getRootElement();
        //得到根元素的所有子节点
        List<Element> elementList = root.elements();
        // 遍历所有子节点
        List<Element> elements;
        for (Element e : elementList){
            elements = e.elements();
            if(elements.size()>0){
                for (Element element : elements) {
                    map.put(element.getName(),element.getText());
                }
            }
            map.put(e.getName(), e.getText());
        }
        // 释放资源
        inputStream.close();
        inputStream = null;
        return map;
    }
}
