package com.iformall.service.impl;

import cn.binarywang.wx.miniapp.bean.WxMaTemplateData;
import com.alibaba.fastjson.JSONObject;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import com.google.common.collect.Lists;
import com.iformall.common.ErrorCode;
import com.iformall.common.IdWorker;
import com.iformall.common.Result;
import com.iformall.common.ResultData;
import com.iformall.domain.dto.WxSharingOrderDto;
import com.iformall.domain.po.*;
import com.iformall.domain.po.msg.AppUniformMsg;
import com.iformall.domain.po.msg.MpAppMsg;
import com.iformall.domain.po.msg.SmartAppMsg;
import com.iformall.domain.vo.*;
import com.iformall.enums.*;
import com.iformall.exception.MallinkException;
import com.iformall.mapper.*;
import com.iformall.mq.MqBaseProducer;
import com.iformall.service.*;
import com.iformall.utils.DateUtils;
import me.chanjar.weixin.mp.bean.template.WxMpTemplateData;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.math.BigDecimal;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.*;

@Service
public class WxCouponOrderServiceImpl implements WxCouponOrderService {
    private final Logger logger = LoggerFactory.getLogger(this.getClass());

    @Autowired
    WxCouponOrderMapper wxCouponOrderMapper;

    @Autowired
    WxOrderMapper wxOrderMapper;

    @Autowired
    WxMerchantMapper wxMerchantMapper;

    @Autowired
    WxCouponMerchantMapper wxCouponMerchantMapper;

    @Autowired
    WxMerchantBUserMapper wxMerchantBUserMapper;

    @Autowired
    WxCUserMapper wxCUserMapper;

    @Autowired
    WxOrderService wxOrderService;

    @Autowired
    WxCouponSendService wxCouponSendService;

    @Autowired
    WxProfitSharingOrderService wxProfitSharingOrderService;

    @Autowired
    WxPayOrderMapper wxPayOrderMapper;

    @Autowired
    WxMallMapper wxMallMapper;

    @Autowired
    WxTemplateMsgMapper wxTemplateMsgMapper;

    @Autowired
    WxCouponMapper wxCouponMapper;

    @Autowired
    WxAppinfoService wxAppinfoService;

    @Autowired
    WxMerchantSubsidyMapper wxMerchantSubsidyMapper;

    @Autowired
    WxPayAccountMapper wxPayAccountMapper;

    @Autowired
    WxCardInfoMapper wxCardInfoMapper;

    @Autowired
    WxCardTransferInfoMapper wxCardTransferInfoMapper;

    @Autowired
    WxCouponChannelMapper wxCouponChannelMapper;

    @Autowired
    MqBaseProducer mqBaseProducer;

    @Autowired
    WxAuthorizerInfoMapper authorizerInfoMapper;

    @Autowired
    ExcelService excelService;

    @Override
    public PageInfo<WxCouponOrder> listAsPage(WxCouponOrder record, Integer pageIndex, Integer pageSize) {
        return PageHelper.startPage(pageIndex, pageSize).doSelectPageInfo(() -> wxCouponOrderMapper.findList(record));
    }

    @Override
    public WxCouponOrder getById(Long id) {
        return wxCouponOrderMapper.selectByPrimaryKey(id);
    }

    @Override
    public void saveOrUpdate(WxCouponOrder record) {
        if (record.getId() == null) {
            //record.setId(UUID.randomUUID().toString().replaceAll("-", ""));
            final IdWorker idWorker = IdWorker.get();
            record.setId(idWorker.nextId());
            wxCouponOrderMapper.insertSelective(record);
        } else {
            wxCouponOrderMapper.updateByPrimaryKeySelective(record);
        }
    }

    @Override
    public void deleteById(Long id) {
        wxCouponOrderMapper.deleteByPrimaryKey(id);
    }


