package com.qs.mp.web.controller.api.callback;

import com.alibaba.fastjson.JSON;
import com.alipay.api.AlipayApiException;
import com.alipay.api.domain.AlipayTradeAppPayModel;
import com.alipay.api.internal.util.AlipaySignature;
import com.alipay.api.request.AlipayTradeAppPayRequest;
import com.alipay.api.response.AlipayTradeAppPayResponse;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.qs.mp.common.enums.PayOrderStatusEnum;
import com.qs.mp.common.exception.ServiceException;
import com.qs.mp.common.utils.DateUtils;
import com.qs.mp.common.utils.LogUtil;
import com.qs.mp.common.utils.StringUtils;
import com.qs.mp.common.utils.WebhookService;
import com.qs.mp.pay.domain.PayOrder;
import com.qs.mp.pay.service.IPayOrderService;
import com.qs.mp.pay.service.IWalletService;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.math.BigDecimal;
import java.sql.Date;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;

/**
 * @auther duota
 * @create 2021 2021/9/6 2:54 下午
 * @describe 三方支付平台回调
 */

@RestController
@RequestMapping("/service/notify")
public class AlipayCallBackController {

  private final Logger logger = LoggerFactory.getLogger(this.getClass().getSimpleName());
  private String UNKNOWN = "UNKNOWN";

  @Autowired
  private IPayOrderService payOrderService;

  @Autowired
  private IWalletService walletService;

  @Value("${ali-miniApp.public-key}")
  private String aliPublicKey;


  @RequestMapping(value = "/alipayCallback", method = RequestMethod.POST)
  public void payCallback(HttpServletRequest request, HttpServletResponse response) {
    //获取支付宝POST过来反馈信息
    Map< String , String > params = new HashMap< String , String >();
    Map requestParams = request.getParameterMap();
    logger.info("直连支付宝回调参数:" + JSON.toJSONString(requestParams));
    for(Iterator iter = requestParams.keySet().iterator();iter.hasNext();){
      String name = (String)iter.next();
      String[] values = (String [])requestParams.get(name);
      String valueStr = "";
      for(int i = 0;i < values.length;i ++ ){
        valueStr =  (i==values.length-1)?valueStr + values [i]:valueStr + values[i] + ",";
      }
      //乱码解决，这段代码在出现乱码时使用。
      /*try {
        valueStr = new String(valueStr.getBytes("ISO-8859-1"), "utf-8");
      } catch (UnsupportedEncodingException e) {
        e.printStackTrace();
      }*/
      params.put (name,valueStr);
    }
    //切记alipaypublickey是支付宝的公钥，请去open.alipay.com对应应用下查看。
    //boolean AlipaySignature.rsaCheckV1(Map<String, String> params, String publicKey, String charset, String sign_type)
    boolean flag = false;
    try {
      LogUtil.info(logger, "publickey:" + aliPublicKey);
      flag = AlipaySignature.rsaCheckV1 (params, aliPublicKey, "UTF-8","RSA2");
      if (!flag) {
        LogUtil.error(logger,"验签失败");
        responseWrite(response,"fail");
        return;
      }
    } catch (AlipayApiException e) {
      e.printStackTrace();
    }
    String orderId = request.getParameter("out_trade_no");
    String tradeNo = request.getParameter("trade_no");
    String tradeStatus = request.getParameter("trade_status"); // TRADE_SUCCESS
    int totalAmount = new BigDecimal(request.getParameter("total_amount")).multiply(new BigDecimal(100)).intValue();
    String completeDate = request.getParameter("gmt_payment");
    logger.info("data: orderId:"+orderId +" tradeNo:"+tradeNo +" totalAmount:"+totalAmount+ "tradeStatus:"+tradeStatus);

    //回调金额与订单金额一致性校验
    PayOrder order = payOrderService.getById(orderId);
    if (null == order) {
      logger.error("支付订单不存在，orderId:" + orderId + ",tradeNo:" + tradeNo);
      responseWrite(response,"fail");
      return;
    }
    if (order.getOrderStatus() == PayOrderStatusEnum.SUCCESS.getValue()) {
      logger.info("支付订单已成功，消息忽略，orderId:" + orderId + ",tradeNo:" + tradeNo);
      responseWrite(response,"true");
    }

    if(order.getTransactionAmount().intValue() != totalAmount){
      logger.error("回调金额与订单金额不一致。transAmt:" + order.getTransactionAmount().intValue() + ",payAmt:" + totalAmount);
      responseWrite(response,"fail");
      return;
    }
    if (!"TRADE_SUCCESS".equals(tradeStatus)) {
      logger.error("非支付成功消息，忽略");
      responseWrite(response,"fail");
      return;
    }
    PayOrder payOrder = payOrderService.getById(order.getOrderId());
    payOrder.setOrderId(order.getOrderId());
    payOrder.setOrderNo(tradeNo);
    payOrder.setCompleteDate(completeDate);
//    payOrder.setChannelNo(channelNo);
    payOrder.setOrderStatus(PayOrderStatusEnum.SUCCESS.getValue());


    try {
      // 更新订单，单个事务处理
      logger.info("支付回调消息更新成功 orderId:" + order.getOrderId());
      walletService.payOrderStatusHandle(payOrder);

      // 订单支付状态单独保存
      LambdaUpdateWrapper<PayOrder> updateWrapper = new LambdaUpdateWrapper<>();
      updateWrapper.eq(PayOrder::getOrderStatus, PayOrderStatusEnum.WAIT.getValue());
      updateWrapper.eq(PayOrder::getOrderId, order.getOrderId());
      boolean ret = payOrderService.update(payOrder, updateWrapper);
      if (!ret) {
        LogUtil.error(logger, "支付回调消息更新支付单状态失败 orderId:" + order.getOrderId());
        responseWrite(response,"fail");
      }

      responseWrite(response,"success");
    } catch (Exception e){
      LogUtil.error(logger, e, "支付回调消息处理异常 orderId:" + order.getOrderId());
      responseWrite(response,"fail");
    }
  }

  private void responseWrite(HttpServletResponse response,String echostr){
    try {
      response.getWriter().write(echostr);
      response.getWriter().flush();
      response.getWriter().close();
    } catch (IOException e) {
      LogUtil.error(logger, e, "微信公众号设置url回调处理异常");
    }
  }

  /**
   * 获取 IP地址
   * 使用 Nginx等反向代理软件， 则不能通过 request.getRemoteAddr()获取 IP地址
   * 如果使用了多级反向代理的话，X-Forwarded-For的值并不止一个，而是一串IP地址，
   * X-Forwarded-For中第一个非 unknown的有效IP字符串，则为真实IP地址
   */
  private String getIpAddr(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.getRemoteAddr();
    }
    return "0:0:0:0:0:0:0:1".equals(ip) ? "127.0.0.1" : ip;
  }

}
