package com.cnd3b.utility.wechatpay.nativepay;

import com.cnd3b.utility.Math;
import com.alibaba.fastjson.JSONObject;
import com.wechat.pay.contrib.apache.httpclient.WechatPayHttpClientBuilder;
import com.wechat.pay.contrib.apache.httpclient.auth.AutoUpdateCertificatesVerifier;
import com.wechat.pay.contrib.apache.httpclient.auth.PrivateKeySigner;
import com.wechat.pay.contrib.apache.httpclient.auth.WechatPay2Credentials;
import com.wechat.pay.contrib.apache.httpclient.auth.WechatPay2Validator;
import com.wechat.pay.contrib.apache.httpclient.util.PemUtil;
import com.cnd3b.common.BaseClass;
import com.cnd3b.common.data.Row;
import com.cnd3b.common.data.db.DBConnect;
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.entity.StringEntity;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.util.EntityUtils;
import org.glassfish.grizzly.http.util.Base64Utils;
import p2.pao.PaoRemote;
import p2.pao.PaoSetRemote;
import p2.application.tuseraccountdetails.tuseraccountdetails;

import javax.crypto.Cipher;
import javax.crypto.spec.GCMParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.security.GeneralSecurityException;
import java.security.PrivateKey;
import java.util.Calendar;

public class nativepay extends BaseClass {
    private CloseableHttpClient httpClient;
    private AutoUpdateCertificatesVerifier verifier;

