package co.yixiang.yshop.module.pay.strategy.weixin.service;

import co.yixiang.yshop.module.pay.controller.admin.merchantdetails.vo.PayParam;
import co.yixiang.yshop.module.pay.dal.dataobject.merchantdetails.MerchantDetailsDO;
import co.yixiang.yshop.module.pay.enums.PayTypeEnum;
import co.yixiang.yshop.module.pay.strategy.weixin.skd.PaymentApi;
import co.yixiang.yshop.module.pay.strategy.weixin.skd.PaymentKit;
import co.yixiang.yshop.module.pay.strategy.weixin.skd.RandomStringUtil;
import co.yixiang.yshop.module.pay.strategy.weixin.skd.WXPayUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;

import java.math.BigDecimal;
import java.net.URLEncoder;
import java.util.HashMap;
import java.util.Map;

@Component
@Slf4j(topic = "WxPayServiceUtils")
public class WxPayServiceUtils implements InitializingBean {
    /**
     * 支付小程序appid
     */
    @Value("${weixin.appid}")
    private String appid;

    /**
     * 支付APP端的appid
     */
    @Value("${weixin.app_appid}")
    private String app_appid;

    /**
     * 支付小程序秘钥
     */
    @Value("${weixin.secret}")
    private String secret;

    /**
     * 商户号
     */
    @Value("${weixin.mchid}")
    private String mch_id;

    /**
     * 证书路径
     */
    @Value("${weixin.certurl}")
    private String cert_url;

    /**
     * app回调地址
     */
    @Value("${weixin.app_notifyurl}")
    private String app_notify_url;

    /**
     * 商户秘钥
     */
    @Value("${weixin.key}")
    private String key;