    @Override
    public ResultData listOnDateAsPage(Long bUserId, String date, Integer pageIndex, Integer pageSize, boolean isVerified) {

        WxMerchantBUser wxMerchantBUser = wxMerchantBUserMapper.selectByPrimaryKey(bUserId.longValue());
        if (wxMerchantBUser == null) {
            logger.error("核销员不存在:" + bUserId);
            throw new MallinkException(ErrorCode.MERCHANT_INFO_NOT_FOUND);
        }

        WxMerchant wxMerchant = wxMerchantMapper.selectByPrimaryKey(wxMerchantBUser.getMerchantId());
        if (wxMerchant == null) {
            logger.error("商户不存在:" + bUserId);
            throw new MallinkException(ErrorCode.MERCHANT_INFO_NOT_FOUND);
        }

        SimpleDateFormat fmt = new SimpleDateFormat("yyyy-MM-dd");
        String dateString;
        Date startDate;
        Date endDate;

        if (date == null) {
            endDate = new Date();
            dateString = fmt.format(new Date());
            try {
                startDate = fmt.parse(dateString);
            } catch (ParseException e) {
                return new ResultData(ErrorCode.SYS_PARAMETER_CAST_ERROR);
            }
        } else {
            try {
                startDate = fmt.parse(date);
            } catch (ParseException e) {
                return new ResultData(ErrorCode.SYS_PARAMETER_CAST_ERROR);
            }
            Calendar cal = Calendar.getInstance();
            cal.setTime(startDate);
            cal.add(Calendar.DATE, 1);
            endDate = cal.getTime();
        }

        Map dateMap = new HashMap();
        dateMap.put("startDate", startDate);
        dateMap.put("endDate", endDate);
        dateMap.put("merchantId", wxMerchant.getId());

        Map resultMap = new HashMap();

        if (pageIndex == null || pageSize == null) {
            List<WxCouponOrder> list;
            if (isVerified)
                list = wxCouponOrderMapper.findListOfVerifiedByDate(dateMap);
            else
                list = wxCouponOrderMapper.findListOfOrderedByDate(dateMap);
            //logger.info("find " + list.size() + " coupon order from " + /startDate + " to " + new Date());
            resultMap.put("amount", list.stream().mapToInt(p->p.getCouponPrice()).sum());
        } else {
            if (isVerified)
                resultMap.put("list", PageHelper.startPage(pageIndex, pageSize).doSelectPageInfo(() -> wxCouponOrderMapper.findListOfVerifiedByDateForBUser(dateMap)));
            else
                resultMap.put("list", PageHelper.startPage(pageIndex, pageSize).doSelectPageInfo(() -> wxCouponOrderMapper.findListOfOrderedByDateForBUser(dateMap)));
        }
        return new ResultData(resultMap);
    }

    @Override
    public PageInfo<WxCouponOrderCVo> listCUserVoAsPage(WxCouponOrder record, Integer pageIndex, Integer pageSize) {

        return  PageHelper.startPage(pageIndex, pageSize).doSelectPageInfo(() -> wxCouponOrderMapper.findListOfCUser(record));
    }

    @Override
    public WxCouponOrderCVo detailCUserVo(String couponOrderId) {

        WxCouponOrderCVo wxCouponOrderCVo = wxCouponOrderMapper.findDetailOfCUser(Long.valueOf(couponOrderId));
        if (wxCouponOrderCVo == null)
            throw new MallinkException(ErrorCode.COUPON_ORDER_IS_NULL);
        return wxCouponOrderCVo;
    }


    @Override
    public ResultData carListCUserVoAsPage(WxCouponOrder record, Integer pageIndex, Integer pageSize) {
        return new ResultData(PageHelper.startPage(pageIndex, pageSize).doSelectPageInfo(() -> wxCouponOrderMapper.findCarListOfCUser(record)));
    }

    @Override
    public List<WxCouponOrderCarCVo> carListCUserVo(WxCouponOrder record) {
        return wxCouponOrderMapper.findCarListOfCUser(record);
    }

    @Override
    public ResultData detailBUserVo(Long bUserId, String couponOrderId) {
        WxMerchantBUser wxMerchantBUser = wxMerchantBUserMapper.selectByPrimaryKey(bUserId);
        if (wxMerchantBUser == null) {
            logger.error("用户不存在:" + bUserId);
            throw new MallinkException(ErrorCode.USER_IS_EMPTY);
        }

        WxMerchant wxMerchant = wxMerchantMapper.selectByPrimaryKey(wxMerchantBUser.getMerchantId());
        if (wxMerchant == null) {
            logger.error("商户不存在:" + bUserId);
            throw new MallinkException(ErrorCode.MERCHANT_INFO_NOT_FOUND);
        }
        WxCouponOrderCVo wxCouponOrderCVo = null;
        try {
            wxCouponOrderCVo = wxCouponOrderMapper.findDetailOfCUser(Long.valueOf(couponOrderId));
        } catch (Exception e) {
            return new ResultData(ErrorCode.COUPON_ORDER_IS_NULL);
        }
        if (wxCouponOrderCVo == null)
            return new ResultData(ErrorCode.COUPON_ORDER_IS_NULL);
        return new ResultData(wxCouponOrderCVo);
    }

    @Override
    public ResultData listAdminAsPage(WxCouponOrderBVo wxCouponOrderBVo, Integer pageIndex, Integer pageSize) {
        PageInfo<WxCouponOrderBVo> pageInfo= PageHelper.startPage(pageIndex, pageSize).doSelectPageInfo(() -> wxCouponOrderMapper.findListOfAdmin(wxCouponOrderBVo));
        return new ResultData(pageInfo);
    }

    @Override
    public ResultData detailAdminVo(Long couponOrderId) {

        WxCouponOrderBVo wxCouponOrderBVo = wxCouponOrderMapper.findDetailOfAdmin(couponOrderId);
        if (wxCouponOrderBVo == null)
            return new ResultData(ErrorCode.COUPON_ORDER_IS_NULL);
        return new ResultData(wxCouponOrderBVo);
    }

