package com.xunwang.payment.controller;

import com.google.gson.Gson;
import com.wechat.pay.contrib.apache.httpclient.auth.Verifier;
import com.wechat.pay.contrib.apache.httpclient.cert.CertificatesManager;
import com.xunwang.servicebase.exception.XunwangException;
import com.xunwang.servicebase.utils.R;
import com.xunwang.payment.config.WxPayConfig;
import com.xunwang.payment.service.WxPayService;
import com.xunwang.payment.util.HttpUtils;
import com.xunwang.payment.util.WechatPay2ValidatorForRequest;
import com.xunwang.servicebase.utils.ResultCode;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.*;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;

@RestController
@RequestMapping("/payment/wx-pay")
@Api("小程序微信支付")
@Slf4j
public class WxPayController {

    @Resource
    private WxPayService wxPayService;

    @Resource
    private CertificatesManager certificatesManager;

    @Resource
    private WxPayConfig wxPayConfig;

    @ApiOperation("调用下单API，获取预支付交易会话标识，有效期为2小时")
    @GetMapping("/jsapi")
    public R jsapiPay(HttpServletRequest request) throws IOException {
        log.info("发起支付请求");

        String inviteId = request.getParameter("inviteId");
        // 返回预支付交易id
        Map<String, Object> map = wxPayService.jsapiPay(inviteId);

        return R.ok().data(map);
    }

    @ApiOperation("支付通知")
    @PostMapping("/jsapi/notify")
    public String jsapiNotify(HttpServletRequest request, HttpServletResponse response) {

        System.out.println("支付通知成功");
        Gson gson = new Gson();
        Map<String, String> map = new HashMap<>(); // 应答对象

        try {
            // 处理通知参数
            String body = HttpUtils.readData(request);
            Map<String, Object> bodyMap = gson.fromJson(body, HashMap.class);
            String requestId = (String) bodyMap.get("id");
            log.info("支付通知的id ===> {}", requestId);
            log.info("支付通知完整数据 ===> {}", body);

            Verifier verifier = certificatesManager.getVerifier(wxPayConfig.getMchId());
            // TODO : 签名的验证
            WechatPay2ValidatorForRequest validator = new WechatPay2ValidatorForRequest(verifier, body, requestId);
            if (!validator.validate(request)) {

                log.error("通知验签失败");
                // 失败应答
                response.setStatus(500);
                map.put("code", "ERROR");
                map.put("message", "通知验签失败");
                return gson.toJson(map);
            }

            log.info("通知验签成功");

            // 处理订单
            wxPayService.processOrder(bodyMap);

            //成功应答：成功应答必须为200或204，否则就是失败应答
            response.setStatus(200);
            map.put("code", "SUCCESS");
            map.put("message", "成功");
            return gson.toJson(map);

        } catch (Exception e) {
            e.printStackTrace();

            // 测试错误应答
            response.setStatus(500);
            map.put("code", "ERROR");
            map.put("message", "系统错误");
            return gson.toJson(map);
        }
    }

    /**
     * 用户取消订单
     *
     * @param orderNo
     * @return
     */
    @ApiOperation("用户取消订单")
    @PostMapping("/cancel/{orderNo}")
    public R cancel(@PathVariable String orderNo) throws IOException {

        log.info("取消订单");

        wxPayService.cancelOrder(orderNo);
        return R.ok().message("订单已取消");
    }

    /**
     * 申请退款
     * @return
     * @throws IOException
     */
    @ApiOperation("申请退款")
    @GetMapping("/refunds")
    public R refunds(HttpServletRequest request){
        String orderNo = request.getParameter("orderNo");
        String reason = request.getParameter("reason");
        log.info("申请退款");
        try {
            wxPayService.refund(orderNo, reason);
        } catch (IOException e) {
            throw new XunwangException(ResultCode.ERROR, "WX退款ERROR: " + e.getMessage());
        }
        return R.ok();
    }

    /**
     * 退款结果通知
     * 退款状态改变后，微信会把相关退款结果发送给商户
     *
     * @param request
     * @param response
     * @return
     */
    @PostMapping("/refunds/notify")
    public String refundsNotify(HttpServletRequest request, HttpServletResponse response) {

        log.info("退款通知执行");
        Gson gson = new Gson();
        Map<String, String> map = new HashMap<>();  // 应答对象

        try {
            // 处理通知参数
            String body = HttpUtils.readData(request);
            Map<String, Object> bodyMap = gson.fromJson(body, HashMap.class);
            String requestId = (String) bodyMap.get("id");
            log.info("支付通知的id ===> {}", requestId);

            Verifier verifier = certificatesManager.getVerifier(wxPayConfig.getMchId());
            // 签名的验证
            WechatPay2ValidatorForRequest wechatPay2ValidatorForRequest = new WechatPay2ValidatorForRequest(verifier, body, requestId);
            if (!wechatPay2ValidatorForRequest.validate(request)) {

                log.error("通知验签失败");
                // 失败应答
                response.setStatus(500);
                map.put("code", "ERROR");
                map.put("message", "通知验签失败");
                return gson.toJson(map);
            }
            log.info("通知验签成功");

            // 处理退款单
            wxPayService.processRefund(bodyMap);

            // 成功应答
            response.setStatus(200);
            map.put("code", "SUCCESS");
            map.put("message", "成功");
            return gson.toJson(map);

        } catch (Exception e) {
            e.printStackTrace();
            // 失败应答
            response.setStatus(500);
            map.put("code", "ERROR");
            map.put("message", "失败");
            return gson.toJson(map);
        }
    }
}
