package com.sv.service.api.config;

import com.dw.ccm.wechat.base.pay.CommonUtils;
import com.dw.ccm.wechat.base.pay.MD5Utils;
import com.dw.ccm.wechat.base.pay.WeChatPayHelper;
import com.dw.ccm.wechat.base.pay.response.OrderResponse;
import com.enums.MoneyLogEnum;
import com.enums.OrderTypeEnum;
import com.enums.PayTypeEnum;
import com.google.common.collect.Maps;
import com.sv.dto.api.wechat.OrderPaySignResponse;
import com.sv.entity.*;
import com.sv.service.api.*;
import com.sv.service.api.util.EncryptionUtil;
import com.sv.service.api.util.XmlUtils;
import com.ydd.framework.core.common.utils.JsonMapper;
import com.ydd.framework.core.exception.ServiceException;
import com.ydd.framework.core.service.impl.BaseServiceImpl;
import org.apache.commons.lang3.builder.ToStringBuilder;
import org.apache.commons.lang3.time.DateFormatUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.Assert;

import javax.annotation.Resource;
import java.io.IOException;
import java.math.BigDecimal;
import java.util.*;


@Service
public class WechatPayService extends BaseServiceImpl {
    private Logger logger = LoggerFactory.getLogger(WechatPayService.class);

    @Resource
    private MemberAuthService memberAuthService;
    @Resource
    private PayConfigService payConfigService;
    @Resource
    private OrderService orderService;
    @Resource
    private MemberCardOrderService memberCardOrderService;
    @Resource
    private MemberCardService memberCardService;
    @Resource
    private MemberMoneyLogService memberMoneyLogService;
    @Resource
    private MemberLessonTicketService memberLessonTicketService;
    @Resource
    private MemberRefundService memberRefundService;

    /**
     * 创建微信支付的统一订单
     *
     * @return
     */
    @Transactional
    public OrderPaySignResponse.WechatPayParam createUnifiedOrder(String orderSn, BigDecimal money, String ip, String tradeType, Integer memberId) {
        OrderPaySignResponse.WechatPayParam wechatPayParam;
        try {
            // 设置过期时间
            Date current = getCurrentTime();
            Calendar expire = Calendar.getInstance();
            expire.setTime(current);
            expire.add(Calendar.HOUR_OF_DAY, 24);
            PayConfig payConfig = payConfigService.findKey("face");
            Assert.hasText(payConfig.getCert(), "证书找不到");
            String nonceStr = CommonUtils.CreateNonceStr(30);
            WeChatPayHelper weChatPayHelper = new WeChatPayHelper(payConfig.getCert());
            weChatPayHelper.setAppId(payConfig.getAppId());
            weChatPayHelper.setMchId(payConfig.getMchId());
            weChatPayHelper.setKey(payConfig.getKey());
            weChatPayHelper.setParameter("nonce_str", nonceStr);
            weChatPayHelper.setParameter("body", "购买商品");
            weChatPayHelper.setParameter("detail", "商品");
            weChatPayHelper.setParameter("out_trade_no", orderSn);
            String payMoney = money.multiply(new BigDecimal(100))
                    .setScale(0, BigDecimal.ROUND_HALF_UP).toString();
            weChatPayHelper.setParameter("total_fee", payMoney); // 微信总金额为分
            weChatPayHelper.setParameter("spbill_create_ip", ip);
            weChatPayHelper.setParameter("time_start", DateFormatUtils.format(current, "yyyyMMddHHmmss"));
            weChatPayHelper.setParameter("notify_url", payConfig.getNotifyUrl());
            weChatPayHelper.setParameter("trade_type", tradeType);
            //使用公众号的appid
            MemberAuth memberAuth = memberAuthService.findByMemberId(memberId);
            weChatPayHelper.setParameter("openid", memberAuth.getAuthId());

            logger.info("统一订单请求参数" + ToStringBuilder.reflectionToString(weChatPayHelper));
            // 调用统一下单接口
            OrderResponse response = weChatPayHelper.unifiedOrder();

            // 记录统一下单接口返回
            logger.info(ToStringBuilder.reflectionToString(response));
            System.out.println(ToStringBuilder.reflectionToString(response));
            if (response.isSuccess()) {
                wechatPayParam = this.createGzhBizPackage(response,payConfig);
                orderService.updatePrepayId(orderSn,response.getPrepayId());
                logger.info("返回的结果为：" + ToStringBuilder.reflectionToString(wechatPayParam));
            } else {
                logger.error("返回的结果为："+ToStringBuilder.reflectionToString(response));
                throw new RuntimeException("统一支付订单创建失败，请重试！");
            }
        } catch (Exception e) {
            e.printStackTrace();
            logger.error("创建统一支持订单接口异常", e);
            throw new ServiceException("系统异常");
        }
        wechatPayParam.setOrderSn(orderSn);
        return wechatPayParam;
    }


