package com.sqx.modules.shopping.service.impl;

import com.github.wxpay.sdk.WXPay;
import com.github.wxpay.sdk.WXPayConstants;
import com.github.wxpay.sdk.WXPayUtil;
import com.sqx.modules.app.entity.UserEntity;
import com.sqx.modules.app.service.UserService;
import com.sqx.modules.common.entity.CommonInfo;
import com.sqx.modules.common.service.CommonInfoService;
import com.sqx.modules.pay.config.WXConfig;
import com.sqx.modules.shopping.dao.OrdersJpaRepository;
import com.sqx.modules.shopping.entity.SelfGoods;
import com.sqx.modules.shopping.entity.SelfGoodsVirtual;
import com.sqx.modules.shopping.entity.SelfOrders;
import com.sqx.modules.shopping.service.GoodsService;
import com.sqx.modules.shopping.service.OrdersService;
import com.sqx.modules.shopping.service.SelfGoodsVirtualService;
import com.sqx.modules.shopping.service.SelfWXService;
import com.sqx.modules.shopping.utils.AmountCalUtil;
import com.sqx.modules.shopping.utils.DateUtil;
import com.sqx.modules.shopping.utils.WXConfigUtil;
import com.sqx.modules.utils.HttpClientUtil;
import com.sqx.modules.utils.MD5Util;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.servlet.http.HttpServletRequest;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;

@Service
public class SelfWXServiceImpl implements SelfWXService {
    private static final String TRADE_TYPE_APP = "APP";
    private static final String TRADE_TYPE_NATIVE = "NATIVE";
    private static final String TRADE_TYPE_JSAPI = "JSAPI";
    private static final String Wap = "MWEB";

    private final Logger log = LoggerFactory.getLogger(SelfWXServiceImpl.class);

    @Autowired
    private CommonInfoService commonRepository;
    @Autowired
    private OrdersService ordersService;
    @Autowired
    private OrdersJpaRepository ordersJpaRepository;
    @Autowired
    private GoodsService goodsService;
    @Autowired
    private UserService userService;