    @Override
    public void exportData(HttpServletRequest request, HttpServletResponse response, WxCouponOrderBVo wxCouponOrder) {
        WxMall wxMall = new WxMall();
        wxMall.setTenantId(wxCouponOrder.getTenantId());
        wxMall = wxMallMapper.findList(wxMall).get(0);
        String filename = wxMall.getName() + DateUtils.getSystemTime("yyyyMMDDHHmmss");
        List<WxCouponOrderBVo> list = wxCouponOrderMapper.findListOfAdmin(wxCouponOrder);
        excelService.exportExcel(list, null, filename, WxCouponOrderBVo.class, filename + ".xls", response);
    }

    @Override
    @Transactional(propagation = Propagation.REQUIRED, readOnly = false, rollbackFor = {Exception.class})
    public WxCouponOrder verify(Long couponOrderId, Long bUserId) {

        WxCouponOrder wxCouponOrder = wxCouponOrderMapper.selectByPrimaryKey(couponOrderId);
        if (wxCouponOrder == null) {
            logger.error("券ID不存在:" + couponOrderId);
            throw new MallinkException(ErrorCode.COUPON_ORDER_IS_NULL);
        }

        WxMerchantBUser wxMerchantBUser = wxMerchantBUserMapper.selectByPrimaryKey(bUserId.longValue());
        if (wxMerchantBUser == null) {
            logger.error("核销员ID不存在:" + bUserId);
            throw new MallinkException(ErrorCode.COUPON_ORDER_IS_NULL);
        }

        WxCoupon wxCoupon = wxCouponMapper.selectByPrimaryKey(wxCouponOrder.getCouponId());
        if (wxCoupon == null) {
            logger.error("券: coupon-" + wxCoupon.getId() + "不存在" + "couponOrder-" + wxCouponOrder.getId());
            throw new MallinkException(ErrorCode.COUPON_ORDER_IS_NULL);
        }else {
            WxCouponMerchant wxCouponMerchant = new WxCouponMerchant();
            wxCouponMerchant.setProductId(wxCoupon.getId());
            wxCouponMerchant.setStatus(EnumCouponMerchantStatus.COUPON_MERCHANT_STATUS_VALID.getCode());
            List<WxCouponMerchant>  couponMerchantList = wxCouponMerchantMapper.findList(wxCouponMerchant);
            if (!couponMerchantList.stream().anyMatch(cm->cm.getMerchantId().equals(wxMerchantBUser.getMerchantId()))){
                logger.error("券: coupon-" + wxCoupon.getId() + "核销: couponMerchantId-" + wxMerchantBUser.getMerchantId());
                throw new MallinkException(ErrorCode.COUPON_ORDER_IS_NULL);
            }
        }


        if (wxCouponOrder.getCouponOrderStatus() == EnumCouponOrderStatus.COUPON_ORDER_OVER_TIME.getCode()) {
            logger.error("已过期: couponOrder-" + wxCouponOrder.getId());
            throw new MallinkException(ErrorCode.COUPON_ORDER_IS_OVER_TIME);
        }
        if (wxCouponOrder.getCouponOrderStatus() == EnumCouponOrderStatus.COUPON_ORDER_INVALID.getCode()) {
            logger.error("已退款: couponOrder-" + wxCouponOrder.getId());
            throw new MallinkException(ErrorCode.COUPON_ORDER_IS_INVALID);
        }
        if (wxCouponOrder.getCouponOrderStatus() == EnumCouponOrderStatus.COUPON_ORDER_USED.getCode()) {
            logger.error("已经核销过的券: couponOrder-" + wxCouponOrder.getId());
            throw new MallinkException(ErrorCode.COUPON_ORDER_IS_USED);
        }
        try {
            wxCouponOrder.setCouponOrderStatus(EnumCouponOrderStatus.COUPON_ORDER_USED.getCode()); //1核销
            wxCouponOrder.setbUserId(wxMerchantBUser.getId());
            wxCouponOrder.setUpdateDate(new Date());
            wxCouponOrderMapper.updateByPrimaryKeySelective(wxCouponOrder);
        } catch (Exception e) {
            logger.error("db failed: couponOrder-" + wxCouponOrder.getId() + ", e:" + e.getMessage());
            throw new MallinkException(ErrorCode.DB_FAIL.getCode(), "DB FAILD " + e.getMessage());
        }

        return wxCouponOrder;


    }

