package com.yunniu.farming.webadmin.service.impl;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.yunniu.farming.util.*;
import com.yunniu.farming.webadmin.dao.*;
import com.yunniu.farming.webadmin.model.*;
import com.yunniu.farming.webadmin.service.WxService;
import com.yunniu.farming.wx.WxConfigUtil;
import com.yunniu.farming.wx.WxUtil;
import com.yunniu.farming.wx.XMLUtil;
import lombok.extern.slf4j.Slf4j;
import org.jdom.JDOMException;
import org.osgi.framework.ServiceException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.crypto.Cipher;
import javax.crypto.spec.SecretKeySpec;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.*;
import java.text.DecimalFormat;
import java.util.*;

@Service
@Slf4j
public class WxServiceImpl implements WxService {

    @Autowired
    private CustomerDao customerDao;

    @Autowired
    private OrderMainDao orderMainDao;

    @Autowired
    private OrderMainServiceImpl oderMainServiceImpl;

    @Autowired
    private IntegralrecDao integralrecDao;

    @Autowired
    private GroupOrderServiceImpl groupOrderService;

    @Autowired
    private GroupBuyDao groupBuyDao;

    @Autowired
    private OrderRefundMapper refundMapper;

    private String[] imageUrl = {"https://yuezhi-1314984551.cos.ap-shanghai.myqcloud.com/register/41e98a7cc2834450b41927219197d713.jpeg"
            , "https://yuezhi-1314984551.cos.ap-shanghai.myqcloud.com/register/65daa7ab2a9c46c99a580874c73465e3.jpeg"
            , "https://yuezhi-1314984551.cos.ap-shanghai.myqcloud.com/register/056bb47d0b274ab7b430ddd522b18ee3.jpeg"
            , "https://yuezhi-1314984551.cos.ap-shanghai.myqcloud.com/register/d8cee72db9e84166937e26e5871d9324.jpeg"};

//    @Autowired
//    private RedisUtil redisUtil;


    @Override
    public Result login(String code) {


        if (StringHelper.isEmpty(code) ||
                code.equals("the code is a mock one")) {

            return new Result(103,"Error::获取小程序Js_code失败！");
        }


        System.out.println("code================================" + code);
        //向微信服务器查询微信用户openid
        JSONObject wxsession = getSessionKeyOropenid(code);
        String openid = wxsession.getString("openid");
        System.out.println("openid====" + openid);
        System.out.println("jsStr====" + wxsession);
        //String unionId = (String) jsStr.get("unionid");

        if(openid == null){
            return new Result(102);
        }

        Customer user = null;

        if(StringHelper.isNotEmpty(openid)){
            user = this.customerDao.selectAuthLogin(openid);
        }

        String token = UUIDUtils.getUUID();
        Map<String, Object> map1 = new HashMap<>();
        map1.put("token", token);
        if (user == null) {
            Customer u = new Customer();
            u.setSxcxopenid(openid);
//            u.setUnionId(unionId);
            u.setIroleid(Customer.ROLE_NORMAL);//普通用户
            u.setTcreatetime(new Date());
            int index = (int) (Math.random() * imageUrl.length);
            u.setSwximgurl(imageUrl[index]);
            Random random = new Random();
            int number = random.nextInt(10000); // 生成[0,10000)之间的随机整数
            String result = String.format("%04d", number);
            u.setSwxnick("小菜果" + result);
            int insert = this.customerDao.insert(u);
            if (insert > 0) {

                //首次登陆赠送积分
                Integralrec integra = new Integralrec();
                integra.setDincome(500.00); //暂定送500
                integra.setCustomerid(u.getId());//用户id
                integra.setItype(Integralrec.INTEGRALREC_NEWUSR);//新用户赠送
                integra.setSdesc("新用户赠送");
                integra.setSoprdate(DateTools.getDate("yyyy-MM-dd"));
                integra.setToprtime(new Date());
                integralrecDao.insertSelective(integra);
//              redisUtil.set(token,user.getUserId(), 30);
                map1.put("user", u);
            } else {
                throw new RuntimeException();
            }
        } else {
//            redisUtil.set(token,user.getUserId(), 30);
//            map1.put("user", user);
            map1.put("user", user);
            return new Result(map1);
        }
        return new Result(map1);
    }






