package com.izouma.weixin.web;

import com.izouma.awesomeadmin.constant.AppConstant;
import com.izouma.awesomeadmin.model.MemberCoin;
import com.izouma.awesomeadmin.model.UserInfo;
import com.izouma.awesomeadmin.service.MemberCoinService;
import com.izouma.awesomeadmin.service.UserInfoService;
import com.izouma.awesomeadmin.service.UserOrderService;
import com.izouma.awesomeadmin.shiro.WechatToken;
import com.izouma.awesomeadmin.util.Base64;
import com.izouma.awesomeadmin.util.PropertiesFileLoader;
import com.izouma.weixin.dao.WxpayTempMapper;
import com.izouma.weixin.dto.WxPaySendData;
import com.izouma.weixin.model.WxpayTemp;
import com.izouma.weixin.service.WeiXinService;
import com.izouma.weixin.util.WeixinUtil;
import com.izouma.weixin.wxpay.MyConfig;
import com.izouma.weixin.wxpay.WXPay;
import com.izouma.weixin.wxpay.WXPayConstants;
import com.izouma.weixin.wxpay.WXPayUtil;
import org.apache.commons.lang.StringUtils;
import org.apache.log4j.Logger;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.subject.Subject;
import org.json.JSONObject;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.*;
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.IOException;
import java.math.BigDecimal;
import java.util.HashMap;
import java.util.Map;

@Controller
@RequestMapping("/wx")
public class WeiXinController {

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


    @Autowired
    private WeiXinService weiXinService;

    @Autowired
    private UserOrderService userOrderService;

    @Autowired
    private UserInfoService userInfoService;

    @Autowired
    private MemberCoinService memberCoinService;

    @Autowired
    private WxpayTempMapper wxpayTempMapper;

    @RequestMapping(value = "/auth", method = RequestMethod.GET)
    @ResponseBody
    public ModelAndView auth(@RequestParam("redirectUri") String redirectUri) {
        if (StringUtils.isNotEmpty(redirectUri)) {
            redirectUri = Base64.getBase64(redirectUri);
        } else {
            redirectUri = "";
        }
        String wxRedirectUri = PropertiesFileLoader.getProperties("host")
                + "/wx/doAuth/" + redirectUri;
        return new ModelAndView("redirect:https://open.weixin.qq.com/connect/oauth2/authorize?appid="
                + PropertiesFileLoader.getProperties("weixinappid")
                + "&redirect_uri=" + wxRedirectUri
                + "&response_type=code&scope=snsapi_userinfo&state=STATE#wechat_redirect");
    }

    @RequestMapping("/doAuth/{redirectUri}")
    public ModelAndView doAuth(@RequestParam("code") String code, @PathVariable("redirectUri") String redirectUri) {
        ModelAndView modelAndView;
        if (StringUtils.isNotEmpty(redirectUri)) {
            redirectUri = Base64.getFromBase64(redirectUri);
            modelAndView = new ModelAndView("redirect:" + redirectUri);
        } else {
            redirectUri = "";
            modelAndView = new ModelAndView("redirect:/");
        }
        Subject subject = SecurityUtils.getSubject();
        WechatToken wechatToken = new WechatToken(code);
        try {
            subject.login(wechatToken);
        } catch (Exception e) {
            logger.error("doAuth", e);
            modelAndView = new ModelAndView("redirect:" + PropertiesFileLoader.getProperties("host")
                    + "/wx/auth?redirectUri=" + redirectUri);
        }
        return modelAndView;
    }

    @RequestMapping(value = "/getSignature", method = RequestMethod.GET)
    @ResponseBody
    public Map<String, String> getSignature(HttpServletRequest request) {

        String shareUrl = request.getParameter("shareUrl");
        return weiXinService.getSignature(shareUrl);

    }


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