    @Override
    @Transactional(propagation = Propagation.REQUIRED, readOnly = false, rollbackFor = {Exception.class})
    public void shareAfterVerify(WxCouponOrder couponOrder, Long merchantId) {
        // 微信分账
        try {
            WxPayOrder wxPayOrder = new WxPayOrder();
            wxPayOrder.setTenantId(couponOrder.getTenantId());
            wxPayOrder.setOrderId(couponOrder.getOrderId());
            wxPayOrder.setPayOrderStatus(EnumPayStatus.PAY_STATUS_SUCCESS.getCode());
            wxPayOrder = wxPayOrderMapper.selectOne(wxPayOrder);
            if (wxPayOrder != null && wxPayOrder.getShare().equals(EnumPayShare.YES.getCode())) {
                WxSharingOrderDto wxSharingOrderDto = new WxSharingOrderDto();
                wxSharingOrderDto.setcUserId(wxPayOrder.getcUserId());
                wxSharingOrderDto.setMerchantId(merchantId);
                wxSharingOrderDto.setType(EnumProfitSharingOrderType.PROFIT_SHARING_SINGLE.getCode());
                wxSharingOrderDto.setPayAmount(wxPayOrder.getPayAmount());
                wxSharingOrderDto.setOrderId(wxPayOrder.getId());
                wxSharingOrderDto.setPayTimeStart(wxPayOrder.getPayTimeStart());
                wxSharingOrderDto.setPayTimeEnd(wxPayOrder.getPayTimeEnd());
                wxSharingOrderDto.setTenantId(wxPayOrder.getTenantId());
                wxSharingOrderDto.setTransactionId(wxPayOrder.getTransactionId());
                wxSharingOrderDto.setShareAmount(wxPayOrder.getShareAmount());
                wxProfitSharingOrderService.createSharingOrder(wxSharingOrderDto);
            }
        } catch (Exception e) {
            logger.error("微信分账: " + e.getMessage());
        }
    }


    // 补贴
    @Override
    @Transactional(propagation = Propagation.REQUIRED, readOnly = false, rollbackFor = {Exception.class})
    public void subsidyAfterVerify(WxCouponOrder couponOrder, Long merchantId) {
        final IdWorker idWorker = IdWorker.get();

        WxCouponMerchant couponMerchantQ = new WxCouponMerchant();

        couponMerchantQ.setProductId(couponOrder.getCouponId());
        couponMerchantQ.setMerchantId(merchantId);
        WxCouponMerchant couponMerchant;
        try {
            couponMerchant = wxCouponMerchantMapper.selectOne(couponMerchantQ);
        }catch (Exception e) {
            logger.error("查找所属卡券商户错误: " + "CouponId:" + couponMerchantQ.getProductId(), " merchantId:" + merchantId );
            throw new MallinkException(ErrorCode.SYS_PARAMETER_ERROR);
        }

        if (couponMerchant == null) {
            logger.error("未找到所属卡券商户: " + "CouponId:" + couponMerchantQ.getProductId(), " merchantId:" + merchantId);
            throw new MallinkException(ErrorCode.SYS_PARAMETER_ERROR);
        }

        // coupon
        WxCoupon coupon;
        try {
            coupon = wxCouponMapper.selectByPrimaryKey(couponOrder.getCouponId());
        }catch (Exception e) {
            logger.error("查找卡券错误: " + "CouponId:" + couponMerchantQ.getProductId());
            throw new MallinkException(ErrorCode.SYS_PARAMETER_ERROR);
        }

        WxAppinfo wxAppinfo = wxAppinfoService.getCAppInfo(couponOrder.getTenantId());
        WxPayAccount payAccount = wxPayAccountMapper.selectByPrimaryKey(wxAppinfo.getPayId());

        Integer subsidyNum = coupon.getSubsidyNum();
        if (subsidyNum == null || subsidyNum.intValue() == 0) {
            String parameter = couponMerchant.getParameter();
            try {
                JSONObject jParameter = JSONObject.parseObject(parameter);
                subsidyNum = new BigDecimal(jParameter.getString("subsidyNumStr")).multiply(new BigDecimal(100)).intValue();
            } catch (Exception e) {
                subsidyNum = null;
            }
        }
        if (subsidyNum != null && subsidyNum.intValue() > 0) {
            // 有补贴时入库
            Double dSubChargeFee = Math.ceil(subsidyNum * 1.0D * payAccount.getRate() / 10000);
            Integer realSubsidyFee = subsidyNum - dSubChargeFee.intValue();

            Double priceChargeFee = Math.ceil(coupon.getSalePrice() * 1.0D * payAccount.getRate() / 10000);
            Integer realPayment = coupon.getSalePrice() - priceChargeFee.intValue();

            WxMerchantSubsidy merchantSubsidy = new WxMerchantSubsidy();
            merchantSubsidy.setId(idWorker.nextId());
            merchantSubsidy.setTenantId(couponOrder.getTenantId());
            merchantSubsidy.setOrderId(couponOrder.getOrderId());
            merchantSubsidy.setOrderType(EnumOrderType.COUPON.getCode());
            merchantSubsidy.setMerchantId(merchantId);
            merchantSubsidy.setCouponOrderId(couponOrder.getId());
            merchantSubsidy.setCouponType(couponOrder.getCouponType());
            merchantSubsidy.setOrderPayment(coupon.getPrice());
            merchantSubsidy.setReceiverPayment(coupon.getSalePrice());
            merchantSubsidy.setRealPayment(realPayment);
            merchantSubsidy.setSubsidy(subsidyNum);
            merchantSubsidy.setRealSubsidy(realSubsidyFee);
            merchantSubsidy.setStatus(EnumMerchantSubsidyStatus.NOT_SUBSIDY.getCode());
            merchantSubsidy.setCreateDate(new Date());
            merchantSubsidy.setUpdateDate(new Date());
            try {
                wxMerchantSubsidyMapper.insertSelective(merchantSubsidy);
            } catch (Exception e) {
                logger.error("数据库插入错误:" + e.getMessage());
                throw new MallinkException(ErrorCode.DB_FAIL);
            }
        }
    }