    /**
     * 创建客户端需要的支付参数，微信公众号登录
     *
     * @param response
     * @return
     */
    private OrderPaySignResponse.WechatPayParam createGzhBizPackage(OrderResponse response,PayConfig payConfig) {
        OrderPaySignResponse.WechatPayParam wechatPayParam = new OrderPaySignResponse.WechatPayParam();
        Map<String, String> param = Maps.newHashMap();
        param.put("appId", payConfig.getAppId());
        param.put("nonceStr", CommonUtils.CreateNonceStr(30));
        param.put("package", "prepay_id=" + response.getPrepayId()); //prepay_id需要存到数据库
        param.put("signType", "MD5");
        param.put("timeStamp", String.valueOf(System.currentTimeMillis() / 1000));
        param.put("paySign", CommonUtils.getSign(param, payConfig.getKey()));
        wechatPayParam.setAppId(param.get("appId"));
        wechatPayParam.setPrepayId(response.getPrepayId());
        wechatPayParam.setTimeStamp(param.get("timeStamp"));
        wechatPayParam.setPaySign(param.get("paySign"));
        wechatPayParam.setNonceStr(param.get("nonceStr"));
        wechatPayParam.setSignType("MD5");
        return wechatPayParam;
    }

    @Transactional
    public void notify(Map<String,String> params ) throws IOException {
        logger.info("微信回调参数:" + JsonMapper.nonNullMapper().toJson(params));
        // 读取输入流
        if (params.get("return_code").equals("SUCCESS")) {
            if (params.get("result_code").equals("SUCCESS")) {
                String orderSn = params.get("out_trade_no");
                Order order = orderService.findByOrderSn(orderSn,null);
                if (order.getPayStatus().intValue() > 0) {
                    //已支付 不需要在判断
                    return;
                }
                if (!checkWxXml(params)) {
                    return;
                }
                String outTradeSn = params.get("transaction_id");
                // 异步成功修改状态
                orderService.paySuccess(order.getId(),outTradeSn);

                // 会员卡购买
                if (order.getType().intValue() == OrderTypeEnum.VIP_ORDER.value){
                    // 修改用户会员卡订单pay_status为1已支付
                    MemberCardOrder memberCardOrder = memberCardOrderService.paySuccess(orderSn);
                    // 添加用户会员卡
                    if (memberCardOrder != null) {
                        memberCardService.createCard(memberCardOrder,order.getPrice());
                    }
                }

                // 余额充值，添加用户余额记录，用户表中余额增加
                if (order.getType().intValue() == OrderTypeEnum.BALANCE_ORDER.value){
                    memberMoneyLogService.create(order.getMemberId(),order.getPlatformId(),MoneyLogEnum.RECHARGE.value,order.getToMoney(),PayTypeEnum.WEI_XIN.value,null,null,null,null);
                }

                // 预约课程,修改‘用户预约的场馆课程票号’支付状态：1已支付
                if (order.getType().intValue() == OrderTypeEnum.COURSE_ORDER.value){
                    memberLessonTicketService.paySuccess(order);
                }

            }
        }
    }