    public Map<String, String> gotoPay(PayParam param) throws Exception {
        Map<String, String> reqParams = new HashMap<>();
        //获取商户信息
        //h5
        String outTradeNo = "";
        if (PayTypeEnum.WEIXIN_H5.getType().equals(param.getType())) {
            outTradeNo = param.getOrderId() + "-" + RandomStringUtil.getRandomCode(3, 0) + "H5";
            reqParams.put("appid", param.getMerchantDetailsDO().getAppid());
            //交易类型
            reqParams.put("trade_type", "MWEB");
        } else if (PayTypeEnum.WEIXIN_APP.getType().equals(param.getType())) {
            //微信app分配的APPID
            //app_appid
            outTradeNo = param.getOrderId() + "-" + RandomStringUtil.getRandomCode(3, 0) + "APP";
            reqParams.put("appid", param.getMerchantDetailsDO().getAppid());
            //交易类型
            reqParams.put("trade_type", "APP");
        } else if (PayTypeEnum.WEIXIN_APPLET.getType().equals(param.getType())) {
            //微信app分配的APPID
            reqParams.put("openid", param.getOpenId());
            outTradeNo = param.getOrderId() + "-" + RandomStringUtil.getRandomCode(3, 0) + "APPLET";
            reqParams.put("appid", param.getMerchantDetailsDO().getAppid());
            //交易类型
            reqParams.put("trade_type", "JSAPI");
        } else {
            //微信app分配的APPID
            reqParams.put("openid", param.getOpenId());
            outTradeNo = param.getOrderId() + "-" + RandomStringUtil.getRandomCode(3, 0) + "APPLET";
            reqParams.put("appid", param.getMerchantDetailsDO().getAppid());
            //交易类型
            reqParams.put("trade_type", "JSAPI");
        }
        //微信支付分配的商户号
        //保存对应的outTradeNo

        reqParams.put("mch_id", param.getMerchantDetailsDO().getMchId());
        //随机字符串
        reqParams.put("nonce_str", System.currentTimeMillis() / 1000 + "");
        //签名类型
        reqParams.put("sign_type", "MD5");
        //充值订单 商品描述
        reqParams.put("body", "充值" + param.getPayDesc() + "订单-微信支付");
        //商户订单编号
        reqParams.put("out_trade_no", outTradeNo);
        //订单总金额，单位为分
        reqParams.put("total_fee", param.getMoney().multiply(BigDecimal.valueOf(100)).intValue() + "");
        //终端IP
        reqParams.put("spbill_create_ip", param.getIp());
        //通知地址
        reqParams.put("notify_url", param.getMerchantDetailsDO().getNotifyUrl());
        //用户标识
        //  reqParams.put("openid", openid);
        //签名
        String sign = WXPayUtil.generateSignature(reqParams, param.getMerchantDetailsDO().getKeyPrivate());
        reqParams.put("sign", sign);
        /*
            调用支付定义下单API,返回预付单信息 prepay_id
         */
        String xmlResult = PaymentApi.pushOrder(reqParams);
        log.info("微信下单信息：{}", xmlResult);
        Map<String, String> result = PaymentKit.xmlToMap(xmlResult);
        //预付单信息
        String prepay_id = result.get("prepay_id");

        /*
            小程序调起支付数据签名
         */
        Map<String, String> packageParams = new HashMap<String, String>();
        packageParams.put("appId", param.getMerchantDetailsDO().getAppid());
        packageParams.put("timeStamp", System.currentTimeMillis() / 1000 + "");
        packageParams.put("nonceStr", System.currentTimeMillis() + "");
        packageParams.put("package", "prepay_id=" + prepay_id);
        packageParams.put("signType", param.getMerchantDetailsDO().getSignType());
        String packageSign = WXPayUtil.generateSignature(packageParams, param.getMerchantDetailsDO().getKeyPrivate());
        packageParams.put("paySign", packageSign);
        packageParams.put("codeUrl", result.get("code_url"));
        packageParams.put("orderId", param.getOrderId());
        //将组合后的商户订单号返回
        packageParams.put("out_trade_no", outTradeNo);
        packageParams.put("merchant_id", param.getMerchantDetailsDO().getMchId());
        Map map = PaymentApi.queryByOutTradeNo(param.getMerchantDetailsDO().getAppid(), param.getMerchantDetailsDO().getMchId(), param.getMerchantDetailsDO().getKeyPrivate(), outTradeNo);
        log.info("查询到微信订单信息：" + map.toString());
        // payInfo.setTransaction_id(map.get("transaction_id"))
        if (PayTypeEnum.WEIXIN_H5.getType().equals(param.getType())) {
            packageParams.put("mwebUrl", result.get("mweb_url") + "&redirect_url=" + URLEncoder.encode(param.getMerchantDetailsDO().getReturnUrl() + param.getRedirectType(), "GBK"));
        }
        return packageParams;
    }

    public Map<String, String> refund(String transactionId, String outRefundNo, BigDecimal total, BigDecimal refund, MerchantDetailsDO merchantDetailsDO) throws Exception {
        //退款资金来源-可用余额退款
        String refundAccount = "REFUND_SOURCE_RECHARGE_FUNDS";
        Map<String, String> params = new HashMap<>();
        params.put("appid", merchantDetailsDO.getAppid());
        params.put("mch_id", merchantDetailsDO.getMchId());
        params.put("nonce_str", System.currentTimeMillis() / 1000 + "");
        //商户订单号和微信订单号二选一
//        params.put("out_trade_no", wxPayLog.getOutTradeNo());
        params.put("transaction_id", transactionId);
        params.put("out_refund_no", outRefundNo);
        params.put("total_fee", total.multiply(BigDecimal.valueOf(100)).intValue() + "");
        params.put("refund_fee", refund.multiply(BigDecimal.valueOf(100)).intValue() + "");
        params.put("refund_account", refundAccount);
        // 退款原因，若商户传入，会在下发给用户的退款消息中体现退款原因
        params.put("refund_desc", "退款");
        //退款回调 先不做
        //   params.put("notify_url", pc_refund_notify_url);
        //签名算法
        String sign = WXPayUtil.generateSignature(params, merchantDetailsDO.getKeyPrivate());
        params.put("sign", sign);
        String xml = PaymentKit.toXml(params);
        log.info(xml);
        String xmlStr = WXPayUtil.doRefund("https://api.mch.weixin.qq.com/secapi/pay/refund", xml, cert_url, merchantDetailsDO.getMchId());
        //加入微信支付日志
        return PaymentKit.xmlToMap(xmlStr);
    }