    /**
     * 微信支付
     * @param ordersId  订单id
     * @param type 类型 1App支付 2Web支付
     * @return
     * @throws Exception
     */
    @Override
    @Transactional
    public Map doUnifiedOrder(Long ordersId, Integer type,HttpServletRequest request) throws Exception {
        String url;
        CommonInfo one2 = commonRepository.findOne(19);
        if(type==1){
            url=one2.getValue()+"/sqx_fast/pay/notify";
        }else if(type == 2 || type == 4){
            url=one2.getValue()+"/sqx_fast/pay/notifyjs";
        }else{
            url=one2.getValue()+"/sqx_fast/pay/notifys";
        }
        log.info("回调地址："+url);
        //获取订单
        SelfOrders orders = ordersJpaRepository.findById(ordersId).orElse(null);
        //校验金额是否一致
        SelfGoods byId = goodsService.findById(orders.getGoodsId());
        if(!byId.getStatus().equals(1)){
            ordersJpaRepository.deleteById(ordersId);
            throw new Exception("订单信息错误，请重新下单！");
        }
        UserEntity userById = userService.selectUserById(orders.getUserId());
        Double aDouble=0.00;
        if(userById.getMember()==null || userById.getMember()!=1){
            aDouble = AmountCalUtil.moneyMul(byId.getPrice(), orders.getNumber());
        }else{
            aDouble = AmountCalUtil.moneyMul(byId.getMemberPrice(), orders.getNumber());
        }
        aDouble= AmountCalUtil.add(aDouble,byId.getPostagePrice());
        if(!orders.getPayMoney().equals(aDouble)){
            ordersJpaRepository.deleteById(ordersId);
            throw new Exception("订单信息错误，请重新下单！");
        }
        String outTradeNo = orders.getOrderNum();
        WXConfig config = new WXConfig();
        if(type==1){
            config.setAppId(commonRepository.findOne(260).getValue());//微信商户key
            config.setKey(commonRepository.findOne(245).getValue());
            //微信商户号mchId
            config.setMchId(commonRepository.findOne(246).getValue());
        }else if(type==2 || type == 4){
            config.setAppId(commonRepository.findOne(5).getValue());
            //微信商户key
            config.setKey(commonRepository.findOne(75).getValue());
            //微信商户号mchId
            config.setMchId(commonRepository.findOne(76).getValue());
        }else{
            config.setAppId(commonRepository.findOne(243).getValue());
            //微信商户key
            config.setKey(commonRepository.findOne(245).getValue());
            //微信商户号mchId
            config.setMchId(commonRepository.findOne(246).getValue());
        }
        config.setKey(commonRepository.findOne(75).getValue());
        config.setMchId(commonRepository.findOne(76).getValue());
        String generateNonceStr = WXPayUtil.generateNonceStr();
        WXPay wxpay = new WXPay(config);
        Map<String, String> data = new HashMap<>();
        data.put("appid", config.getAppID());
        data.put("mch_id", config.getMchID());
        data.put("nonce_str",generateNonceStr );
        data.put("body", orders.getTitle());
        //生成商户订单号，不可重复
        data.put("out_trade_no", outTradeNo);
        data.put("total_fee", new Double(orders.getPayMoney()*100).intValue()+""); //1块等于微信支付传入100);
        //自己的服务器IP地址
        //异步通知地址（请注意必须是外网）
        data.put("notify_url", url);
        //交易类型
        if (type ==2){
            data.put("openid",userById.getWxOpenId());
        }else if(type ==3){
            data.put("openid",userById.getArtificerOpenId());
        }
        if (type == 1) {
            data.put("trade_type", TRADE_TYPE_APP);
        } else if (type == 2) {
            data.put("trade_type", TRADE_TYPE_JSAPI);
        } else if (type == 3) {
            data.put("trade_type", TRADE_TYPE_JSAPI);
        } else {
            data.put("trade_type", Wap);
            data.put("spbill_create_ip", HttpClientUtil.getIpAddress(request));
        }
        //附加数据，在查询API和支付通知中原样返回，该字段主要用于商户携带订单的自定义数据
        data.put("attach", "");
        data.put("sign", WXPayUtil.generateSignature(data, config.getKey(), WXPayConstants.SignType.MD5));
        //使用官方API请求预付订单
        Map<String, String> response = wxpay.unifiedOrder(data);
        for (String key : response.keySet()) {
            log.error("key= "+ key + " and value= " + response.get(key));
        }
        if ("SUCCESS".equals(response.get("return_code"))) {//主要返回以下5个参数
            if(type==1){
                Map<String, String> param = new HashMap<>();
                param.put("appid", config.getAppID());
                param.put("partnerid", response.get("mch_id"));
                param.put("prepayid", response.get("prepay_id"));
                param.put("package", "Sign=WXPay");
                param.put("noncestr", WXPayUtil.generateNonceStr());
                param.put("timestamp", System.currentTimeMillis() / 1000 + "");
                param.put("sign", WXPayUtil.generateSignature(param, config.getKey(),
                        WXPayConstants.SignType.MD5));
                param.put("outtradeno", outTradeNo);
                param.put("signType", "MD5");
                return param;
            }else{
                Map<String, String> param = new HashMap<>();
                param.put("appid", config.getAppID());
                param.put("partnerid", response.get("mch_id"));
                param.put("prepayid", response.get("prepay_id"));
                param.put("noncestr", generateNonceStr);
                String timestamp = System.currentTimeMillis() / 1000 + "";
                param.put("timestamp",timestamp);
                    /*param.put("sign", WXPayUtil.generateSignature(param, config.getKey(),
                            WXPayConstants.SignType.MD5));*/
                String stringSignTemp = "appId=" + config.getAppID() + "&nonceStr=" + generateNonceStr + "&package=prepay_id=" + response.get("prepay_id") + "&signType=MD5&timeStamp=" + timestamp+ ""+"&key="+config.getKey();
                String sign = MD5Util.md5Encrypt32Upper(stringSignTemp).toUpperCase();
                param.put("sign",sign);
                param.put("outtradeno", outTradeNo);
                param.put("package", "prepay_id="+response.get("prepay_id"));//给前端返回的值
                param.put("mweb_url", response.get("mweb_url"));
                param.put("trade_type", response.get("trade_type"));
                param.put("return_msg", response.get("return_msg"));
                param.put("result_code", response.get("result_code"));
                param.put("signType", "MD5");
                return param;
            }
        }
        throw new Exception("下单失败");
    }