        try {
            Map<String, String> m = notifyMap(request, response);
            if (m != null && "SUCCESS".equals(m.get("result_code"))) {
                String attach = m.get("attach");
                JSONObject attachJson = new JSONObject(attach);

                WxpayTemp wxpayTemp = new WxpayTemp();
                wxpayTemp.setOrderId(attachJson.getString("orderId"));
                wxpayTemp.setCoin(BigDecimal.valueOf(attachJson.getDouble("coin")));
                wxpayTemp.setPoint(BigDecimal.valueOf(attachJson.getDouble("point")));
                wxpayTemp.setCash(BigDecimal.valueOf(attachJson.getDouble("cash")));
                wxpayTemp.setTotalAmount(BigDecimal.valueOf(attachJson.getInt("total") / 100.0));
                wxpayTemp.setOutTradeNo(m.get("out_trade_no"));
                wxpayTemp.setTransactionId(m.get("transaction_id"));
                wxpayTemp.setTypeFlag(AppConstant.Aliapi.BUY);

                wxpayTempMapper.insertSelective(wxpayTemp);

                userOrderService.payOrder(attachJson.getString("orderId"), attachJson.getDouble("coin"),
                        attachJson.getDouble("point"), attachJson.getDouble("cash"), AppConstant.PayMode.WEI_XIN);
            }
        } catch (Exception e) {
            logger.error("微信支付回调异常", e);
        }