    /**
     * 获取微信小程序 session_key 和 openid
     *
     * @author zhy
     * @param wxcode 调用微信登陆返回的Code
     * @return
     */
    public JSONObject getSessionKeyOropenid(String wxcode){

        if(StringHelper.isEmpty(wxcode)) return null;

        //微信服务器端请求参数封装
        Map<String,String> requestUrlParam = new HashMap<String,String>();
        requestUrlParam.put("appid", WxConfigUtil.APPID);  //开发者设置中的appId
        requestUrlParam.put("secret", WxConfigUtil.App_Secret); //开发者设置中的appSecret
        requestUrlParam.put("js_code", wxcode); //小程序调用wx.login返回的code
        requestUrlParam.put("grant_type", "authorization_code");    //默认参数

        //发送post请求读取调用微信  接口获取openid用户唯一标识
        JSONObject jsonObject = JSON.parseObject(UrlUtil.sendPost(WxConfigUtil.jscodepath, requestUrlParam));
        //log.info("openid:"+jsonObject.getString("openid"));

        return jsonObject;
    }




    @Override
    public void notify(HttpServletRequest request, HttpServletResponse response) throws IOException, JDOMException {
        InputStream inputStream;
        StringBuffer sb = new StringBuffer();
        inputStream = request.getInputStream();
        String s;
        BufferedReader in = new BufferedReader(new InputStreamReader(inputStream, "UTF-8"));
        while ((s = in.readLine()) != null) {
            sb.append(s);
        }
        in.close();
        inputStream.close();
        // 解析xml成map
        Map<String, String> m = new HashMap<String, String>();
        m = XMLUtil.doXMLParse(sb.toString());
        for (Object keyValue : m.keySet()) {
            System.out.println(keyValue + "=" + m.get(keyValue));
        }
        // 过滤空 设置 TreeMap
        SortedMap<Object, Object> packageParams = new TreeMap<Object, Object>();
        Iterator it = m.keySet().iterator();
        while (it.hasNext()) {
            String parameter = (String) it.next();
            String parameterValue = m.get(parameter);
            String v = "";
            if (null != parameterValue) {
                v = parameterValue.trim();
            }
            packageParams.put(parameter, v);
        }
        // 判断签名是否正确
        String resXml = "";
        if ("SUCCESS".equals((String) packageParams.get("result_code"))) {
            System.out.println("支付成功!");
            // 这里是支付成功
            // ////////执行自己的业务逻辑////////////////
            String mch_id = (String) packageParams.get("mch_id"); // 商户号
            String openid = (String) packageParams.get("openid"); // 用户标识
            String outTradeNo = (String) packageParams.get("out_trade_no"); // 商户订单号
            String total_fee = (String) packageParams.get("total_fee"); //订单金额
            String id = (String) packageParams.get("attach");//订单id
            double payAmount = Double.valueOf(total_fee) / 100;
            String transaction_id = (String) packageParams.get("transaction_id"); // 微信支付订单号

            if (WxConfigUtil.MCH_ID.equals(mch_id)) {

                System.out.print("订单号"+id);
                // 调用支付成功处理
                this.handleNotifyOk(Integer.valueOf(id));

            }
            resXml = "<xml>" + "<return_code><![CDATA[SUCCESS]]></return_code>" + "<return_msg><![CDATA[OK]]></return_msg>" + "</xml> ";

        } else {
            resXml = "<xml>" + "<return_code><![CDATA[FAIL]]></return_code>" + "<return_msg><![CDATA[报文为空]]></return_msg>" + "</xml> ";
        }
        // ------------------------------
        // 处理业务完毕
        // ------------------------------
        BufferedOutputStream out = new BufferedOutputStream(response.getOutputStream());
        out.write(resXml.getBytes());
        out.flush();
        out.close();
    }

