package com.app.service.wx;

import com.app.config.WXMPPayConfig;
import com.app.dto.wx.PrePayDto;
import com.app.util.DateUtil;
import com.app.util.HttpUtil;
import com.github.wxpay.sdk.WXPay;
import com.github.wxpay.sdk.WXPayConstants;
import com.github.wxpay.sdk.WXPayUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.math.BigDecimal;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;

@Slf4j
@Component
public class WXPayService {

    @Autowired
    private WXMPPayConfig wxmpPayConfig;

    @Autowired
    private HttpUtil httpUtil;

    WXPayConstants.SignType signType = WXPayConstants.SignType.MD5;

    /**
     * 功能描述：统一下单接口（预下单）
     * 官方文档
     * https://pay.weixin.qq.com/wiki/doc/api/jsapi.php?chapter=9_1
     * 签名校验工具
     * https://pay.weixin.qq.com/wiki/doc/api/jsapi.php?chapter=20_1
     *
     * @param openId
     * @param orderId
     * @param body
     * @param detail
     * @param totalFee
     * @param orderStartTime
     * @param orderExpireTime
     * @return
     */
    public PrePayDto unifiedOrder(String openId, String orderId, String body, String detail, BigDecimal totalFee, Date orderStartTime, Date orderExpireTime) {
        PrePayDto prePayDto = new PrePayDto();

        try {
            Map<String, String> unifiedOrderParamMap = new HashMap<>();
            unifiedOrderParamMap.put("appid", wxmpPayConfig.getAppID()); // 公众账号ID
            unifiedOrderParamMap.put("mch_id", wxmpPayConfig.getMchID()); // 商户号
            unifiedOrderParamMap.put("device_info", ""); // 设备号
            unifiedOrderParamMap.put("nonce_str", WXPayUtil.generateNonceStr()); // 随机字符串
            unifiedOrderParamMap.put("sign_type", signType.name()); // 签名类型
            unifiedOrderParamMap.put("body", body); // 商品描述
            unifiedOrderParamMap.put("detail", detail); // 商品详情
            unifiedOrderParamMap.put("attach", ""); // 附加数据
            unifiedOrderParamMap.put("out_trade_no", orderId); // 商户订单号
            unifiedOrderParamMap.put("fee_type", "CNY"); // 标价币种
            unifiedOrderParamMap.put("total_fee", totalFee.multiply(BigDecimal.valueOf(100)).toBigInteger().toString()); // 标价金额(订单总金额，单位为分，详见支付金额)
            unifiedOrderParamMap.put("spbill_create_ip", httpUtil.getHostAddress()); // 终端IP
            unifiedOrderParamMap.put("time_start", DateUtil.format(orderStartTime, DateUtil.yyyyMMddHHmmss)); // 交易起始时间
            unifiedOrderParamMap.put("time_expire", DateUtil.format(orderExpireTime, DateUtil.yyyyMMddHHmmss)); // 交易结束时间
            unifiedOrderParamMap.put("goods_tag", ""); // 订单优惠标记
            unifiedOrderParamMap.put("notify_url", wxmpPayConfig.getNotifyUrl()); // 通知地址
            unifiedOrderParamMap.put("trade_type", wxmpPayConfig.getTradeType()); // 交易类型
            unifiedOrderParamMap.put("product_id", orderId); // 商品ID
            unifiedOrderParamMap.put("limit_pay", ""); // 指定支付方式
            unifiedOrderParamMap.put("openid", openId); // 用户标识
            unifiedOrderParamMap.put("receipt", ""); // 电子发票入口开放标识
            unifiedOrderParamMap.put("scene_info", ""); // 场景信息
            unifiedOrderParamMap.put("sign", WXPayUtil.generateSignature(unifiedOrderParamMap, wxmpPayConfig.getKey())); // 签名

            WXPay wxpay = new WXPay(wxmpPayConfig, signType, wxmpPayConfig.getUseSandbox());
            if (log.isDebugEnabled()) {
                log.debug("微信支付[统一下单] 请求参数：[{}]", unifiedOrderParamMap);
            }
            Map<String, String> unifiedOrderResp = wxpay.unifiedOrder(unifiedOrderParamMap);
            if (log.isDebugEnabled()) {
                log.debug("微信支付[统一下单] 请求响应：[{}]", unifiedOrderResp);
            }

            if ("FAIL".equals(unifiedOrderResp.get("return_code"))) {
                log.error("微信支付[统一下单] 接口响应错误消息：[{}]", unifiedOrderResp.get("return_msg"));
                throw new RuntimeException("");
            } else if ("SUCCESS".contentEquals(unifiedOrderResp.get("return_code")) && "SUCCESS".contentEquals(unifiedOrderResp.get("result_code"))) {
                prePayDto = wxRequestPayment(unifiedOrderResp.get("prepay_id"));
            } else { // 其他异常
                log.error("微信支付[统一下单] 接口响应错误消息：[{}]", unifiedOrderResp);
            }
        } catch (Exception e) {
            log.error("微信支付[统一下单] 异常[{}]", e);
        } finally {
            return prePayDto;
        }
    }

    /**
     * 功能描述：小程序调起支付数据签名字段
     * 官方文档
     * https://pay.weixin.qq.com/wiki/doc/api/wxa/wxa_api.php?chapter=7_7&index=5
     *
     * @param prepayId
     * @return
     * @throws Exception
     */
    private PrePayDto wxRequestPayment(String prepayId) throws Exception {
        /* 生成所需的签名字段 */
        String timeStamp = String.format("%s", System.currentTimeMillis() / 1000);
        String nonceStr = WXPayUtil.generateNonceStr();
        String packages = String.format("prepay_id=%s", prepayId);

        /* 组装数组待生成签名 */
        Map<String, String> prePayParam = new HashMap<>();
        prePayParam.put("appId", wxmpPayConfig.getAppID());
        prePayParam.put("timeStamp", timeStamp);
        prePayParam.put("nonceStr", nonceStr);
        prePayParam.put("package", packages);
        prePayParam.put("signType", signType.name());

        /* 构造返回参数对象 */
        PrePayDto prePayDto = new PrePayDto();
        prePayDto.setTimeStamp(timeStamp);
        prePayDto.setNonceStr(nonceStr);
        prePayDto.setPackages(packages);
        prePayDto.setSignType(signType.name());
        prePayDto.setPaySign(WXPayUtil.generateSignature(prePayParam, wxmpPayConfig.getKey()));
        return prePayDto;
    }

}