    @Override
    public boolean sendCouponAfterVerify(WxCouponOrder couponOrder, WxMerchantBUser bUser) {
        // 核销发券
        WxOrder wxOrder = wxOrderMapper.selectByPrimaryKey(couponOrder.getOrderId());
        if (wxOrder != null) {
            try {
                return wxCouponSendService.sendCouponToUser(EnumCouponSendSendType.COUPON_VERIFY, wxOrder);
            } catch (Exception e) {
                logger.error("核销发券: " + e.getMessage());
            }
        }
        return false;
    }

    @Override
    public boolean sendCouponAfterMicroPay(String tenantId, Long orderId, Long cUserId) {
        // B端刷卡支付发券
        WxOrder wxOrder = wxOrderMapper.selectByPrimaryKey(orderId);
        if (wxOrder != null) {
            try {
                return wxCouponSendService.sendCouponToUser(EnumCouponSendSendType.B_MICROPAY, wxOrder);
            } catch (Exception e) {
                logger.error("B端刷卡支付发券: " + e.getMessage());
            }
        }
        return false;
    }

    /**
     * 微信模板消息
     *
     * @param couponOrder, bUser
     */
    @Override
    public void sendVerifyMsg(WxCouponOrder couponOrder, WxMerchantBUser bUser, boolean hadSentCoupon) {
        // 1. get order info
        WxOrder order = wxOrderMapper.selectByPrimaryKey(couponOrder.getOrderId());
        if (order == null) {
            logger.error("找不到订单信息");
            throw new MallinkException(ErrorCode.ORDER_IS_NOT_FIND);
        }
        String formId = null;
        if(StringUtils.isNotBlank(order.getFormId())) {
            formId = order.getFormId();
        }
        // 2. get coupon info
        WxCoupon coupon = wxCouponMapper.selectByPrimaryKey(couponOrder.getCouponId());
        if (coupon == null) {
            logger.error("找不到券信息");
            throw new MallinkException(ErrorCode.COUPON_IS_EMPTY);
        }
        // 3. merchant info
        WxMerchant merchant = wxMerchantMapper.selectByPrimaryKey(bUser.getMerchantId());
        if (merchant == null) {
            logger.error("找不到商户信息");
            throw new MallinkException(ErrorCode.MERCHANT_INFO_NOT_FOUND);
        }
        // 4. get user info
        WxCUser user = wxCUserMapper.selectByPrimaryKey(order.getcUserId());
        if (user == null) {
            logger.error("找不到C端用户");
            throw new MallinkException(ErrorCode.USER_IS_EMPTY);
        }

        // 5. get app info
//        WxAppinfo appInfo = wxAppinfoService.getByAppId(user.getAppId());

        // 6. get payOrder info
        if(StringUtils.isBlank(order.getFormId())) {
            WxPayOrder payOrder = null;
            WxPayOrder payOrderQ = new WxPayOrder();
            payOrderQ.setTenantId(couponOrder.getTenantId());
            payOrderQ.setOrderId(order.getId());
            payOrderQ.setPayOrderStatus(EnumPayStatus.PAY_STATUS_SUCCESS.getCode());
            List<WxPayOrder> payList = wxPayOrderMapper.select(payOrderQ);
            if (payList.size() > 0) {
                payOrder = payList.get(0);
            }
            if (payOrder == null) {
                logger.error("找不到payOrder信息");
                throw new MallinkException(ErrorCode.PAY_ORDER_NOT_FOUND);
            }
            if (payOrder.getPrepayId() == null) {
                logger.error("payOrder信息中，prepay_id为空");
                throw new MallinkException(ErrorCode.PREPAY_ID_IS_EMPTY);
            }
            formId = payOrder.getPrepayId();
        }

        if(StringUtils.isBlank(formId)) {
            logger.error("formId为空");
            throw new MallinkException(ErrorCode.TEMPLATE_FORMID_NOT_FOUND);
        }

        SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS");
        String couponDetail = "";
        if (coupon.getType() == EnumCouponType.COUPON_MANJIAN.getCode()) {
            couponDetail = "满" + coupon.getUsePriceStr() + "减" + coupon.getPriceStr();
        }

        boolean bUsed = false;
        String gotopage = "pages/index/index";
        String notes = "";
        if (couponOrder.getCouponOrderStatus() == EnumCouponOrderStatus.COUPON_ORDER_USED.getCode()) {
            if (hadSentCoupon) {
                gotopage = "pages/couponorder/index/index";
                notes = "您有新的券";
            }
            bUsed = true;
        }

        // 7. 公众号消息
        if(StringUtils.isNotBlank(user.getMpAppId()) &&
                StringUtils.isNotBlank(user.getMpOpenId()) &&
                user.getMpSubscribe().equals(EnumUserIsSubscribe.YES.getCode())) {
            // 已关注公众号
            /**
             * 卡券核销通知
             * {{first.DATA}}
             * 卡券类型：{{keyword1.DATA}}
             * 卡券号码：{{keyword2.DATA}}
             * 核销时间：{{keyword3.DATA}}
             * {{remark.DATA}}
             */
            MpAppMsg mpAppMsg = new MpAppMsg();
            mpAppMsg.setMsgType(EnumMsgRecordType.PUBLIC.getCode());
            mpAppMsg.setAppId(user.getMpAppId());
            mpAppMsg.setTo(user.getMpOpenId());
            mpAppMsg.setMiniAppId(user.getAppId());
            mpAppMsg.setMiniPagePath(gotopage);
            mpAppMsg.setTenantId(couponOrder.getTenantId());
            mpAppMsg.setTemplateType(EnumTemplateType.VERIFY_RESULT.getCode());
            mpAppMsg.setTemplateDataList(Lists.newArrayList(
                    new WxMpTemplateData("first", "商家"+merchant.getName()+"的券被核销", "#173177"),
                    new WxMpTemplateData("keyword1", EnumCouponType.getEnum(coupon.getType()).getMessage(), "#173177"),
                    new WxMpTemplateData("keyword2", couponOrder.getId().toString(), "#173177"),
                    new WxMpTemplateData("keyword3", dateFormat.format(new Date()), "#173177"),
                    new WxMpTemplateData("remark", "更多优惠等您来！", "#173177")
            ));

            try {
                mqBaseProducer.sendMessage(mpAppMsg, EnumMsgMqTopic.DEFAULT.getCode(),EnumMsgMqTag.DEFAULT.getCode(),EnumMsgMqKey.DEFAULT.getCode());
            } catch (Exception e) {
                logger.error("核销-公众号-模板消息发送失败: " + e.getMessage());
                throw new MallinkException(ErrorCode.MP_TEMPLATE_SEND_FAILED);
            }
            return;
        } else {
            // 可能未关注公众号, 用户可能收不到
            // 8. 微信小程序-统一消息
            //  获取小程序关联的服务号
            WxAuthorizerInfo authQ = new WxAuthorizerInfo();
            authQ.setAuthorizerAppid(user.getAppId());
            authQ.setTenantId(user.getTenantId());
            WxAuthorizerInfo weappInfo = authorizerInfoMapper.findMp(authQ);
            if(weappInfo != null) {
                AppUniformMsg appUniformMsg = new AppUniformMsg();
                appUniformMsg.setMsgType(EnumMsgRecordType.SMART_APP_UNIFORM.getCode());
                appUniformMsg.setAppId(user.getAppId());
                appUniformMsg.setTo(user.getOpenId());
                appUniformMsg.setTemplateType(EnumTemplateType.VERIFY_RESULT.getCode());
                appUniformMsg.setPagePath(gotopage);
                appUniformMsg.setUrl("http://iformall.com");
                appUniformMsg.setMpAppId(weappInfo.getAuthorizerAppid());
                appUniformMsg.setTemplateDataList(Lists.newArrayList(
                        new WxMaTemplateData("first", "商家"+merchant.getName()+"的券被核销", "#173177"),
                        new WxMaTemplateData("keyword1", EnumCouponType.getEnum(coupon.getType()).getMessage(), "#173177"),
                        new WxMaTemplateData("keyword2", couponOrder.getId().toString(), "#173177"),
                        new WxMaTemplateData("keyword3", dateFormat.format(new Date()), "#173177"),
                        new WxMaTemplateData("remark", "更多优惠等您来！", "#173177")
                ));
                try {
                    mqBaseProducer.sendMessage(appUniformMsg, EnumMsgMqTopic.DEFAULT.getCode(),EnumMsgMqTag.DEFAULT.getCode(),EnumMsgMqKey.DEFAULT.getCode());
                } catch (Exception e) {
                    logger.error("核销-公众号-模板消息发送失败: " + e.getMessage());
                    throw new MallinkException(ErrorCode.UNIFORM_SEND_FAILED);
                }
            }
        }

        // 9. 微信小程序-模板消息
        SmartAppMsg smartAppMsg;
        if (bUsed) {
            //mq发送小程序消息 - 核销成功消息
            /**
             * 核销成功消息
             * 核销金额 {{keyword1.DATA}}
             * 商家名称 {{keyword2.DATA}}
             * 商品    {{keyword3.DATA}}
             * 商品描述 {{keyword4.DATA}}
             * 订单金额 {{keyword5.DATA}}
             * 核销时间 {{keyword6.DATA}}
             * 温馨提示 {{keyword7.DATA}}
             */
            smartAppMsg = new SmartAppMsg();
            smartAppMsg.setMsgType(EnumMsgRecordType.SMART_APP.getCode());
            smartAppMsg.setAppId(user.getAppId());
            smartAppMsg.setTenantId(couponOrder.getTenantId());
            smartAppMsg.setTemplateType(EnumTemplateType.VERIFY_SUCCESS.getCode());
            smartAppMsg.setGotopage(gotopage);
            smartAppMsg.setTo(user.getOpenId());
            smartAppMsg.setFormId(formId);
            smartAppMsg.setTemplateDataList(Lists.newArrayList(
                    new WxMaTemplateData("keyword1", coupon.getPriceStr() + "元", "#173177"),
                    new WxMaTemplateData("keyword2", merchant.getName(), "#173177"),
                    new WxMaTemplateData("keyword3", coupon.getTitle(), "#173177"),
                    new WxMaTemplateData("keyword4", couponDetail, "#173177"),
                    new WxMaTemplateData("keyword5", coupon.getSalePriceStr() + "元", "#173177"),
                    new WxMaTemplateData("keyword6", dateFormat.format(new Date()), "#173177"),
                    new WxMaTemplateData("keyword7", notes, "#173177")));
            smartAppMsg.setEmphasisKeyword("keyword1.DATA");
        } else {
            // mq发送小程序消息 - 核销失败消息
            /**
             * 核销失败消息
             * 商品名称 {{keyword1.DATA}}
             * 核销时间 {{keyword2.DATA}}
             * 失败原因 {{keyword3.DATA}}
             * 备注 {{keyword4.DATA}}
             */
            smartAppMsg = new SmartAppMsg();
            smartAppMsg.setMsgType(EnumMsgRecordType.SMART_APP.getCode());
            smartAppMsg.setAppId(user.getAppId());
            smartAppMsg.setTenantId(couponOrder.getTenantId());
            smartAppMsg.setTemplateType(EnumTemplateType.VERIFY_FAIL.getCode());
            smartAppMsg.setGotopage(gotopage);
            smartAppMsg.setTo(user.getOpenId());
            smartAppMsg.setReceiver(user.getOpenId());
            smartAppMsg.setFormId(formId);
            smartAppMsg.setTemplateDataList(Lists.newArrayList(
                    new WxMaTemplateData("keyword1", coupon.getTitle(), "#173177"),
                    new WxMaTemplateData("keyword2", dateFormat.format(new Date()), "#173177"),
                    new WxMaTemplateData("keyword3", "未知"),
                    new WxMaTemplateData("keyword4", couponDetail)));
            smartAppMsg.setEmphasisKeyword("keyword1.DATA");
        }

        try {
            mqBaseProducer.sendMessage(smartAppMsg, EnumMsgMqTopic.DEFAULT.getCode(),EnumMsgMqTag.DEFAULT.getCode(),EnumMsgMqKey.DEFAULT.getCode());
        } catch (Exception e) {
            logger.error("支付通知发送失败: " + e.getMessage());
            throw new MallinkException(ErrorCode.TEMPLATE_SEND_FAILED);
        }
    }