    /**
     * 退款
     * @param userId
     * @param orderId
     * @param request
     * @return
     */
    @Override
    public Result wxRefund(Integer userId, Integer orderId, String srefundreason, HttpServletRequest request) throws Exception {
        OrderMain order = orderMainDao.selectByPrimaryKey(orderId);
        if (order == null || !order.getCustomerid().equals(userId)) {
            return new Result(102);
        }
        if (srefundreason.equals("拼团失败")) {
            order.setSrefundreason(srefundreason); // 退款理由
            order.setIrefundstatus(OrderMain.STATUS_CANCEL);
        }
//        order.setTrefundtime(new Date());
//        order.setRefundorderno(StringHelper.getOrderno());
//        orderMainDao.updateById(order);
        OrderRefund refund = refundMapper.selectOne(Wrappers.<OrderRefund>lambdaQuery()
                .eq(OrderRefund::getOrderMianId, order.getId())
                .eq(OrderRefund::getRefundStatus, 6));
        refund.setRefundCode(StringHelper.getOrderno());
        refundMapper.updateById(refund);

        double tradeMoney = order.getDactmoney();
        DecimalFormat decimalFormat = new DecimalFormat("###################");
        SortedMap<Object, Object> parameters = new TreeMap<Object, Object>();
        parameters.put("appid", WxConfigUtil.APPID); // 应用APPID
        parameters.put("mch_id", WxConfigUtil.MCH_ID); // 微信支付分配的商户号
        parameters.put("nonce_str", WxUtil.generateNonceStr()); // 随机字符串，不长于32位
        parameters.put("sign_type", WxConfigUtil.MD5); // 签名类型
        parameters.put("out_trade_no", order.getSorderno()); // 商户订单号
        parameters.put("refund_fee_type", "CNY"); // 默认人民币：CNY
        parameters.put("total_fee", decimalFormat.format(tradeMoney * 100)); // 订单总金额
        if (refund.getRefundStatus().equals(1)) {
            parameters.put("refund_fee", decimalFormat.format(refund.getRefundMoney() * 100)); // 订单总金额
        }else {
            parameters.put("refund_fee", decimalFormat.format(refund.getRefundMoney() * 100)); // 退款金额
        }
        //parameters.put("profit_sharing", "Y");
        // 用户端实际ip
        parameters.put("notify_url", WxConfigUtil.refund_notify_url); // 接收微信支付异步通知回调地址
        parameters.put("out_refund_no", refund.getRefundCode());
        System.out.println("sign=====" + parameters);
        // 设置签名
        String sign = WxUtil.createSignMD5(parameters);
        System.out.println("sign=====" + sign);
        parameters.put("sign", sign);
        // 封装请求参数结束
        String requestXML = WxUtil.getRequestXml(parameters);
        System.out.println(requestXML);
        // 调用申请退款接口
        String result = WxUtil.doRefund(WxConfigUtil.REFUND_ORDER_URL, requestXML);
        System.out.println(result);
        Map<String, String> map = XMLUtil.doXMLParse(result);
        if (!"SUCCESS".equals(map.get("result_code"))){
            throw new ServiceException("退款失败：" + map.get("err_code_des"));
        }
        return new Result();
    }

    /**
     * 退款成功回调
     * @param request
     * @param response
     */
    @Override
    public void wxRefundNotify(HttpServletRequest request, HttpServletResponse response) throws IOException, JDOMException {
        InputStream inputStream;
        StringBuffer sb = new StringBuffer();
        inputStream = request.getInputStream();
        String s;
        BufferedReader in = new BufferedReader(new InputStreamReader(inputStream, "UTF-8"));
        while ((s = in.readLine()) != null) {
            sb.append(s);
        }
        in.close();
        inputStream.close();
        // 解析xml成map
        Map<String, String> m = new HashMap<String, String>();
        m = XMLUtil.doXMLParse(sb.toString());
        for (Object keyValue : m.keySet()) {
            System.out.println(keyValue + "=" + m.get(keyValue));
        }
        // 过滤空 设置 TreeMap
        SortedMap<Object, Object> packageParams = new TreeMap<Object, Object>();
        Iterator it = m.keySet().iterator();
        while (it.hasNext()) {
            String parameter = (String) it.next();
            String parameterValue = m.get(parameter);
            String v = "";
            if (null != parameterValue) {
                v = parameterValue.trim();
            }
            packageParams.put(parameter, v);
        }
        log.info("退款回调解密前1：{}", packageParams);
        // 判断签名是否正确
        String resXml = "";
        if ("SUCCESS".equals((String) packageParams.get("return_code"))) {
            System.out.println("退款成功!");
            // 这里是退款成功
            // ////////执行自己的业务逻辑////////////////
            String req_info = (String) packageParams.get("req_info"); // 商户号
            log.info("退款回调解密前2：{}", req_info);
            resXml = this.wechatRefund(req_info);

        } else {
            resXml = "<xml>" + "<return_code><![CDATA[FAIL]]></return_code>" + "<return_msg><![CDATA[报文为空]]></return_msg>" + "</xml> ";
        }
        // ------------------------------
        // 处理业务完毕
        // ------------------------------
        BufferedOutputStream out = new BufferedOutputStream(response.getOutputStream());
        out.write(resXml.getBytes());
        out.flush();
        out.close();
    }

