package com.fdkankan.platform.order.controller.pay;

import com.alibaba.fastjson.JSONObject;
import com.fdkankan.common.constant.Constant;
import com.fdkankan.common.constant.ConstantUrl;
import com.fdkankan.common.constant.ErrorCode;
import com.fdkankan.common.controller.BaseController;
import com.fdkankan.common.exception.BusinessException;
import com.fdkankan.pay.paypal.sdk.UrlUtils;
import com.fdkankan.pay.wx.WXPayDefaultConfig;
import com.fdkankan.pay.wx.sdk.WXPayConstants;
import com.fdkankan.pay.wx.sdk.WXPayUtil;
import com.fdkankan.platform.order.entity.CommerceOrder;
import com.fdkankan.platform.order.entity.ExpansionOrder;
import com.fdkankan.platform.order.entity.IncrementOrder;
import com.fdkankan.platform.order.entity.VirtualOrder;
import com.fdkankan.platform.order.request.RequestPlaceOrder;
import com.fdkankan.platform.order.service.ICommerceOrderService;
import com.fdkankan.platform.order.service.IExpansionOrderService;
import com.fdkankan.platform.order.service.IIncrementOrderService;
import com.fdkankan.platform.order.service.IOrderService;
import com.fdkankan.platform.order.service.IVirtualOrderService;
import com.fdkankan.platform.order.service.PayOrderService;
import com.fdkankan.platform.user.factory.PayFactory;
import com.fdkankan.platform.user.strategy.OrderStrategyFactory;
import com.fdkankan.platform.user.vo.ResponseOrder;
import com.fdkankan.platform.user.vo.ResponseOrderItem;
import com.fdkankan.redis.constant.RedisKey;
import com.fdkankan.redis.util.RedisUtil;
import java.io.BufferedOutputStream;
import java.io.InputStream;
import java.math.BigDecimal;
import java.net.HttpURLConnection;
import java.net.URL;
import java.util.List;
import java.util.Map;
import lombok.extern.log4j.Log4j2;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.ResponseBody;

/**
 * 支付中心-微信支付模块
 */
@Log4j2
@Controller
@RequestMapping("/service/platform/order/pay")
public class OrderWechatPayController extends BaseController {
    @Autowired
    private OrderStrategyFactory orderStrategyFactory;
    @Autowired
    private PayFactory payFactory;
    @Autowired
    private IOrderService orderService;
    @Autowired
    private IVirtualOrderService virtualOrderService;
    @Autowired
    private IExpansionOrderService expansionOrderService;
    @Autowired
    private ICommerceOrderService commerceOrderService;
    @Autowired
    private IIncrementOrderService incrementOrderService;
    @Autowired
    private PayOrderService payOrderService;
    @Autowired
    private RedisUtil redisUtil;

    @Value("${main.url}")
    private String mainUrl;

    /**
     * 微信扫码付款
     * orderId          订单id
     * orderType        订单类型，0购买相机，1点数重置，2扩容，3商业版，4增值服务，5场景下载
     * spaceId          0表示国内订单，1表示国外订单
     * @return
     */
    @ResponseBody
    @RequestMapping(value = "/wechatPay", method = RequestMethod.POST)
    public JSONObject wechatPay(@RequestBody RequestPlaceOrder order) throws Exception {
        return payFactory.scanPay("wechat", order);
    }

    /**
     * 微信H5付款
     * orderId          订单id
     * orderType        订单类型，0购买相机，1点数重置，2扩容，3商业版，4增值服务，5场景下载
     * spaceId          0表示国内订单，1表示国外订单
     * @return
     */
    @ResponseBody
    @RequestMapping(value = "/wechatMobilePay", method = RequestMethod.POST)
    public JSONObject wechatMobilePay(@RequestBody RequestPlaceOrder order) throws Exception {
        return payFactory.h5Pay("wechat", order, UrlUtils.getIpAddr(request));
    }

