package com.izouma.weixin.web;

import cfca.org.bouncycastle.util.encoders.Base64;
import cfca.x509.certificate.X509Cert;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.izouma.agpay.bean.ApiHead;
import com.izouma.agpay.bean.ApiMessage;
import com.izouma.agpay.bean.QR1008ReqBody;
import com.izouma.agpay.util.HttpClient431Util;
import com.izouma.agpay.util.MessageUtil;
import com.izouma.agpay.util.RsaP1Util;
import com.izouma.awesomeadmin.constant.AppConstant;
import com.izouma.awesomeadmin.service.UserOrderService;
import com.izouma.awesomeadmin.util.PropertiesFileLoader;
import com.izouma.weixin.dao.WxpayTempMapper;
import com.izouma.weixin.model.WxpayTemp;
import com.izouma.weixin.util.WeixinUtil;
import org.apache.commons.lang.StringUtils;
import org.apache.log4j.Logger;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import org.springframework.web.servlet.ModelAndView;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import java.io.BufferedOutputStream;
import java.io.FileInputStream;
import java.io.IOException;
import java.math.BigDecimal;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;

@Controller
@RequestMapping("/agpay")
public class AGController {

    private static Logger logger = Logger.getLogger(AGController.class);

    String url = PropertiesFileLoader.getProperties("agpay_api_url");
    String merchantPfxPath = PropertiesFileLoader.getProperties("agpay_merchantPfxPath");
    String publicKeyPath = PropertiesFileLoader.getProperties("agpay_publicKeyPath");
    String agpay_platmerid = PropertiesFileLoader.getProperties("agpay_platmerid");
    String agpay_pwd = PropertiesFileLoader.getProperties("agpay_pwd");


    @Autowired
    private UserOrderService userOrderService;


    @Autowired
    private WxpayTempMapper wxpayTempMapper;


    @RequestMapping(value = "/notify", method = RequestMethod.POST)
    @ResponseBody
    public ModelAndView notify(HttpServletRequest request, HttpServletResponse response) {


        try {
            ApiMessage m = notifyMap(request, response);
            if (m != null && "C000000000".equals(m.getMessage().getData().getHead().getRespcode())) {

                JSONObject bodyJson = JSON.parseObject(JSON.toJSONString(m.getMessage().getData().getBody()));

                String tranflow = m.getMessage().getData().getHead().getTranflow();
                String payamount = bodyJson.getString("payamount");

                if (Double.valueOf(payamount) > 0) {

                    WxpayTemp wxpayTemp = new WxpayTemp();
                    wxpayTemp.setTransactionId(tranflow);
                    wxpayTemp = wxpayTempMapper.queryWxpayTemp(wxpayTemp);
                    if (wxpayTemp != null) {

                        userOrderService.payOrder(wxpayTemp.getOrderId(), wxpayTemp.getCoin().doubleValue(),
                                wxpayTemp.getPoint().doubleValue(), wxpayTemp.getCash().doubleValue(), AppConstant.PayMode.AG_PAY);
                    }

                }


            }
        } catch (Exception e) {
            logger.error("agpay支付回调异常", e);
        }


        return null;
    }