    public String wechatRefund(String xmlStr) {
        String xmlBack = "";
        Map<String, String> notifyMap = null;
        try {
            //解密
            String reqInfo = decryptData(xmlStr);
            // 解析xml成map
            Map<String, String> m = new HashMap<String, String>();
            m = XMLUtil.doXMLParse(reqInfo);
            for (Object keyValue : m.keySet()) {
                System.out.println(keyValue + "=" + m.get(keyValue));
            }
            // 过滤空 设置 TreeMap
            SortedMap<String, String> map = new TreeMap<String, String>();
            Iterator it = m.keySet().iterator();
            while (it.hasNext()) {
                String parameter = (String) it.next();
                String parameterValue = m.get(parameter);
                String v = "";
                if (null != parameterValue) {
                    v = parameterValue.trim();
                }
                map.put(parameter, v);
            }
            if (null == map || map.size() == 0) {
                log.info("解密异常");
                return "<xml><return_code><![CDATA[FAIL]]></return_code><return_msg><![CDATA[报文为空]]></return_msg></xml>";
            }
            //支付交易号
            String transactionId = map.get("transaction_id");
            //订单号sys/sysDepart/batchSyncSysDepart
            String outTradeNo = map.get("out_trade_no");
            //退款交易号
            String refundId = map.get("refund_id");
            //退款单号
            String outRefundNo = map.get("out_refund_no");
            //订单金额
            String totalFee = map.get("total_fee");
            String settlementTotalFee = map.get("settlement_total_fee");
            //申请金额
            String refundFee = map.get("refund_fee");
            //退款金额
            String settlementRefundFee = map.get("settlement_refund_fee");
            //退款状态
            String refundStatus = map.get("refund_status");
            //成功时间
            String successTime = map.get("success_time");
            String refundRecvAccout = map.get("refund_recv_accout");
            String refundAccount = map.get("refund_account");
            String refundRequestSource = map.get("refund_request_source");
            log.info("退款回调解密后：{}", JSON.toJSONString(map));
            groupOrderService.updateRefundStatus(outRefundNo);

            if (null == settlementRefundFee) {
                log.info("退款金额为空");
                return "<xml><return_code><![CDATA[FAIL]]></return_code><return_msg><![CDATA[报文为空]]></return_msg></xml>";
            }
            if (null == outRefundNo) {
                log.info("商户退款单号为空");
                return "<xml><return_code><![CDATA[FAIL]]></return_code><return_msg><![CDATA[报文为空]]></return_msg></xml>";
            }
            if (null == refundId) {
                log.info("微信退款单号为空");
                return "<xml><return_code><![CDATA[FAIL]]></return_code><return_msg><![CDATA[报文为空]]></return_msg></xml>";
            }
            log.info("\n\t----------------------------------------------------------\n\t" +
                    "订单退款成功" +
                    "\n\t----------------------------------------------------------");
            return "<xml><return_code><![CDATA[SUCCESS]]></return_code><return_msg><![CDATA[OK]]></return_msg></xml>";
        } catch (Exception e) {
            e.printStackTrace();
            log.info("退款回调失败");
            return "<xml><return_code><![CDATA[FAIL]]></return_code><return_msg><![CDATA[报文为空]]></return_msg></xml>";
        }

    }

    public String decryptData(String decryptData) throws Exception {
        SecretKeySpec keySpec = new SecretKeySpec(MD5Util.MD5Encode(WxConfigUtil.API_KEY, "UTF-8").toLowerCase().getBytes(), "AES");
        Cipher cipher = Cipher.getInstance("AES/ECB/PKCS5Padding");
        cipher.init(Cipher.DECRYPT_MODE, keySpec);
        byte[] buffer = Base64.getDecoder().decode(decryptData);
        return new String(cipher.doFinal(buffer), "UTF-8");
    }


    /**
     * @支付成功回调处理
     * @param id
     */
    @Transactional
    public void handleNotifyOk(Integer id) {

        // 从数据库中将信息详情查出来
        OrderMain curOrder = this.orderMainDao.selectByPrimaryKey(id);


        //购买商品订单
        if(curOrder.getItype() != null && curOrder.getItype() == OrderMain.ITYPE_TAKE){
            this.oderMainServiceImpl.handleCommProuctOrder(curOrder);
        }else if(curOrder.getItype() != null && curOrder.getItype() == OrderMain.ITYPE_GROUP){
            this.oderMainServiceImpl.handleCommProuctOrder(curOrder);
            this.groupOrderService.isSuccess(curOrder);
        }
    }



    /**
     * @支付成功回调处理
     * @param id
     */
    @Transactional
    public void testNotifyOk(Integer id) {

        // 从数据库中将信息详情查出来
        OrderMain curOrder = this.orderMainDao.selectByPrimaryKey(id);

        //购买商品订单
        if(curOrder.getItype() != null && curOrder.getItype() == OrderMain.ITYPE_TAKE){
            this.oderMainServiceImpl.handleCommProuctOrder(curOrder);
        }


    }