    /**
     * 微信内H5付款
     * code
     * orderId          订单id
     * orderType        订单类型，0购买相机，1点数重置，2扩容，3商业版，4增值服务，5场景下载
     * spaceId          0表示国内订单，1表示国外订单
     */
    @RequestMapping(value = "/wechatPreJsPay")
    public String wechatPreJsPay(Long orderId, int orderType, String code, Long spaceId) throws Exception {
        InputStream is = null;
        WXPayDefaultConfig config = new WXPayDefaultConfig();
        // 这个url链接地址和参数皆不能变
        String url = ConstantUrl.WEIXIN_TOKEN_URL1 + config.getAppID() + "&secret=" + config.getSecret() + "&grant_type=authorization_code" + "&code=" + code;
        try {
            URL urlGet = new URL(url);
            HttpURLConnection http = (HttpURLConnection) urlGet.openConnection();
            http.setRequestMethod("GET"); // 必须是get方式请求
            http.setRequestProperty("Content-Type", "application/x-www-form-urlencoded");
            http.setDoOutput(true);
            http.setDoInput(true);
            System.setProperty("sun.net.client.defaultConnectTimeout", "30000");// 连接超时30秒
            System.setProperty("sun.net.client.defaultReadTimeout", "30000"); // 读取超时30秒
            http.connect();
            is = http.getInputStream();
            int size = is.available();
            byte[] jsonBytes = new byte[size];
            is.read(jsonBytes);
            String message = new String(jsonBytes, "UTF-8");
            log.debug("获取access_token返回的message:"+message);
            JSONObject oppidObj = JSONObject.parseObject(message);
            String access_token = (String) oppidObj.get("access_token");
            String openid = (String) oppidObj.get("openid");

            String orderSn = null;
            StringBuilder sb = new StringBuilder();
            BigDecimal totalFee = null;
            switch (orderType){
                case 0:
                    ResponseOrder responseOrder = orderService.getOrderDetail(orderId);
                    if (responseOrder.getId() == null) return "redirect:" + mainUrl + "mobile.html#/payresult/fail";

                    List<ResponseOrderItem> items = responseOrder.getOrderItems();
                    for (int i = 0; i < items.size(); i++){
                        sb.append(items.get(i).getGoodsCount()).append("*").append(items.get(i).getGoodsName());
                        if (i != items.size() - 1){
                            sb.append("，");
                        }
                    }
                    totalFee = responseOrder.getTotalAmount().multiply(new BigDecimal(100));
                    orderSn = responseOrder.getOrderSn();
                    orderSn += "_entity";
                    break;
                case 1:
                    VirtualOrder virtualOrderEntity = virtualOrderService.getById(orderId);
                    if (virtualOrderEntity == null){
                        return "redirect:" + mainUrl + "mobile.html#/payresult/fail";
                    }
                    sb.append(Constant.PAY_SUBJECT + "：" + virtualOrderEntity.getPoints());
                    totalFee = new BigDecimal(virtualOrderEntity.getPoints()).multiply(new BigDecimal(100));
                    orderSn = virtualOrderEntity.getOrderSn();
                    orderSn += "_recharge";
                    break;
                case 2:
                    ExpansionOrder expansion = expansionOrderService.getById(orderId);
                    if (expansion == null){
                        return "redirect:" + mainUrl + "mobile.html#/payresult/fail";
                    }
                    //订单金额为国外金额就报错
                    if(expansion.getAbroad() == 1){
                        throw new BusinessException(ErrorCode.FAILURE_CODE_8004);
                    }
                    String date = "1年";
                    if(expansion.getMonth() < 12){
                        date = expansion.getMonth() + "个月";
                    }
                    String subject = Constant.EXPANSION_SUBJECT + "：" + expansion.getUnitSize() + expansion.getUnit() + "/" + date;
                    sb.append(subject);
                    totalFee = expansion.getAmount().multiply(new BigDecimal(100));
                    orderSn = expansion.getOrderSn();
                    orderSn += "_expansion";
                    break;
                case 3:
                    CommerceOrder commerce = commerceOrderService.getById(orderId);
                    if (commerce == null){
                        return "redirect:" + mainUrl + "mobile.html#/payresult/fail";
                    }
                    sb.append(Constant.COMMERCE_SUBJECT);
                    totalFee = commerce.getAmount().multiply(new BigDecimal(100));
                    orderSn = commerce.getOrderSn();
                    orderSn += "_commerce";
                    break;
                case 4:
                    IncrementOrder incrementOrderEntity = incrementOrderService.getById(orderId);
                    if (incrementOrderEntity == null){
                        return "redirect:" + mainUrl + "mobile.html#/payresult/fail";
                    }
                    //订单金额为国外金额就报错
                    if(incrementOrderEntity.getAbroad() == 1){
                        throw new BusinessException(ErrorCode.FAILURE_CODE_8004);
                    }
                    sb.append(Constant.INCREMENT_SUBJECT + "：" + incrementOrderEntity.getCount() + "个/年");
                    totalFee = incrementOrderEntity.getAmount().multiply(new BigDecimal(100));
                    orderSn = incrementOrderEntity.getOrderSn();
                    orderSn += "_increment";
                    break;
                case 5:
//                    IncrementOrderEntity incrementOrderEntity = incrementOrderService.findById(orderId);
//                    if (incrementOrderEntity == null){
//                        return "redirect:" + mainUrl + "mobile.html#/payresult/fail";
//                    }
//                    //订单金额为国外金额就报错
//                    if(incrementOrderEntity.getAbroad() == 1){
//                        throw new BaseRuntimeException(OrderConstant.FAILURE_CODE_8004, OrderConstant.FAILURE_MSG_8004);
//                    }
//                    sb.append(Constant.INCREMENT_SUBJECT + "：" + incrementOrderEntity.getCount() + "个/年");
//                    totalFee = incrementOrderEntity.getAmount().multiply(new BigDecimal(100));
//                    orderSn = incrementOrderEntity.getOrderSn();
//                    orderSn += "_increment";
                    break;
            }
            String body = sb.toString();
            if(spaceId != null){
                orderSn = orderSn.replace("expansion", String.valueOf(spaceId));
            }
            Map<String, String> resp = payOrderService.wechatPay(orderSn, sb.toString(), body, totalFee, UrlUtils.getIpAddr(request), openid);
            String timeStamp = String.valueOf(System.currentTimeMillis() / 1000);
            return "redirect:" + mainUrl + ConstantUrl.WEIXIN_MOBILE_PAY_URL + timeStamp + "&signType=MD5&appId=" + resp.get("appid")
                    + "&nonceStr=" + resp.get("nonce_str") + "&prepay_id=" + resp.get("prepay_id") + "&paySign=" + resp.get("paySign");
        }catch (Exception e){
            log.debug("获取access_token发生异常",e);
        }finally {
            if (is != null){
                is.close();
            }
        }
        return "redirect:" + mainUrl + "mobile.html#/payresult/fail";
    }