    @RequestMapping(value = "/unifiedOrder", method = RequestMethod.GET)
    @ResponseBody
    public Map<String, String> unifiedOrder(@RequestParam(required = true, value = "orderId") String orderId, @RequestParam(required = true, value = "coin") double coin,
                                            @RequestParam(required = true, value = "point") double point) {
        Map<String, String> resultMap = new HashMap<>();


        RsaP1Util rsaP1Util = new RsaP1Util();

        try {

            HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();

            String ip = WeixinUtil.getIpAdderss(request);


            double cash = userOrderService.calculatedPrice(orderId, coin, point);
            double total = 0;


            total = cash;

            //测试为一分
            total = 0.01;


            //按照要求组装好报文
            ApiHead head = new ApiHead();
            QR1008ReqBody body = new QR1008ReqBody();

            final SimpleDateFormat formatter = new SimpleDateFormat("yyyyMMddHHmmss");
            final String timeStr = formatter.format(new Date());

            head.setClienttime(timeStr);
            head.setPlatmerid(agpay_platmerid);
            head.setTrancode("QR1008");
            head.setTranflow(agpay_platmerid + timeStr + WeixinUtil.getRandomNum(6));

            body.setPayamount("0.01");
            body.setAmount(String.valueOf(cash));
            body.setAgentid("API_WXAPP");
            body.setCommodityname("一米世界-导游包");
            body.setNotifyurl(PropertiesFileLoader.getProperties("agpay_notify_url"));
            body.setSpbillcreateip(ip);


            //head和body组装对应的报文
            ApiMessage father = new ApiMessage();
            ApiMessage.Message message = father.new Message();
            ApiMessage.Message.Data data = message.new Data();
            data.setHead(head);
            data.setBody(body);
            message.setData(data);

            String bodyStr = JSON.toJSONString(data.getBody());
            //生成对应的待签名串 只签名报文体
            String signMessage = MessageUtil.getSignStr(bodyStr);
            //生成签名
            String sign = rsaP1Util.rsaP1Sign(signMessage, merchantPfxPath, "umbpay");
            //得到sign后继续组装对应报文，然后加密
            message.setSign(sign);
            father.setMessage(message);
            String messageStr = JSON.toJSONString(father);
            String reqMsg = new String(rsaP1Util.envelopMessage(messageStr, publicKeyPath));
            Map<String, String> params = new HashMap<String, String>();
            params.put("data", reqMsg);
            params.put("formatType", "json");
            params.put("cryptType", "cert");
            params.put("signType", "cert");
            //发送请求得到结果
            String result = HttpClient431Util.doPost(params, url, "UTF-8", "UTF-8");
            //解密得到明文
            String platinMsg = new String(rsaP1Util.openMessage(result, merchantPfxPath, "umbpay"));
            System.out.println(platinMsg);
            //在返回报文明文 platinMsg中获取系统返回的签名
            //在返回报文明文 platinMsg中自己重新组装待签名串

            ApiMessage resfather = JSON.parseObject(platinMsg, ApiMessage.class);
            System.out.println(resfather);
            //准备验签
            FileInputStream is = new FileInputStream(publicKeyPath);
            X509Cert x509Cert = new X509Cert(is);
            String cert = new String(Base64.encode(x509Cert.getEncoded()), "UTF-8");
            //验签
            String signdata = MessageUtil.getSignStr(JSON.toJSONString(resfather.getMessage().getData().getBody()));

            if (rsaP1Util.rsaP1Verify(resfather.getMessage().getSign(), signdata, cert.getBytes("UTF-8"))) {

                //验签成功，业务处理
                WxpayTemp wxpayTemp = new WxpayTemp();
                wxpayTemp.setOrderId(orderId);
                wxpayTemp.setCoin(BigDecimal.valueOf(coin));
                wxpayTemp.setPoint(BigDecimal.valueOf(point));
                wxpayTemp.setCash(BigDecimal.valueOf(cash));
                wxpayTemp.setTotalAmount(BigDecimal.valueOf(total));
                wxpayTemp.setTransactionId(head.getTranflow());
                wxpayTemp.setOutTradeNo("agpay_order");
                wxpayTemp.setTypeFlag(AppConstant.Aliapi.BUY);

                wxpayTempMapper.insertSelective(wxpayTemp);
                JSONObject bodyJson = JSON.parseObject((JSON.toJSONString(resfather.getMessage().getData().getBody())));

                JSONObject payinfo = JSON.parseObject((bodyJson.getString("payinfo")));


                resultMap.put("appId", StringUtils.isNotEmpty(payinfo.getString("appId"))?payinfo.getString("appId"):PropertiesFileLoader.getProperties("agpay_wx_appid"));
                resultMap.put("partnerid", payinfo.getString("partnerId"));
                resultMap.put("prepayid", payinfo.getString("prepayId"));
                resultMap.put("timestamp", payinfo.getString("timeStamp"));
                resultMap.put("noncestr", payinfo.getString("nonceStr"));
                resultMap.put("package", "Sign=WXPay");
                resultMap.put("sign", payinfo.getString("sign"));


            } else {
                //验签失败，数据可能被篡改
            }


            //result.put("code_url", unified.get("code_url"));
        } catch (Exception e) {
            logger.error("", e);
        }


        return resultMap;

    }


    /**
     * 解析微信支付回调结果
     *
     * @param request
     * @param response
     * @return
     */
    public ApiMessage notifyMap(HttpServletRequest request, HttpServletResponse response) {

        RsaP1Util rsaP1Util = new RsaP1Util();

        logger.info("payOrder：支付订单");
        ApiMessage notifyMap = null;
        try {

            System.out.print("agpay支付回调数据开始");
            String inputLine;
            String notityXml = "";
            String resXml = "";

            try {
                while ((inputLine = request.getReader().readLine()) != null) {
                    notityXml += inputLine;
                }
                request.getReader().close();
            } catch (Exception e) {
                e.printStackTrace();
            }

            System.out.println("接收到的报文：" + notityXml);


            //解密得到明文
            String platinMsg = new String(rsaP1Util.openMessage(notityXml, merchantPfxPath, "umbpay"));
            System.out.println(platinMsg);
            //在返回报文明文 platinMsg中获取系统返回的签名
            //在返回报文明文 platinMsg中自己重新组装待签名串

            ApiMessage resfather = JSON.parseObject(platinMsg, ApiMessage.class);
            System.out.println(resfather);
            //准备验签
            FileInputStream is = new FileInputStream(publicKeyPath);
            X509Cert x509Cert = new X509Cert(is);
            String cert = new String(Base64.encode(x509Cert.getEncoded()), "UTF-8");
            //验签
            String signdata = MessageUtil.getSignStr(JSON.toJSONString(resfather.getMessage().getData().getBody()));

            if (rsaP1Util.rsaP1Verify(resfather.getMessage().getSign(), signdata, cert.getBytes("UTF-8"))) {

                //验签成功，业务处理


                notifyMap = resfather;


                // 进行处理。
                // 注意特殊情况：订单已经退款，但收到了支付结果成功的通知，不应把商户侧订单状态从退款改成支付成功
                if ("C000000000".equals(notifyMap.getMessage().getData().getHead().getRespcode())) {
                    //支付成功
                    resXml = "SUCC";
                } else {
                    resXml = "FAIL";
                }


            } else {
                resXml = "FAIL";
            }


            System.out.println("agpay支付回调数据结束");

            HttpSession session = request.getSession();
            session.setAttribute("notify", "agpay支付回调");
            try {
                BufferedOutputStream out = new BufferedOutputStream(response.getOutputStream());
                out.write(resXml.getBytes());
                out.flush();
                out.close();
            } catch (IOException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }


        } catch (Exception e) {
            logger.error("payOrder：支付订单异常", e);
        }
        return notifyMap;

    }


}