    @Override
    public Result wxPay(Integer userId, Integer orderId, HttpServletRequest request) throws Exception {
        OrderMain order = orderMainDao.selectByPrimaryKey(orderId);
        if (order == null || !order.getCustomerid().equals(userId)) {
            return new Result(102);
        }

        if (order.getGroupOrderId() != null) {
            GroupOrder groupOrder = groupOrderService.findById(order.getGroupOrderId());
            GroupBuy groupBuy = groupBuyDao.selectById(groupOrder.getGroupBuyId());
            if (groupBuy.getEndTime().before(new Date())) {
                throw new RuntimeException("该团购已失效");
            }
        }

        //判断用户积分是否足够
        if (order.getDactscore() != null) {

            // 查询该用户的积分
            Integralrec integralrec = new Integralrec();
            integralrec.setCustomerid(order.getCustomerid());
            Double inte = this.integralrecDao.sumIntegral(integralrec);

            if (inte == null || inte < 0) return Result.error("积分不足");

            // 用户收入积分减去支付积分要大于订单积分价格
            // 用户余额要大于支付额
            if((inte!=null ?  inte : 0) < order.getDactscore()) {
                return Result.error("积分不足");
            }

        }

        Customer user = customerDao.selectByPrimaryKey(userId);
        double tradeMoney = order.getDactmoney();
        DecimalFormat decimalFormat = new DecimalFormat("###################");
        SortedMap<Object, Object> parameters = new TreeMap<Object, Object>();
        TreeMap<Object, Object> objectObjectTreeMap = new TreeMap<>();
        parameters.put("appid", WxConfigUtil.APPID); // 应用APPID
        parameters.put("mch_id", WxConfigUtil.MCH_ID); // 微信支付分配的商户号
        parameters.put("nonce_str", WxUtil.generateNonceStr()); // 随机字符串，不长于32位
        parameters.put("sign_type", WxConfigUtil.MD5); // 签名类型
        parameters.put("body", "农园"); // 商品描述
        parameters.put("out_trade_no", order.getSorderno()); // 支付订单编号
        parameters.put("fee_type", "CNY"); // 默认人民币：CNY
        parameters.put("total_fee", decimalFormat.format(tradeMoney * 100)); // 订单总金额
        parameters.put("spbill_create_ip", request.getRemoteAddr()); //
        //parameters.put("profit_sharing", "Y");
        // 用户端实际ip
        parameters.put("notify_url", WxConfigUtil.notify_url); // 接收微信支付异步通知回调地址
        parameters.put("trade_type", "JSAPI"); // 支付类型
        parameters.put("openid", user.getSxcxopenid()); // 用户openId
        parameters.put("attach", order.getId().toString());// 附加数据，主要用于存放订单id，用于支付成功后回写数据状态
        System.out.println("sign=====" + parameters);
        // 设置签名
        String sign = WxUtil.createSignMD5(parameters);
        System.out.println("sign=====" + sign);
        parameters.put("sign", sign);
        // 封装请求参数结束
        String requestXML = WxUtil.getRequestXml(parameters);
        System.out.println(requestXML);
        // 调用统一下单接口
        String result = WxUtil.httpsRequest(WxConfigUtil.UNIFIED_ORDER_URL, "POST", requestXML);
        System.out.println(result);
        SortedMap<Object, Object> parameterMap2 = new TreeMap<Object, Object>();

        try {
            Map<String, String> map = XMLUtil.doXMLParse(result);
            parameterMap2.put("appId", WxConfigUtil.APPID);
            // parameterMap2.put("partnerid", WxConfigUtil.MCH_ID);
            // parameterMap2.put("prepayid", map.get("prepay_id"));
            parameterMap2.put("package", "prepay_id=" + map.get("prepay_id"));
            parameterMap2.put("signType", WxConfigUtil.MD5);
            parameterMap2.put("nonceStr", WxUtil.generateNonceStr());
            // 本来生成的时间戳是13位，但是ios必须是10位，所以截取了一下
            parameterMap2.put("timeStamp", Integer.parseInt(Long.valueOf(System.currentTimeMillis()).toString().substring(0, 10)));
            String sign2 = WxUtil.createSignMD5(parameterMap2);
            parameterMap2.put("paySign", sign2);
        } catch (JDOMException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
        return new Result(parameterMap2);
    }





}