        return null;
    }


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

        try {

            Map<String, String> m = notifyMap(request, response);
            if (m != null && "SUCCESS".equals(m.get("result_code"))) {
                String attach = m.get("attach");
                JSONObject attachJson = new JSONObject(attach);

                Integer userId = attachJson.getInt("userId");
                Integer money = attachJson.getInt("money") / 100;

                UserInfo userInfo = userInfoService.getUserInfoById(userId + "");


                /**
                 * 余额
                 */
                double moneyCoin = userInfo.getMoneyCoin();
                UserInfo updateUser = new UserInfo();
                updateUser.setId(userId);
                updateUser.setMoneyCoin(moneyCoin + money);
                userInfoService.updateUserInfo(updateUser);


                MemberCoin memberCoin = new MemberCoin();
                memberCoin.setCreateUser("微信充值");
                memberCoin.setUserId(userId + "");
                memberCoin.setMoney(String.valueOf(money));
                memberCoin.setBalance(String.valueOf(moneyCoin + money));
                memberCoin.setTypeFlag(AppConstant.CoinType.RECHARGE);
                memberCoin.setRemark("微信充值，" + money);
                memberCoinService.createMemberCoin(memberCoin);


                WxpayTemp wxpayTemp = new WxpayTemp();

                wxpayTemp.setUserId(String.valueOf(userId));
                wxpayTemp.setOutTradeNo(m.get("out_trade_no"));
                wxpayTemp.setTransactionId(m.get("transaction_id"));
                wxpayTemp.setTotalAmount(BigDecimal.valueOf(money));
                wxpayTemp.setTypeFlag(AppConstant.Aliapi.RECHARGE);

                wxpayTempMapper.insertSelective(wxpayTemp);
            }

        } catch (Exception e) {
            logger.error("微信充值回调异常", e);
        }

        return null;
    }


    @RequestMapping(value = "/recharge", method = RequestMethod.POST)
    @ResponseBody
    public Map recharge(@RequestParam(required = true, value = "userId") Integer userId, @RequestParam(required = true, value = "money") Integer money) {
        Map<String, String> result = new HashMap<String, String>();

        try {

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

            String ip = WeixinUtil.getIpAdderss(request);


            MyConfig config = new MyConfig();

            int total = money;

            //测试为一分
            //total = 1;

            JSONObject attach = new JSONObject();
            attach.put("userId", userId);
            attach.put("money", money);

            WxPaySendData data = new WxPaySendData();
            data.setDevice_info(AppConstant.DEVICE_INFO);
            data.setBody("充值");
            data.setOut_trade_no(WeixinUtil.create_out_trade_no());
            data.setNotify_url(PropertiesFileLoader.getProperties("weixin_notify_url_recharge"));
            data.setTotal_fee(total);
            data.setTrade_type(AppConstant.TRADE_TYPE_APP);
            //data.setSpbill_create_ip("117.62.182.63");
            data.setSpbill_create_ip(ip);
            //扫码支付不需要openId
            //data.setOpenid(openId);

            data.setAttach(attach.toString());

            Map<String, String> unified = WeixinUtil.unifiedOrder(data);

            String timeStamp = WeixinUtil.create_timestamp();
            String nonceStr = WeixinUtil.create_nonce_str();
            String packageStr = "prepay_id=" + unified.get("prepay_id");
            //生成sign签名
            Map<String, String> params = new HashMap<>();

            params.put("appId", config.getAppID());
            params.put("timeStamp", timeStamp);
            params.put("nonceStr", nonceStr);
            params.put("package", packageStr);

            result.put("appId", config.getAppID());
            result.put("timeStamp", timeStamp);
            result.put("nonceStr", nonceStr);
            result.put("myPackage", packageStr);
            result.put("paySign", WXPayUtil.generateSignature(params, config.getKey()));

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

    @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> result = new HashMap<>();
        try {

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

            String ip = WeixinUtil.getIpAdderss(request);

            MyConfig config = new MyConfig();

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


            total = (int) (cash * 100);

            //测试为一分
            //total = 1;

            JSONObject attach = new JSONObject();
            attach.put("orderId", orderId);
            attach.put("coin", coin);
            attach.put("point", point);
            attach.put("cash", cash);
            attach.put("total", total);

            WxPaySendData data = new WxPaySendData();
//            data.setAppid(PropertiesFileLoader.getProperties("weixinappid"));
//            data.setMch_id(PropertiesFileLoader.getProperties("weixin_mch_id"));
//            data.setNonce_str(MbappUtil.create_nonce_str());

            data.setDevice_info(AppConstant.DEVICE_INFO);
            data.setBody("一米世界-导游包");
            data.setOut_trade_no(WeixinUtil.create_out_trade_no());
            data.setNotify_url(PropertiesFileLoader.getProperties("weixin_notify_url"));
            data.setTotal_fee(total);
            data.setTrade_type(AppConstant.TRADE_TYPE_APP);
            //data.setSpbill_create_ip("117.62.182.63");
            data.setSpbill_create_ip(ip);
            //data.setOpenid(openId);
            data.setAttach(attach.toString());


            Map<String, String> unified = WeixinUtil.unifiedOrder(data);

            String timeStamp = WeixinUtil.create_timestamp();
            String nonceStr = WeixinUtil.create_nonce_str();
            //生成sign签名
            Map<String, String> params = new HashMap<>();

            params.put("appid", config.getAppID());
            params.put("partnerid", config.getMchID());
            params.put("prepayid", unified.get("prepay_id"));
            params.put("timestamp", timeStamp);
            params.put("noncestr", nonceStr);
            params.put("package", "Sign=WXPay");

            result.put("appId", config.getAppID());
            result.put("partnerid", config.getMchID());
            result.put("prepayid", unified.get("prepay_id"));
            result.put("timestamp", timeStamp);
            result.put("noncestr", nonceStr);
            result.put("package", "Sign=WXPay");
            result.put("sign", WXPayUtil.generateSignature(params, config.getKey(), WXPayConstants.SignType.HMACSHA256));


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


        return result;

    }


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

        logger.info("payOrder：支付订单");
        Map<String, String> notifyMap = new HashMap<>();
        try {

            System.out.print("微信支付回调数据开始");
            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);

            MyConfig config = new MyConfig();
            WXPay wxpay = new WXPay(config);

            notifyMap = WXPayUtil.xmlToMap(notityXml);

            if (wxpay.isPayResultNotifySignatureValid(notifyMap)) {
                // 签名正确
                // 进行处理。
                // 注意特殊情况：订单已经退款，但收到了支付结果成功的通知，不应把商户侧订单状态从退款改成支付成功
                if ("SUCCESS".equals(notifyMap.get("result_code"))) {
                    //支付成功
                    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> ";
                }
                System.out.println("微信支付回调数据结束");

                HttpSession seesion = request.getSession();
                seesion.setAttribute("notify", "微信支付回调");
                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();
                }

            } else {
                System.out.println("报文验证签名错误：" + notityXml);
                // 签名错误，如果数据里没有sign字段，也认为是签名错误
                return null;
            }


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

    }


}