    /**
     * 下单
     *
     * @throws Exception
     */
    public String createOrder(String siteid, long userid, String fappmodel, int famount) {
        String codeurl = "";
        try {
            String out_trade_no = Calendar.getInstance().getTimeInMillis() + siteid + userid;

            HttpPost httpPost = new HttpPost("https://api.mch.weixin.qq.com/v3/pay/transactions/native");
            // 请求body参数

            JSONObject reqdata = new JSONObject();
            reqdata.put("time_expire", "2021-04-02T18:30:00+08:00");
            JSONObject amount = new JSONObject();
            {
                amount.put("total", famount);
                amount.put("currency", "CNY");
            }
            reqdata.put("amount", amount);
            reqdata.put("mchid", parameter.mchId);
            reqdata.put("description", "多三边-使用年费");//description
            reqdata.put("notify_url", parameter.notify_url);//通知地址
            reqdata.put("out_trade_no", out_trade_no);//商户订单号
            reqdata.put("appid", parameter.appid);
            reqdata.put("attach", "");//附加数据,自定义数据说明

            StringEntity entity = new StringEntity(reqdata.toString(), "utf-8");
            entity.setContentType("application/json");
            httpPost.setEntity(entity);
            httpPost.setHeader("Accept", "application/json");

            //完成签名并执行请求
            CloseableHttpResponse response = httpClient.execute(httpPost);

            try {
                int statusCode = response.getStatusLine().getStatusCode();
                if (statusCode == 200) { //处理成功
                    System.out.println("success,return body = " + EntityUtils.toString(response.getEntity()));
                    codeurl = EntityUtils.toString(response.getEntity());
                    createLocalOrder(out_trade_no, siteid, userid, "系统授权", fappmodel, famount);
                    return codeurl;
                } else if (statusCode == 204) { //处理成功，无返回Body
                    System.out.println("success");
                } else {
                    System.out.println("failed,resp code = " + statusCode + ",return body = " + EntityUtils.toString(response.getEntity()));
                    throw new IOException("request failed");
                }
            } catch (Exception e) {
                e.printStackTrace();
            } finally {
                response.close();
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return codeurl;
    }

    /**
     * 下单
     *
     * @throws Exception
     */
    public String createOrder(String siteid, long userid, int famount) {
        String codeurl = "";
        try {
            String out_trade_no = Calendar.getInstance().getTimeInMillis() + siteid + userid;

            HttpPost httpPost = new HttpPost("https://api.mch.weixin.qq.com/v3/pay/transactions/native");
            // 请求body参数

            JSONObject reqdata = new JSONObject();
            reqdata.put("time_expire", "2021-04-02T18:30:00+08:00");
            JSONObject amount = new JSONObject();
            {
                amount.put("total", famount);
                amount.put("currency", "CNY");
            }
            reqdata.put("amount", amount);
            reqdata.put("mchid", parameter.mchId);
            reqdata.put("description", "多三边-账户充值");//description
            reqdata.put("notify_url", parameter.notify_url);//通知地址
            reqdata.put("out_trade_no", out_trade_no);//商户订单号
            reqdata.put("appid", parameter.appid);
            reqdata.put("attach", "");//附加数据,自定义数据说明

            StringEntity entity = new StringEntity(reqdata.toString(), "utf-8");
            entity.setContentType("application/json");
            httpPost.setEntity(entity);
            httpPost.setHeader("Accept", "application/json");

            //完成签名并执行请求
            CloseableHttpResponse response = httpClient.execute(httpPost);

            try {
                int statusCode = response.getStatusLine().getStatusCode();
                if (statusCode == 200) { //处理成功
                    System.out.println("success,return body = " + EntityUtils.toString(response.getEntity()));
                    codeurl = EntityUtils.toString(response.getEntity());
                    createLocalOrder(out_trade_no, siteid, userid, "账户充值", "", famount);
                    return codeurl;
                } else if (statusCode == 204) { //处理成功，无返回Body
                    System.out.println("success");
                } else {
                    System.out.println("failed,resp code = " + statusCode + ",return body = " + EntityUtils.toString(response.getEntity()));
                    throw new IOException("request failed");
                }
            } catch (Exception e) {
                e.printStackTrace();
            } finally {
                response.close();
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return codeurl;
    }


    /**
     * 创建本地订单信息
     */
    public void createLocalOrder(String out_trade_no, String siteid, long userid, String ftype, String fappmodel, double famount) {
        PaoSetRemote twechatpayorderSet = null;
        try {
            twechatpayorderSet = getP2ServerSystemPaoSet("twechatpayorder");
            PaoRemote pao = twechatpayorderSet.addAtEnd();
            pao.setValue("siteid", siteid);
            pao.setValue("createdate", Calendar.getInstance().getTime());
            pao.setValue("tenterprise_userid", userid);
            pao.setValue("fappmodel", fappmodel);
            pao.setValue("famount", Math.div(famount, 100, 2));
            pao.setValue("out_trade_no", out_trade_no);
            pao.setValue("trade_type", "NATIVE", 11L);
            pao.setValue("ftype", ftype, 11L);
            twechatpayorderSet.save();
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            try {
                twechatpayorderSet.close();
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }

    /**
     * 订单查询
     *
     * @param out_trade_no 商户订单号
     * @return
     */
    public void queryOrder(String out_trade_no) {
        try {
            HttpGet httpPost = new HttpGet("https://api.mch.weixin.qq.com/v3/pay/transactions/out-trade-no/" + out_trade_no + "?mchid=" + parameter.mchId);
            httpPost.setHeader("Accept", "application/json");
            //完成签名并执行请求
            CloseableHttpResponse response = httpClient.execute(httpPost);
            try {
                int statusCode = response.getStatusLine().getStatusCode();
                if (statusCode == 200) { //处理成功
                    System.out.println("success,return body = " + EntityUtils.toString(response.getEntity()));

                    JSONObject returnobject = JSONObject.parseObject(EntityUtils.toString(response.getEntity()));
                    updateLocalOrder_query(returnobject);
                } else if (statusCode == 204) { //处理成功，无返回Body
                    System.out.println("success");
                } else {
                    System.out.println("failed,resp code = " + statusCode + ",return body = " + EntityUtils.toString(response.getEntity()));
                    throw new IOException("request failed");
                }
            } catch (Exception e) {
                e.printStackTrace();
            } finally {
                response.close();
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }


    /**
     * 更新本地数据库的订单信息
     */
    public boolean updateLocalOrder_query(JSONObject wechatOrder) {
        String trade_state = wechatOrder.getString("trade_state");
        PaoSetRemote twechatpayorderSet = null;
        try {
            twechatpayorderSet = getP2ServerSystemPaoSet("twechatpayorder", "out_trade_no='" + wechatOrder.getString("out_trade_no") + "'");
            if (!twechatpayorderSet.isEmpty()) {
                PaoRemote pao = twechatpayorderSet.getPao(0);
                pao.setValue("TRADE_STATE", wechatOrder.getString("trade_state"));
                pao.setValue("TRADE_STATE_DESC", wechatOrder.getString("trade_state_desc"));
                if ("SUCCESS".equals(trade_state)) {
                    pao.setValue("BANK_TYPE", wechatOrder.getString("bank_type"));
                    pao.setValue("TIME_END", wechatOrder.getString("success_time"));
                    pao.setValue("TRANSACTION_ID", wechatOrder.getString("transaction_id"));
                }
                JSONObject amountobject = wechatOrder.getJSONObject("amount");
                pao.setValue("TOTAL_FEE", amountobject.getIntValue("total"));
                if (amountobject.containsKey("payer_total")) {
                    pao.setValue("CASH_FEE", amountobject.getIntValue("payer_total"));
                }
                pao.setValue("orderxml", wechatOrder.toString());
                if ("SUCCESS".equals(trade_state)) {
                    String ftype = pao.getString("ftype");
                    switch (ftype) {
                        case "账户充值": {
                            PaoSetRemote tuseraccountdetailsSet = pao.getPaoSet("$tuseraccountdetails", "tuseraccountdetails", "fsourceobject='" + pao.getName() + "' and fsourceid=" + pao.getUniqueIDValue());
                            Row userrow = getUser(pao.getString("siteid"), pao.getString("tenterprise_userid"));
                            if (tuseraccountdetailsSet.isEmpty()) {
                                tuseraccountdetails tuseraccountdetails = (tuseraccountdetails) tuseraccountdetailsSet.addAtEnd();
                                int famount = amountobject.getIntValue("payer_total");
                                String siteid = pao.getString("siteid");
                                String fname = userrow.getString("fname");
                                long userid = pao.getLong("tenterprise_userid");
                                tuseraccountdetails.setValues("收入", "充值", famount, "微信支付充值", fname, siteid, userid);
                                /**
                                 * 账户余额通过tuseraccountdetails触发器实现
                                 */
                            }
                            break;
                        }
                        case "系统授权": {
                            PaoSetRemote tpayinfoSet = pao.getPaoSet("$tpayinfo", "tpayinfo", "fsourceobject='" + pao.getName() + "' and fsourceid=" + pao.getUniqueIDValue());
                            PaoRemote payinfo = null;
                            Row userrow = getUser(pao.getString("siteid"), pao.getString("tenterprise_userid"));
                            if (tpayinfoSet.isEmpty()) {
                                payinfo = tpayinfoSet.addAtEnd();
                                payinfo.setValue("fsourceobject", pao.getName());
                                payinfo.setValue("fsourceid", pao.getUniqueIDValue());
                                payinfo.setValue("FTYPE", "微信扫码支付");
                                payinfo.setValue("createdate", Calendar.getInstance().getTime());
                                payinfo.setValue("createby", userrow.getString("fname"));
                            } else {
                                payinfo = tpayinfoSet.getPao(0);
                            }
                            payinfo.setValue("famount", pao.getDouble("famount"), 11L);
                            payinfo.setValue("fappmodel", pao.getString("fappmodel"), 11L);
                            Calendar calendar = Calendar.getInstance();
                            payinfo.setValue("FBEGDATE", calendar.getTime(), 11L);
                            calendar.add(Calendar.YEAR, 1);
                            payinfo.setValue("FENDDATE", calendar.getTime(), 11L);
                            payinfo.setValue("tenterprise_userid", pao.getLong("tenterprise_userid"), 11L);
                            payinfo.setValue("tagentsid", userrow.getLong("tagentsid"), 11L);
                            break;
                        }
                        default:
                            break;
                    }
                }
                twechatpayorderSet.save();
                return true;
            } else {
                return false;
            }
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        } finally {
            try {
                twechatpayorderSet.close();
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }

    public String decryptResponseBody(String apiV3Key, String associatedData, String nonce, String ciphertext) {
        try {
            Cipher cipher = Cipher.getInstance("AES/GCM/NoPadding");

            SecretKeySpec key = new SecretKeySpec(apiV3Key.getBytes(StandardCharsets.UTF_8), "AES");
            GCMParameterSpec spec = new GCMParameterSpec(128, nonce.getBytes(StandardCharsets.UTF_8));

            cipher.init(Cipher.DECRYPT_MODE, key, spec);
            cipher.updateAAD(associatedData.getBytes(StandardCharsets.UTF_8));

            byte[] bytes;
            try {
                bytes = cipher.doFinal(Base64Utils.decode(ciphertext));
            } catch (GeneralSecurityException e) {
                throw new IllegalArgumentException(e);
            }
            return new String(bytes, StandardCharsets.UTF_8);
        } catch (Exception e) {
            throw new IllegalStateException(e);
        }
    }

    /**
     * 更新本地数据库的订单信息
     */
    public boolean updateLocalOrder_callback(JSONObject returnobject) {
        if ("支付成功".equals(returnobject.getString("summary"))) {
            JSONObject resource = returnobject.getJSONObject("resource");
            String associated_data = resource.getString("associated_data");
            String ciphertext = resource.getString("ciphertext");
            String nonce = resource.getString("nonce");
            String data = decryptResponseBody(parameter.apiV3Key, associated_data, nonce, ciphertext);

            JSONObject dataobject = JSONObject.parseObject(data);

            PaoSetRemote twechatpayorderSet = null;
            try {
                twechatpayorderSet = getP2ServerSystemPaoSet("twechatpayorder", "out_trade_no='" + dataobject.getString("out_trade_no") + "'");
                if (!twechatpayorderSet.isEmpty()) {
                    PaoRemote pao = twechatpayorderSet.getPao(0);
                    pao.setValue("BANK_TYPE", dataobject.getString("bank_type"));
                    pao.setValue("TIME_END", dataobject.getString("success_time"));
                    pao.setValue("TRADE_STATE", dataobject.getString("trade_state"));
                    pao.setValue("TRADE_STATE_DESC", dataobject.getString("trade_state_desc"));
                    pao.setValue("TRANSACTION_ID", dataobject.getString("transaction_id"));

                    JSONObject amountobject = dataobject.getJSONObject("amount");
                    pao.setValue("TOTAL_FEE", amountobject.getDoubleValue("total"));
                    if (amountobject.containsKey("payer_total")) {
                        pao.setValue("CASH_FEE", amountobject.getDoubleValue("payer_total"));
                    }

                    pao.setValue("orderxml", dataobject.toString());
                    if ("SUCCESS".equals(dataobject.getString("trade_state"))) {
                        String ftype = pao.getString("ftype");
                        switch (ftype) {
                            case "账户充值": {
                                PaoSetRemote tuseraccountdetailsSet = pao.getPaoSet("$tuseraccountdetails", "tuseraccountdetails", "fsourceobject='" + pao.getName() + "' and fsourceid=" + pao.getUniqueIDValue());
                                Row userrow = getUser(pao.getString("siteid"), pao.getString("tenterprise_userid"));
                                if (tuseraccountdetailsSet.isEmpty()) {
                                    tuseraccountdetails tuseraccountdetails = (tuseraccountdetails) tuseraccountdetailsSet.addAtEnd();
                                    int famount = amountobject.getIntValue("payer_total");
                                    String siteid = pao.getString("siteid");
                                    String fname = userrow.getString("fname");
                                    long userid = pao.getLong("tenterprise_userid");
                                    tuseraccountdetails.setValues("收入", "充值", famount, "微信支付充值", fname, siteid, userid);
                                    /**
                                     * 账户余额通过tuseraccountdetails触发器实现
                                     */
                                }
                                break;
                            }
                            case "系统授权": {
                                PaoSetRemote tpayinfoSet = pao.getPaoSet("$tpayinfo", "tpayinfo", "fsourceobject='" + pao.getName() + "' and fsourceid=" + pao.getUniqueIDValue());
                                PaoRemote payinfo = null;
                                Row userrow = getUser(pao.getString("siteid"), pao.getString("tenterprise_userid"));
                                if (tpayinfoSet.isEmpty()) {
                                    payinfo = tpayinfoSet.addAtEnd();
                                    payinfo.setValue("fsourceobject", pao.getName());
                                    payinfo.setValue("fsourceid", pao.getUniqueIDValue());
                                    payinfo.setValue("FTYPE", "微信扫码支付");
                                    payinfo.setValue("createdate", Calendar.getInstance().getTime());
                                    payinfo.setValue("createby", userrow.getString("fname"));
                                } else {
                                    payinfo = tpayinfoSet.getPao(0);
                                }
                                payinfo.setValue("famount", pao.getDouble("famount"), 11L);
                                payinfo.setValue("fappmodel", pao.getString("fappmodel"), 11L);
                                Calendar calendar = Calendar.getInstance();
                                payinfo.setValue("FBEGDATE", calendar.getTime(), 11L);
                                calendar.add(Calendar.YEAR, 1);
                                payinfo.setValue("FENDDATE", calendar.getTime(), 11L);
                                payinfo.setValue("tenterprise_userid", pao.getLong("tenterprise_userid"), 11L);
                                payinfo.setValue("tagentsid", userrow.getLong("tagentsid"), 11L);
                                break;
                            }
                            default:
                                break;
                        }

                    }
                    twechatpayorderSet.save();
                    return true;
                } else {
                    return false;
                }
            } catch (Exception e) {
                e.printStackTrace();
                return false;
            } finally {
                try {
                    twechatpayorderSet.close();
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        } else {
            return false;
        }
    }

    public Row getUser(String siteid, String userid) {
        return new DBConnect().runSqlQuery("select  * from tenterprise_users where siteid='" + siteid + "' and tenterprise_userid=" + userid).get(0);
    }

    public void setup() throws IOException {
        PrivateKey merchantPrivateKey = PemUtil.loadPrivateKey(
                new ByteArrayInputStream(parameter.privateKey.getBytes(StandardCharsets.UTF_8)));
        //使用自动更新的签名验证器，不需要传入证书
        PrivateKeySigner privateKeySigner = new PrivateKeySigner(parameter.mchSerialNo, merchantPrivateKey);
        WechatPay2Credentials wechatPay2Credentials = new WechatPay2Credentials(parameter.mchId, privateKeySigner);
        verifier = new AutoUpdateCertificatesVerifier(wechatPay2Credentials, parameter.apiV3Key.getBytes(StandardCharsets.UTF_8));
        WechatPay2Validator wechatPay2Validator = new WechatPay2Validator(verifier);
        httpClient = WechatPayHttpClientBuilder.create().withMerchant(parameter.mchId, parameter.mchSerialNo, merchantPrivateKey).withValidator(wechatPay2Validator).build();
    }

    public void after() throws IOException {
        httpClient.close();
    }

    public static void main(String[] args) {
        nativepay nativepay = new nativepay();
        try {
            nativepay.setup();
            nativepay.after();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

}