    @Override
    public String payBack(String resXml,Integer type) {
        WXConfigUtil config = null;
        try {
            config = new WXConfigUtil();
        } catch (Exception e) {
            e.printStackTrace();
        }
        if(type==1){
            config.setAppId(commonRepository.findOne(260).getValue());//微信商户key
            config.setKey(commonRepository.findOne(245).getValue());
            //微信商户号mchId
            config.setMchId(commonRepository.findOne(246).getValue());
        }else if(type==2 || type == 4){
            config.setAppId(commonRepository.findOne(5).getValue());
            //微信商户key
            config.setKey(commonRepository.findOne(75).getValue());
            //微信商户号mchId
            config.setMchId(commonRepository.findOne(76).getValue());
        }else{
            config.setAppId(commonRepository.findOne(243).getValue());
            //微信商户key
            config.setKey(commonRepository.findOne(245).getValue());
            //微信商户号mchId
            config.setMchId(commonRepository.findOne(246).getValue());
        }
        WXPay wxpay = new WXPay(config);
        String xmlBack = "";
        Map<String, String> notifyMap = null;
        try {
            notifyMap = WXPayUtil.xmlToMap(resXml);         // 调用官方SDK转换成map类型数据
            if (wxpay.isPayResultNotifySignatureValid(notifyMap)) {//验证签名是否有效，有效则进一步处理

                String return_code = notifyMap.get("return_code");//状态
                String out_trade_no = notifyMap.get("out_trade_no");//商户订单号
                if ("SUCCESS".equals(return_code)) {
                    if (out_trade_no != null) {
                        //支付回调
                        this.wxPayBack(out_trade_no);
                        System.err.println("微信手机支付回调成功订单号:" + out_trade_no + "");
                        xmlBack = "<xml>" + "<return_code><![CDATA[SUCCESS]]></return_code>" + "<return_msg><![CDATA[OK]]></return_msg>" + "</xml> ";
                    } else {
//                        System.err.println("微信手机支付回调成功订单号:" + out_trade_no + "");
                        xmlBack = "<xml>" + "<return_code><![CDATA[FAIL]]></return_code>" + "<return_msg><![CDATA[报文为空]]></return_msg>" + "</xml> ";
                    }
                }else{
                }
                return xmlBack;
            } else {
                // 签名错误，如果数据里没有sign字段，也认为是签名错误
                System.err.println("手机支付回调通知签名错误");
                xmlBack = "<xml>" + "<return_code><![CDATA[FAIL]]></return_code>" + "<return_msg><![CDATA[报文为空]]></return_msg>" + "</xml> ";
                return xmlBack;
            }
        } catch (Exception e) {
            System.err.println("手机支付回调通知失败" + e);
            xmlBack = "<xml>" + "<return_code><![CDATA[FAIL]]></return_code>" + "<return_msg><![CDATA[报文为空]]></return_msg>" + "</xml> ";
        }
        return xmlBack;
    }



    @Override
    public boolean refund(Long ordersId){

        SelfOrders orders = ordersJpaRepository.getOne(ordersId);
        WXConfigUtil config = null;
        log.info("证书");
        try {
            config = new WXConfigUtil();
        } catch (Exception e) {
            e.printStackTrace();
        }
        config.setAppId(commonRepository.findOne(74).getValue());
        config.setKey(commonRepository.findOne(75).getValue());
        config.setMchId(commonRepository.findOne(76).getValue());
        WXPay wxpay = new WXPay(config);
        Map<String, String> data = new HashMap<>();
        data.put("appid", config.getAppID());
        data.put("mch_id", config.getMchID());
        data.put("nonce_str", WXPayUtil.generateNonceStr());
        log.info("签名");
        try{
            data.put("sign", WXPayUtil.generateSignature(data, config.getKey(), WXPayConstants.SignType.MD5));
        }catch (Exception e){
            e.printStackTrace();
            return false;
        }
        data.put("out_trade_no", orders.getOrderNum()); //订单号
        data.put("out_refund_no", orders.getOrderNum()); //退款单号
        data.put("total_fee", new Double(orders.getPayMoney()*100).intValue()+""); //1块等于微信支付传入100);
        data.put("refund_fee", new Double(orders.getPayMoney()*100).intValue()+""); //1块等于微信支付传入100);
        //使用官方API退款
        try{
            Map<String, String> response = wxpay.refund(data);
            if ("SUCCESS".equals(response.get("return_code"))) {//主要返回以下5个参数
                return true;
            }else {
                return false;
            }
        }catch (Exception e){
            log.info("返回");
            e.printStackTrace();
            return false;
        }
    }

    @Autowired
    private SelfGoodsVirtualService selfGoodsVirtualService;

    /**
     * 支付成功业务
     */
    public void wxPayBack(String out_trade_no){
        log.info("支付回调，单号："+out_trade_no);
        //支付成功，处理业务：处理多个订单
        SelfOrders orders = ordersService.findByOrderNum(out_trade_no);
        if (orders.getStatus() != 1){
            log.info("订单回调重复："+orders.toString());
            return;
        }
        //1.订单业务
        orders.setPayWay(1); //支付方式（1微信 2支付宝 3零钱）
        orders.setPayTime(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date())); //设置支付时间
        orders.setStatus(2); //2已付款
//        if (orders.getIsExpress() == 2){
//            orders.setStatus(9);
//        }
        //5.虚拟商品处理
        if (orders.getIsExpress() == 2){ //是否需要发货(1需要发货 2无需发货)
            //虚拟商品发货，发货成功为确认收货，否则不做变化
            SelfGoodsVirtual v = selfGoodsVirtualService.sendGoods(orders.getGoodsId());
            if (v != null){
                orders.setVirtualId(v.getId()); //虚拟商品id
                orders.setExpressTime(DateUtil.createTime()); //发货时间
                orders.setFinishTime(DateUtil.createTime()); //收货时间
                orders.setStatus(4); //确认收货
//                System.err.println("虚拟商品发货成功:" + out_trade_no + "");
                log.info("虚拟商品发货成功，单号："+out_trade_no);
            }
        }
        ordersJpaRepository.save(orders);

    }

}