    @Override
    public List<CUserDateAmountVo> queryPriceTotalGroup(String tenantId, Date startTime, Date endTime) {
        return wxCouponOrderMapper.queryPriceTotalGroup(tenantId, startTime, endTime);
    }

    @Override
    public int queryPriceTotal(WxCouponOrder wxCouponOrder) {
        return wxCouponOrderMapper.queryPriceTotal(wxCouponOrder);
    }


    @Override
    public ResultData listCardVoAsPage(WxCardCVo record, Integer pageIndex, Integer pageSize) {
        return new ResultData(PageHelper.startPage(pageIndex, pageSize).doSelectPageInfo(() -> wxCouponOrderMapper.findCardListOfCUser(record)));
    }

    @Override
    public ResultData cardDetailCUserVo(Long ownerId, String couponOrderId) {
        WxCUser wxCuser = wxCUserMapper.selectByPrimaryKey(ownerId);
        if (wxCuser == null) {
            logger.error("用户不存在:" + ownerId);
            throw new MallinkException(ErrorCode.USER_IS_EMPTY);
        }

        WxCardCVo cardCVo = wxCouponOrderMapper.findCardDetailOfCUser(Long.valueOf(couponOrderId));
        Long couponId = cardCVo.getCouponId();
        WxCouponChannel wxCouponChannel = new WxCouponChannel();
        wxCouponChannel.setCouponId(couponId);
        List<WxCouponChannel> list = wxCouponChannelMapper.findList(wxCouponChannel);
        if (!list.isEmpty()) {
            cardCVo.setCouponChannelId(list.get(0).getId());
        }
        if (cardCVo == null)
            return new ResultData(ErrorCode.COUPON_ORDER_IS_NULL);
        return new ResultData(cardCVo);
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public ResultData cardAccept(WxCouponOrder record) {
        //卡券是否存在
        WxCardCVo cardCVo = wxCouponOrderMapper.findCardDetailOfCUser(record.getId());
        if (cardCVo == null) {
            logger.info("卡券不存在" + record.getId());
            return new ResultData(ErrorCode.COUPON_ORDER_IS_NULL);
        }
        //转赠人是否存在
        Long cUserId = record.getcUserId();
        WxCUser wxCuser = wxCUserMapper.selectByPrimaryKey(cUserId);
        if (wxCuser == null) {
            logger.info("转赠人不存在:" + cUserId);
            return new ResultData(ErrorCode.USER_IS_EMPTY.getCode(), "转赠人不存在");
        }

        //判断转赠人与目前卡所有者是否为同一个
        //数据表中当前卡所有者
        Long ownerId = cardCVo.getOwnerId();
        if (!ownerId.equals(cUserId)) {
            logger.info("转赠人与目前卡所有者不相同," + "转赠人:" + cUserId + ",当前所有者:" + ownerId);
            return new ResultData(ErrorCode.CARD_TRANSFERED);
        }

        if (!record.getUpdateDate().equals(cardCVo.getUpdateDate())) {
            return new ResultData(ErrorCode.CARD_TRANSFER_INVALID);
        }

        //判断卡是否已消费
        //面额与余额是否相同
        if (!cardCVo.getAmount().equals(cardCVo.getRemainingAmount())) {
            logger.info("面额与余额不相同");
            return new ResultData(ErrorCode.CARD_TRANSFER_INVALID);
        }
        //保存到转赠表中 id,coupon_order_id,tenant_id,title,amount,remain_amount,from_user,to_user,status,create_date,update_date
        try {
            saveCardTransfer(record, cardCVo);
        } catch (Exception e) {
            logger.info("保存卡转赠信息失败");
            throw new MallinkException(ErrorCode.CARD_TRANSFER_INVALID);
        }
        //更新卡拥有者
        try {
            record.setcUserId(null);
            record.setUpdateDate(new Date());
            wxCouponOrderMapper.updateByPrimaryKeySelective(record);
        } catch (Exception e) {
            logger.info("更新卡拥有者信息失败");
            throw new MallinkException(ErrorCode.CARD_TRANSFER_INVALID);
        }
        return new ResultData(Result.SUCCESS, "领取成功");
    }

    @Override
    public ResultData queryCardStatus(WxCouponOrder record) {
        //卡券是否存在
        WxCardCVo cardCVo = wxCouponOrderMapper.findCardDetailOfCUser(record.getId());
        if (cardCVo == null) {
            logger.info("卡券不存在" + record.getId());
            return new ResultData(ErrorCode.COUPON_ORDER_IS_NULL);
        }
        //转赠人是否存在
        Long cUserId = record.getcUserId();
        WxCUser wxCuser = wxCUserMapper.selectByPrimaryKey(cUserId);
        if (wxCuser == null) {
            logger.info("转赠人不存在:" + cUserId);
            return new ResultData(ErrorCode.USER_IS_EMPTY.getCode(), "转赠人不存在");
        }
        //判断转赠人与目前卡所有者是否为同一个
        //数据表中当前卡所有者
        Long ownerId = cardCVo.getOwnerId();
        if (!ownerId.equals(cUserId)) {
            logger.info("转赠人与目前卡所有者不相同," + "转赠人:" + cUserId + ",当前所有者:" + ownerId);
            return new ResultData(ErrorCode.CARD_TRANSFERED);
        }

        if (!record.getUpdateDate().equals(cardCVo.getUpdateDate())) {
            return new ResultData(ErrorCode.CARD_TRANSFER_INVALID);
        }

        //判断卡是否已消费
        //面额与余额是否相同
        if (!cardCVo.getAmount().equals(cardCVo.getRemainingAmount())) {
            logger.info("面额与余额不相同");
            return new ResultData(ErrorCode.CARD_TRANSFER_INVALID);
        }
        return new ResultData(Result.SUCCESS, "查询成功");
    }

    public void saveCardTransfer(WxCouponOrder couponOrder, WxCardCVo cardCVo) {
        logger.info("保存卡转赠信息");
        WxCardTransferInfo wxCardTransferInfo = new WxCardTransferInfo();
        final IdWorker idWorker = IdWorker.get();
        wxCardTransferInfo.setId(idWorker.nextId());
        wxCardTransferInfo.setTenantId(cardCVo.getTenantId());
        wxCardTransferInfo.setCouponOrderId(couponOrder.getId());
        wxCardTransferInfo.setFromUser(couponOrder.getcUserId());
        wxCardTransferInfo.setToUser(couponOrder.getOwnerId());
        wxCardTransferInfo.setAmount(cardCVo.getAmount());
        wxCardTransferInfo.setRemainAmount(cardCVo.getRemainingAmount());
        wxCardTransferInfo.setStatus(EnumCouponOrderStatus.CARD_TRANSFER.getCode());
        wxCardTransferInfo.setTitle(cardCVo.getTitle());
        wxCardTransferInfo.setExpiredTime(cardCVo.getExpiredTime());
        Date date = new Date();
        wxCardTransferInfo.setCreateDate(date);
        wxCardTransferInfo.setUpdateDate(date);
        wxCardTransferInfoMapper.insertSelective(wxCardTransferInfo);
    }

}
