package com.izouma.nineth.web;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.alipay.api.AlipayApiException;
import com.alipay.api.internal.util.AlipaySignature;
import com.github.binarywang.wxpay.bean.notify.WxPayNotifyResponse;
import com.github.binarywang.wxpay.bean.notify.WxPayOrderNotifyResult;
import com.github.binarywang.wxpay.exception.WxPayException;
import com.github.binarywang.wxpay.service.WxPayService;
import com.huifu.adapay.core.AdapayCore;
import com.huifu.adapay.core.util.AdapaySign;
import com.izouma.nineth.config.AlipayProperties;
import com.izouma.nineth.enums.PayMethod;
import com.izouma.nineth.service.AssetService;
import com.izouma.nineth.service.GiftOrderService;
import com.izouma.nineth.service.OrderService;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections.MapUtils;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.*;

import javax.servlet.http.HttpServletRequest;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;

import static com.alibaba.fastjson.serializer.SerializerFeature.PrettyFormat;

@Slf4j
@Controller
@RequestMapping("/notify")
@AllArgsConstructor
public class OrderNotifyController {

    private final AlipayProperties alipayProperties;
    private final OrderService     orderService;
    private final WxPayService     wxPayService;
    private final AssetService     assetService;
    private final GiftOrderService giftOrderService;

    @PostMapping("/order/alipay")
    @ResponseBody
    public String notify(HttpServletRequest request) throws AlipayApiException {
        Map<String, String> params = new HashMap<>();
        Set<Map.Entry<String, String[]>> entrySet = request.getParameterMap().entrySet();
        for (Map.Entry<String, String[]> entry : entrySet) {
            String name = entry.getKey();
            String[] values = entry.getValue();
            int valLen = values.length;

            if (valLen == 1) {
                params.put(name, values[0]);
            } else if (valLen > 1) {
                StringBuilder sb = new StringBuilder();
                for (String val : values) {
                    sb.append(",").append(val);
                }
                params.put(name, sb.substring(1));
            } else {
                params.put(name, "");
            }
        }
        log.info("支付宝回调 {}", JSON.toJSONString(params, PrettyFormat));
        AlipaySignature.rsaCheckV1(params, alipayProperties.getAliPublicKey(), "UTF-8", "RSA2");
        if (MapUtils.getString(params, "trade_status").equals("TRADE_SUCCESS")) {
            JSONObject body = JSON.parseObject(params.get("body"));
            String action = body.getString("action");
            switch (action) {
                case "payOrder": {
                    Long orderId = body.getLong("orderId");
                    orderService.notifyOrder(orderId, PayMethod.ALIPAY, MapUtils.getString(params, "trade_no"));
                    break;
                }
                case "payGiftOrder": {
                    Long orderId = body.getLong("orderId");
                    giftOrderService.giftNotify(orderId, PayMethod.ALIPAY, MapUtils.getString(params, "trade_no"));
                    break;
                }
            }
            return "success";
        }
        return "error";
    }

    @PostMapping(value = "/order/weixin", produces = "application/xml")
    @ResponseBody
    public String wxNotify(@RequestBody String xmlData) throws WxPayException {
        log.info("微信支付回调: {}", xmlData);
        final WxPayOrderNotifyResult notifyResult = wxPayService.parseOrderNotifyResult(xmlData);
        notifyResult.checkResult(wxPayService, "MD5", true);
        JSONObject attach = JSONObject.parseObject(notifyResult.getAttach());
        String action = attach.getString("action");
        switch (action) {
            case "payOrder": {
                Long orderId = attach.getLong("orderId");
                orderService.notifyOrder(orderId, PayMethod.WEIXIN, notifyResult.getTransactionId());
                break;
            }
            case "payGiftOrder": {
                Long orderId = attach.getLong("orderId");
                giftOrderService.giftNotify(orderId, PayMethod.WEIXIN, notifyResult.getTransactionId());
                break;
            }
        }
        return WxPayNotifyResponse.success("OK");
    }

    @PostMapping("/adapay/order/{orderId}")
    @ResponseBody
    public void adapayNotify(@PathVariable Long orderId, HttpServletRequest request) {
        log.info("adapay notify: \n{}", JSON.toJSONString(request.getParameterMap(), PrettyFormat));
        try {
            String data = request.getParameter("data");
            String sign = request.getParameter("sign");
            boolean checkSign = AdapaySign.verifySign(data, sign, AdapayCore.PUBLIC_KEY);
            log.info("checkSign {}", checkSign);
            if (checkSign) {
                JSONObject jsonObject = JSON.parseObject(data);
                String channel = jsonObject.getString("pay_channel");
                String id = jsonObject.getString("id");
                orderService.notifyOrder(orderId, channel.startsWith("wx") ? PayMethod.WEIXIN : PayMethod.ALIPAY, id);
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    @PostMapping("/adapay/giftOrder/{orderId}")
    @ResponseBody
    public void adapayGiftNotify(@PathVariable Long orderId, HttpServletRequest request) {
        log.info("adapay gift notify: \n{}", JSON.toJSONString(request.getParameterMap(), PrettyFormat));
        try {
            String data = request.getParameter("data");
            String sign = request.getParameter("sign");
            boolean checkSign = AdapaySign.verifySign(data, sign, AdapayCore.PUBLIC_KEY);
            log.info("checkSign {}", checkSign);
            if (checkSign) {
                JSONObject jsonObject = JSON.parseObject(data);
                String channel = jsonObject.getString("pay_channel");
                String id = jsonObject.getString("id");
                giftOrderService.giftNotify(orderId, channel.startsWith("wx") ? PayMethod.WEIXIN : PayMethod.ALIPAY, id);
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}