    /**
     * 微信支付回调
     */
    @RequestMapping(value = {"/wechatPay/notify"}, method = RequestMethod.POST)
    public void callback() {
        log.warn("微信回调接口方法 start");
        String inputLine = "";
        String notifyXml = "";
        try {
            while((inputLine = request.getReader().readLine()) != null){
                notifyXml += inputLine;
            }
            //关闭流
            request.getReader().close();
            log.warn("微信回调内容信息："+notifyXml);
            //解析成Map
            Map<String,String> map = WXPayUtil.xmlToMap(notifyXml);

            WXPayDefaultConfig config = new WXPayDefaultConfig();
            if (WXPayUtil.isSignatureValid(map, config.getKey(), WXPayConstants.SignType.MD5) || WXPayUtil.isSignatureValid(map, config.getKey(), WXPayConstants.SignType.HMACSHA256)) {
                //判断 支付是否成功
                if("SUCCESS".equals(map.get("result_code"))){
                    log.warn("微信回调返回是否支付成功：是");
                    //获得 返回的商户订单号
                    String out_trade_no = map.get("out_trade_no");
                    String trade_no = map.get("transaction_id");
                    String openid = map.get("openid");
                    log.warn("微信回调返回商户订单号：" + out_trade_no);
                    //修改订单状态
                    String orderSnE = out_trade_no.substring(0, out_trade_no.lastIndexOf("_"));

                    String orderSn = out_trade_no.split("_")[0];
                    if(!out_trade_no.contains("recharge") && !out_trade_no.contains("commerce") &&
                            !out_trade_no.contains("entity") && !out_trade_no.contains("expansion") &&
                            !out_trade_no.contains("increment") && !out_trade_no.contains("download")){
//                        orderSn += "_" + out_trade_no.split("_")[1];

                        log.warn("orderSnE:" + orderSn + "_expansion");
                        redisUtil.set(orderSn + "_expansion", out_trade_no, RedisKey.EXPIRE_TIME_2_HOUR);
                    }else {
                        log.warn("orderSnE:" + orderSnE);
                        redisUtil.set(orderSnE, out_trade_no , RedisKey.EXPIRE_TIME_2_HOUR);
                    }
                    orderStrategyFactory.doHandler(orderSn, trade_no, openid, out_trade_no.split("_")[1], 0);
                    log.warn("微信支付成功，订单号："  + orderSn);
                    //通知微信服务器已经支付成功
                    notifyXml = "<xml><return_code><![CDATA[SUCCESS]]></return_code>"
                            + "<return_msg><![CDATA[OK]]></return_msg></xml> ";
                }else{
                    notifyXml = "<xml><return_code><![CDATA[FAIL]]></return_code>"
                            + "<return_msg><![CDATA[报文为空]]></return_msg></xml> ";
                }
            } else{
                log.error("签名验证错误");
                notifyXml = "<xml><return_code><![CDATA[FAIL]]></return_code>"
                        + "<return_msg><![CDATA[签名验证错误]]></return_msg></xml>";
            }
            BufferedOutputStream out = new BufferedOutputStream(
                    response.getOutputStream());
            out.write(notifyXml.getBytes());
            out.flush();
            out.close();

        } catch (Exception e) {
            log.error("微信支付回调数据异常, errorMsg:{}", e.getMessage());
        }
    }


}