    private boolean checkWxXml( Map<String,String> params) throws IOException {
        String signFromAPIResponse = params.get("sign").toString();
        if (signFromAPIResponse == "" || signFromAPIResponse == null) {
            logger.info("API返回的数据签名数据不存在，有可能被第三方篡改!!!");
            return false;
        }
        //清掉返回数据对象里面的Sign数据（不能把这个数据也加进去进行签名），然后用签名算法进行签名
        params.put("sign", "");
        String signForAPIResponse = getSign(params);
        logger.info("签名验证后的sign:"+signForAPIResponse+"  微信回调传入的sign:"+signFromAPIResponse);
        if (!signForAPIResponse.equalsIgnoreCase(signFromAPIResponse)) {
            logger.info("API返回的数据签名数据不一样，有可能被第三方篡改!!!");
            return false;
        }
        return true;
    }

    private String getSign(Map<String, String> map) {
        SortedMap<String, String> signParams = new TreeMap<>();
        for (Map.Entry<String, String> stringStringEntry : map.entrySet()) {
            signParams.put(stringStringEntry.getKey(), stringStringEntry.getValue());
        }
        signParams.remove("sign");
        PayConfig payConfig = payConfigService.findKey("face");
        String sign =  CommonUtils.getSign(signParams, payConfig.getKey());
        return sign;
    }

    /**
     * 退款接口
     */
    public void refundMoney(MemberRefund memberRefund){
        OrderPaySignResponse.WechatPayParam wechatPayParam;
        try {

            PayConfig payConfig = payConfigService.findKey("face");
            Assert.hasText(payConfig.getCert(), "证书找不到");
            String nonceStr = CommonUtils.CreateNonceStr(30);
            WeChatPayHelper weChatPayHelper = new WeChatPayHelper(payConfig.getCert());
            weChatPayHelper.setAppId(payConfig.getAppId());
            weChatPayHelper.setMchId(payConfig.getMchId());
            weChatPayHelper.setKey(payConfig.getKey());
            Integer payMoney = Integer.valueOf(memberRefund.getMoney().multiply(new BigDecimal(100)).setScale(0, BigDecimal.ROUND_HALF_UP).toString());
            Integer refundMoney = Integer.valueOf(memberRefund.getMoney().multiply(new BigDecimal(100)).setScale(0, BigDecimal.ROUND_HALF_UP).toString());
            weChatPayHelper.setParameter("notify_url", payConfig.getNotifyUrl());

            logger.info("申请退款请求参数" + ToStringBuilder.reflectionToString(weChatPayHelper));
            // 调用申请退款
//            String notifyUrl = "https://api.smartvenue.ydd100.cn//weixin/order/refund";
            OrderResponse response = weChatPayHelper.refund("",memberRefund.getOrderSn(),memberRefund.getOutRefundNo(),payMoney,refundMoney,payConfig.getCancel());
            logger.info(ToStringBuilder.reflectionToString(response));
            System.out.println(ToStringBuilder.reflectionToString(response));
            if (response.isSuccess()) {
                    String refundId = response.getRefundId();
                    //更新‘用户退款记录表’中微信退款单号
                    memberRefund.setRefundId(refundId);
                    memberRefundService.update(memberRefund);
            }else{
                logger.error("返回的结果为："+ToStringBuilder.reflectionToString(response));
                throw new RuntimeException("申请退款订单创建失败，请重试！");
            }
        } catch (Exception e) {
            e.printStackTrace();
            logger.error("申请退款支持订单接口异常", e);
            throw new ServiceException("");
        }
    }

    @Transactional
    public void notifyRefund(Map<String,String> params,Integer platformId ) throws IOException {
        logger.info("微信退款回调参数:" + JsonMapper.nonNullMapper().toJson(params));

        // 读取输入流
        if (params.get("return_code").equals("SUCCESS")) {
            String reqInfo = params.get("req_info");//加密信息
            PayConfig payConfig = payConfigService.findKey("face"); //得到秘钥
            String key = MD5Utils.md5(payConfig.getKey()).toString();
            key = key.toLowerCase();
            String refundInfo = EncryptionUtil.Aes256Decode(reqInfo,key);
            Map<String,Object> map = XmlUtils.getResult(refundInfo);

            // 更新‘用户退款记录表’
            String refundStatus = map.get("refund_status").toString(); //退款状态
            String outTradeNo =  map.get("out_trade_no").toString(); //商户订单号
            String successTime =  map.get("success_time").toString(); //退款成功时间
            memberRefundService.updateInfo(refundStatus,outTradeNo,successTime,platformId);

        }
    }
}