    public Map<String, String> refundBond(String transactionId, String outRefundNo, BigDecimal total, BigDecimal refund) throws Exception {
        //退款资金来源-可用余额退款
        String refundAccount = "REFUND_SOURCE_RECHARGE_FUNDS";
        Map<String, String> params = new HashMap<>();
        if (outRefundNo.contains("XCX")) {
            //小程序微信退款
            params.put("appid", appid);
        } else if (outRefundNo.contains("APP")) {
            //APP微信退款
            params.put("appid", app_appid);
        }
        params.put("mch_id", mch_id);
        params.put("nonce_str", System.currentTimeMillis() / 1000 + "");
        //商户订单号和微信订单号二选一
//        params.put("out_trade_no", wxPayLog.getOutTradeNo());
        params.put("transaction_id", transactionId);
        params.put("out_refund_no", outRefundNo);
        params.put("total_fee", total.multiply(BigDecimal.valueOf(100)).intValue() + "");
        params.put("refund_fee", refund.multiply(BigDecimal.valueOf(100)).intValue() + "");
        params.put("refund_account", refundAccount);
        // 退款原因，若商户传入，会在下发给用户的退款消息中体现退款原因
        params.put("refund_desc", "退款");
        //退款回调
        //    params.put("notify_url", pc_bond_refund_notify_url);
        //签名算法
        String sign = WXPayUtil.generateSignature(params, key);
        params.put("sign", sign);
        String xml = PaymentKit.toXml(params);
        log.info(xml);
        String xmlStr = WXPayUtil.doRefund("https://api.mch.weixin.qq.com/secapi/pay/refund", xml, cert_url, mch_id);
        log.info(xmlStr);
        //加入微信支付日志
        Map map = PaymentKit.xmlToMap(xmlStr);
        return map;
    }


    public String getCollectionCode(String orderTradeNo, BigDecimal money, String ip, String tradeType) throws Exception {
        Map<String, String> reqParams = new HashMap<>();
        //微信分配的小程序ID
        reqParams.put("appid", appid);
        //微信支付分配的商户号
        reqParams.put("mch_id", mch_id);
        //随机字符串
        reqParams.put("nonce_str", System.currentTimeMillis() / 1000 + "");
        //签名类型
        reqParams.put("sign_type", "MD5");
        //充值订单 商品描述
        reqParams.put("body", "充值" + orderTradeNo + "订单-微信小程序");

        //商户订单编号
        reqParams.put("out_trade_no", orderTradeNo);
        //订单总金额，单位为分
        reqParams.put("total_fee", money.multiply(BigDecimal.valueOf(100)).intValue() + "");
        //终端IP
//        reqParams.put("spbill_create_ip", "127.0.0.1");
        reqParams.put("spbill_create_ip", ip);
        //支付回调地址
        //    reqParams.put("notify_url", pc_notify_url);
        //交易类型
        reqParams.put("trade_type", tradeType);
        //用户标识
//        reqParams.put("openid", openid);
        //签名
        String sign = WXPayUtil.generateSignature(reqParams, key);
        reqParams.put("sign", sign);
        /*
            调用支付定义下单API,返回预付单信息 prepay_id
         */
        String xmlResult = PaymentApi.pushOrder(reqParams);
        log.info(xmlResult);
        Map<String, String> result = PaymentKit.xmlToMap(xmlResult);
        return result.get("code_url");
    }

    public boolean verifyNotify(Map<String, String> params) {
        return PaymentKit.verifyNotify(params, key);
    }

    @Override
    public void afterPropertiesSet() throws Exception {
        log.info("微信支付配置读取Bean初始化成功");
    }
}
