package com.hwrj.cloud.portal.controller;

import com.github.binarywang.wxpay.bean.notify.WxPayOrderNotifyResult;
import com.github.binarywang.wxpay.bean.request.WxPayUnifiedOrderRequest;
import com.github.binarywang.wxpay.constant.WxPayConstants;
import com.github.binarywang.wxpay.exception.WxPayException;
import com.github.binarywang.wxpay.service.WxPayService;
import com.hwrj.cloud.common.api.CommonResult;
import com.hwrj.cloud.common.exception.Asserts;
import com.hwrj.cloud.portal.from.WxPayFrom;
import com.hwrj.cloud.portal.model.OmsOrder;
import com.hwrj.cloud.portal.service.OmsOrderPayService;
import com.hwrj.cloud.portal.service.OmsPortalOrderService;
import com.hwrj.cloud.portal.util.GeneratorIdUtils;
import com.hwrj.cloud.portal.util.UUIDUtils;
import io.swagger.annotations.Api;
import lombok.extern.slf4j.Slf4j;
import me.chanjar.weixin.common.bean.WxJsapiSignature;
import me.chanjar.weixin.common.error.WxErrorException;
import me.chanjar.weixin.mp.api.WxMpService;
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.*;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.PrintWriter;
import java.math.BigDecimal;

@Slf4j
@Controller
@Api(tags = "支付", description = "支付")
@RequestMapping("/app")
public class WechatH5PayController {

    @Value("${wx.pay.wxpayAppcallbackurl}")
    private String wxpayCallbackUrl;

    @Autowired
    private WxPayService wxPayService;

    @Autowired
    private OmsPortalOrderService omsPortalOrderService;

    @Autowired
    private OmsOrderPayService omsOrderPayService;

    @PostMapping("/pay")
    @ResponseBody
    public CommonResult pay(@RequestBody WxPayFrom wxPayFrom, HttpServletRequest request) {
        Long orderId = wxPayFrom.getOrderId();
        String openid = wxPayFrom.getOpenid();
        String tradeType = wxPayFrom.getTradeType();
        OmsOrder omsOrder = omsPortalOrderService.selectById(orderId);
        Integer status = omsOrder.getPayType();
        //查询订单是否支付
        if (status != 0) {
            throw new RuntimeException("订单已支付");
        }
        WxPayUnifiedOrderRequest orderRequest = new WxPayUnifiedOrderRequest();
        //随机字符串
        String s = UUIDUtils.randomUUID();

        orderRequest.setNonceStr(s);
        //商品描述
        String productName = null;
        try {
            productName = omsPortalOrderService.getProductName(orderId);
        } catch (Exception e) {
            productName = "购买林产品!";
        }
        orderRequest.setBody(productName);
        //商户订单号(支付编号)
        GeneratorIdUtils generatorIdUtils = new GeneratorIdUtils();
        String orderNum = generatorIdUtils.nextId();
        log.info("orderNum:" + orderNum);
        //设置商户订单号
        orderRequest.setOutTradeNo(orderNum);
        //设置金额
        //data.getTotalPrice();
        BigDecimal money = omsOrder.getPayAmount();
        //元转成分
        money = money.multiply(new BigDecimal(100));
        int i = money.intValue();
//        if ("test".equals(tradeType)) {
//            //测试环境一分钱
//            orderRequest.setTotalFee(1);
//        } else {
//            orderRequest.setTotalFee(i);
//        }
        orderRequest.setTotalFee(i);
        //终端ip
        String ipAddress = getIpAddress(request);
        orderRequest.setSpbillCreateIp(ipAddress);
        // 通知地址 支付成功后回调地址
        log.info("wxpayCallbackUrl=================>{}", wxpayCallbackUrl);
        orderRequest.setNotifyUrl(wxpayCallbackUrl);
        //交易类型
        orderRequest.setTradeType(WxPayConstants.TradeType.JSAPI);
        //用户标识 获取用户openid
        orderRequest.setOpenid(openid);
        // 这个可能是偏向原生一点的统一下单，返回的参数有很多没用的 或者null值 建议使用 createOrder下单
        Object unOrder = null;
        try {
            unOrder = wxPayService.createOrder(orderRequest);
        } catch (WxPayException e) {
            //e.printStackTrace();
            log.error(e.getMessage());
            //签名完成新增支付订单
            Asserts.fail("微信支付签名失败!");
        }
        //更新本地订单支付id
        //orderClient.update(data);
        omsOrderPayService.insert(omsOrder, orderNum);
        //签名完成新增支付订单
        return CommonResult.success(unOrder);
    }

