package com.ruoyi.web.work.wxpay;

import cn.hutool.core.util.StrUtil;
import cn.hutool.http.ContentType;
import cn.hutool.json.JSONUtil;
import com.alibaba.fastjson2.JSONObject;
import com.ijpay.core.IJPayHttpResponse;
import com.ijpay.core.enums.RequestMethodEnum;
import com.ijpay.core.kit.HttpKit;
import com.ijpay.core.kit.PayKit;
import com.ijpay.core.kit.WxPayKit;
import com.ijpay.core.utils.DateTimeZoneUtil;
import com.ijpay.wxpay.WxPayApi;
import com.ijpay.wxpay.enums.WxDomainEnum;
import com.ijpay.wxpay.enums.v3.BasePayApiEnum;
import com.ijpay.wxpay.model.v3.Amount;
import com.ijpay.wxpay.model.v3.Payer;
import com.ijpay.wxpay.model.v3.UnifiedOrderModel;
import com.ruoyi.common.core.domain.AjaxResult;
import com.ruoyi.common.exception.ServiceException;
import com.ruoyi.web.work.api.config.BaseController;
import com.ruoyi.web.work.domain.Pay;
import com.ruoyi.web.work.domain.User;
import com.ruoyi.web.work.domain.dto.PayDto;
import com.ruoyi.web.work.service.IPayService;
import com.ruoyi.web.work.service.IUserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.math.BigDecimal;
import java.nio.charset.StandardCharsets;
import java.security.cert.X509Certificate;
import java.util.HashMap;
import java.util.Map;

@RestController
@RequestMapping("/app/wxPay")
public class UserPayController extends BaseController {
    @Resource
    WxPayBean wxPayV3Bean;

    private String serialNo;

    @Autowired
    private IUserService userService;


    @Autowired
    private IPayService payService;


    /**
     * @param dto
     * @return
     */
    @PostMapping("/pay")
    public AjaxResult pay(@Validated @RequestBody PayDto dto) {
        try {
            String orderNum = PayKit.generateStr();
            UnifiedOrderModel unifiedOrderModel = new UnifiedOrderModel();
            unifiedOrderModel.setAppid(wxPayV3Bean.getAppId());
            unifiedOrderModel.setMchid(wxPayV3Bean.getMchId());
            unifiedOrderModel.setDescription("账户充值");
            unifiedOrderModel.setOut_trade_no(orderNum);
            unifiedOrderModel.setTime_expire(DateTimeZoneUtil.dateToTimeZone(System.currentTimeMillis() + 1000 * 60 * 3));
            unifiedOrderModel.setAttach("账户充值");
            unifiedOrderModel.setAmount(new Amount().setTotal(dto.getMoney().multiply(new BigDecimal(100)).intValue()));
            unifiedOrderModel.setNotify_url(wxPayV3Bean.getDomain().concat("/app/wxPay/notify"));
            unifiedOrderModel.setPayer(new Payer().setOpenid(getUser().getOpenId()));
            IJPayHttpResponse response = WxPayApi.v3(RequestMethodEnum.POST, WxDomainEnum.CHINA.toString(), BasePayApiEnum.JS_API_PAY.toString(), wxPayV3Bean.getMchId(), getSerialNumber(), null, wxPayV3Bean.getKeyPath(), JSONUtil.toJsonStr(unifiedOrderModel));
            System.out.println("统一下单响应：" + response);
            boolean verifySignature = WxPayKit.verifySignature(response, wxPayV3Bean.getPlatformCertPath());
            if (response.getStatus() == 200 && verifySignature) {
                String body = response.getBody();
                JSONObject jsonObject = JSONObject.parseObject(body);
                Map<String, String> map = WxPayKit.jsApiCreateSign(wxPayV3Bean.getAppId(), jsonObject.getString("prepay_id"), wxPayV3Bean.getKeyPath());
                //保存支付订单记录
                Pay pay = new Pay();
                pay.setUserId(getUser().getId());
                pay.setMoney(dto.getMoney());
                pay.setState(0);
                pay.setType(0);
                pay.setTitle("在线充值");
                pay.setVersion(System.currentTimeMillis());
                pay.setNums(orderNum);
                if (!payService.save(pay)) {
                    return AjaxResult.error("充值失败,请联系平台");
                }
                return AjaxResult.success(map);
            }
            return AjaxResult.error("支付异常,请联系平台");
        } catch (Exception e) {
            throw new ServiceException(e.getMessage());
        }
    }

    @Transactional
    @PostMapping(value = "/notify")
    public void payNotify(HttpServletRequest request, HttpServletResponse response) {
        Map<String, String> map = new HashMap<>(12);
        try {
            String timestamp = request.getHeader("Wechatpay-Timestamp");
            String nonce = request.getHeader("Wechatpay-Nonce");
            String serialNo = request.getHeader("Wechatpay-Serial");
            String signature = request.getHeader("Wechatpay-Signature");
            String result = HttpKit.readData(request);
            // 需要通过证书序列号查找对应的证书，verifyNotify 中有验证证书的序列号
            JSONObject res = JSONObject.parseObject(WxPayKit.verifyNotify(serialNo, result, signature, nonce, timestamp, wxPayV3Bean.getApiKey3(), wxPayV3Bean.getPlatformCertPath()));
            System.out.println("支付通知明文：" + res.toJSONString());
            if (res != null && res.getString("trade_state").equals("SUCCESS")) {
                //业务处理，更新订单信息
                Pay pay = payService.selectByNums(res.getString("out_trade_no"));
                if (pay != null && pay.getState() == 0) {
                    pay.setState(1);
                    User user = userService.getById(pay.getUserId());
                    user.setMoney(user.getMoney().add(pay.getMoney()));
                    if (payService.updateById(pay) && userService.updateById(user)) {
                        response.setStatus(200);
                        map.put("code", "SUCCESS");
                        map.put("message", "SUCCESS");
                    } else {
                        response.setStatus(500);
                        map.put("code", "ERROR");
                        map.put("message", "支付失败");

                    }
                }
            } else {
                response.setStatus(500);
                map.put("code", "ERROR");
                map.put("message", "签名错误");
            }
            response.setHeader("Content-type", ContentType.JSON.toString());
            response.getOutputStream().write(JSONUtil.toJsonStr(map).getBytes(StandardCharsets.UTF_8));
            response.flushBuffer();
        } catch (Exception e) {
            throw new ServiceException(e.getMessage());
        }
    }

    /**
     * 获取证书序列号
     *
     * @return
     */
    private String getSerialNumber() {
        if (StrUtil.isEmpty(serialNo)) {
            X509Certificate certificate = PayKit.getCertificate(wxPayV3Bean.getCertPath());
            if (certificate != null) {
                serialNo = certificate.getSerialNumber().toString(16).toUpperCase();
            }
        }
        return serialNo;
    }
}