    @Autowired
    private WxMpService wxMpService;

    /*微信js签名接口*/
    @GetMapping("/getJsapiTicket")
    @ResponseBody
    public CommonResult getJsapiTicket(String url) {
        WxJsapiSignature jsapiSignature = null;
        try {
            jsapiSignature = wxMpService.createJsapiSignature(url);
        } catch (WxErrorException e) {
            e.printStackTrace();
            System.err.print(e.getError());
        }
        return CommonResult.success(jsapiSignature);
    }

    /**
     * wx支付成功回调接口
     *
     * @param request
     * @param response
     * @throws IOException
     */
    @RequestMapping("payResult")
    public void payResult(HttpServletRequest request, HttpServletResponse response) throws IOException {
        log.info("微信支付返回通知函数开始---------------------");

        InputStream inStream = request.getInputStream();
        ByteArrayOutputStream outSteam = new ByteArrayOutputStream();
        byte[] buffer = new byte[1024];
        int len = 0;
        while ((len = inStream.read(buffer)) != -1) {
            outSteam.write(buffer, 0, len);
        }
        outSteam.close();
        inStream.close();
        String result = new String(outSteam.toByteArray(), "utf-8");
        boolean isPayOk = false;
        WxPayOrderNotifyResult wxPayOrderNotifyResult = null;
        // 此处调用订单查询接口验证是否交易成功
        try {
            wxPayOrderNotifyResult = wxPayService.parseOrderNotifyResult(result);
            if ("SUCCESS".equals(wxPayOrderNotifyResult.getResultCode())) {
                isPayOk = true;
            }
        } catch (WxPayException e) {
            e.printStackTrace();
        }
        String noticeStr = "";
        // 支付成功，商户处理后同步返回给微信参数
        PrintWriter writer = response.getWriter();
        if (isPayOk) {
            //建议在这里处理付款完成的业务（虽然前端也可以处理后续业务，但是前端处理并不安全，例如：客户突然关闭浏览器了等情况，付款成功后续的业务将中断）
            //支付订单支付编号
            System.out.println("===============付款成功，业务开始处理==============");
            String orderNum = wxPayOrderNotifyResult.getOutTradeNo();
            log.info("orderNum:" + orderNum);
            //将订单更新为支付
            log.info("解析数据:" + wxPayOrderNotifyResult.toString());
            omsOrderPayService.update(orderNum);
            /**
             * 自己的业务
             */
            System.out.println("===============付款成功，业务处理完毕==============");
            // 通知微信已经收到消息，不要再给我发消息了，否则微信会8连击调用本接口
            noticeStr = setXML("SUCCESS", "OK");
            log.info("收到通知返回给微信api信息:-----------" + noticeStr);
            writer.write(noticeStr);
            writer.flush();
        } else {
            // 支付失败， 记录流水失败
            noticeStr = setXML("FAIL", "");
            writer.write(noticeStr);
            writer.flush();
            System.out.println("===============支付失败==============");
        }
    }


    public static String setXML(String return_code, String return_msg) {
        return "<xml><return_code><![CDATA[" + return_code + "]]></return_code><return_msg><![CDATA[" + return_msg + "]]></return_msg></xml>";
    }

    public static String getIpAddress(HttpServletRequest request) {
        String ip = request.getHeader("x-forwarded-for");
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getHeader("Proxy-Client-IP");
        }
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getHeader("WL-Proxy-Client-IP");
        }
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getHeader("HTTP_CLIENT_IP");
        }
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getHeader("HTTP_X_FORWARDED_FOR");
        }
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getRemoteAddr();
        }
        String[] split = ip.split(",");
        ip = split[0];
        return ip;
    }

}
