package com.iformall.service.impl;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import com.iformall.common.ErrorCode;
import com.iformall.common.IdWorker;
import com.iformall.common.ResultData;
import com.iformall.domain.dto.WxCouponMerchantDto;
import com.iformall.domain.po.*;
import com.iformall.domain.po.base.BaseEntity;
import com.iformall.domain.vo.WxCouponCVo;
import com.iformall.domain.vo.WxCouponStatisVo;
import com.iformall.domain.vo.WxMerchantVo;
import com.iformall.enums.*;
import com.iformall.exception.MallinkException;
import com.iformall.mapper.*;
import com.iformall.service.*;
import org.apache.commons.collections.CollectionUtils;
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.Isolation;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.util.*;
import java.util.stream.Collectors;


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

    @Autowired
    WxCouponMapper wxCouponMapper;

    @Autowired
    WxCouponMerchantMapper wxCouponMerchantMapper;

    @Autowired
    WxMerchantMapper wxMerchantMapper;

    @Autowired
    WxCouponChannelService wxCouponChannelService;

    @Autowired
    WxCouponSendService wxCouponSendService;

    @Autowired
    WxOrderService wxOrderService;

    @Autowired
    WxScreenAdService wxScreenAdService;

    @Autowired
    WxCouponChannelMapper wxCouponChannelMapper;

    @Autowired
    WxCardInfoMapper wxCardInfoMapper;

    @Autowired
    WxCouponPasswordMapper couponPasswordMapper;

    @Autowired
    WxCouponPasswordService couponPasswordService;

    @Override
    public ResultData list(WxCoupon wxCoupon, Integer pageNum, Integer pageSize) {
        if (null == wxCoupon) wxCoupon = new WxCoupon();
        wxCoupon.setSortColumns(BaseEntity.SortField.CreateDate_DESC, BaseEntity.SortField.Id_DESC);
        PageInfo<WxCoupon> page = null;
        if (wxCoupon.getStatus() != null && wxCoupon.getStatus() == -1)
            wxCoupon.setStatus(null);

        //除了a端列表 其他默认需要过滤
        if(!EnumFilterPut.NO.equals(wxCoupon.getFilterCanPut())) {
            WxCoupon couponModel = wxCouponMapper.findCouponModel(wxCoupon);
            if (couponModel != null) {
                wxCoupon.setCouponModelId(couponModel.getCouponModelId());
                wxCoupon.setCardModelId(couponModel.getCardModelId());
                wxCoupon.setGroupModelId(couponModel.getGroupModelId());
                wxCoupon.setPressModelId(couponModel.getPressModelId());
            }
        }

        page = listAsPage(wxCoupon, pageNum, pageSize);

        List<WxCoupon> wxCouponList = page.getList();

        if (wxCouponList.isEmpty() || wxCoupon.getTargetAd() != null) {
            return new ResultData(page);
        }

        List<Long> ids = wxCouponList.stream().map(p -> p.getId()).collect(Collectors.toList());
        WxCouponChannel wxCouponChannel = new WxCouponChannel();
        wxCouponChannel.setTenantId(wxCoupon.getTenantId());
        wxCouponChannel.setCouponIds(ids);
        wxCouponChannel.setStatus(EnumCouponChannelStatus.STATUS_THROW_IN.getCode());
        //上架状态
        List<WxCouponChannel> list = wxCouponChannelMapper.findList(wxCouponChannel);
        if (!list.isEmpty()) {
            Map<Long, List<WxCouponChannel>> groupBy = list.stream().collect(Collectors.groupingBy(WxCouponChannel::getCouponId));
            for (WxCoupon temp : wxCouponList) {

                if (groupBy.get(temp.getId()) != null) {
                    List<Integer> channels = new ArrayList<>();
                    for (WxCouponChannel tempchannel : groupBy.get(temp.getId())) {
                        if (!channels.contains(tempchannel.getTargetAd())) {
                            channels.add(tempchannel.getTargetAd());
                        }
                    }
                    String sss = JSON.toJSONString(channels);
                    temp.setChannels(sss);
                } else {
                    temp.setChannels("");
                }

            }
        } else {
            for (WxCoupon temp : wxCouponList) {
                temp.setChannels("");
            }

        }
        return new ResultData(page);
    }

    @Override
    public PageInfo<WxCoupon> listAsPage(WxCoupon record, Integer pageIndex, Integer pageSize) {
        int total = wxCouponMapper.findCouponListCount(record);
        int pages;
        if(total % pageSize == 0){
            pages = total / pageSize;
        }else{
            pages = total / pageSize +1;
        }
        record.setLimitStart((pageIndex -1) * pageSize);
        record.setLimitEnd(pageSize);
        List<WxCoupon> list = wxCouponMapper.findCouponList(record);

        PageHelper.startPage(pageIndex, pageSize);
        PageInfo<WxCoupon> pageInfo = new PageInfo<>(list);
        pageInfo.setPages(pages);
        pageInfo.setTotal(total);
        PageHelper.clearPage();
        return pageInfo;
    }


    @Override
    public PageInfo<WxCouponStatisVo> findCountData(WxCoupon record,Integer pageNum, Integer pageSize) {
        return PageHelper.startPage(pageNum, pageSize).doSelectPageInfo(() -> wxCouponMapper.findCountData(record));
    }

    @Override
    public WxCoupon getById(Long id) {
        return wxCouponMapper.selectById(id);
    }

    @Override
    public WxCouponCVo getVoById(Long id) {
        WxCouponCVo wxCouponCVo = wxCouponMapper.findVoDetail(id);
        List<WxMerchantVo> merchantList = wxCouponCVo.getMerchantVoList();
        if (merchantList != null) {
            merchantList = merchantList.stream().filter(
                    m->m.getMerchantStatus().equals(EnumMerchantStatus.VALID.getCode()))
                    .collect(Collectors.toList());
        }
        wxCouponCVo.setMerchantVoList(merchantList);
        return wxCouponCVo;
    }

    @Override
    public WxCouponCVo getVoStatusById(Long id) {
        WxCouponCVo wxCouponCVo = wxCouponMapper.findVoStatusDetail(id);
        return wxCouponCVo;
    }


    private Long parseMerchantId(JSONObject merchantParam){
        return Long.valueOf(merchantParam.getString("id"));
    }
    private String parseParameter(JSONObject merchantParam){
        return merchantParam.getString("parameter");
    }
    private Integer parseBusiness(JSONObject merchantParam){
        String businessIdStr = merchantParam.getString("businessId");
        return Integer.valueOf(businessIdStr);

    }
    private Integer parseSubBusiness(JSONObject merchantParam){
        String subBusinessIdStr = merchantParam.getString("subBusinessId");
        if (subBusinessIdStr != null)
            return Integer.valueOf(subBusinessIdStr);
        return null;
    }

    private WxCouponMerchantDto parseMerchantParam(JSONObject merchantParam){
        WxCouponMerchantDto wxCouponMerchantDto = new WxCouponMerchantDto();
        try {
            wxCouponMerchantDto.setMerchantId(parseMerchantId(merchantParam));
            wxCouponMerchantDto.setParameter(parseParameter(merchantParam));
            wxCouponMerchantDto.setBusiness(parseBusiness(merchantParam));
            wxCouponMerchantDto.setSubBusiness(parseSubBusiness(merchantParam));
        }catch (Exception e) {
            throw new MallinkException(ErrorCode.SYS_PARAMETER_ERROR);
        }
        if (wxCouponMerchantDto.getBusiness()==null || wxCouponMerchantDto.getMerchantId()==null) {
            throw new MallinkException(ErrorCode.SYS_PARAMETER_ERROR);
        }
        return wxCouponMerchantDto;
    }


    @Override
    @Transactional(isolation=Isolation.SERIALIZABLE, propagation = Propagation.REQUIRED, rollbackFor = {Exception.class})
    public ResultData saveOrUpdate(WxCoupon record) {

        if (StringUtils.isNotEmpty(record.getSalePriceStr())) {
            record.setSalePrice(new BigDecimal(record.getSalePriceStr()).multiply(new BigDecimal(100)).intValue());
        }
        if (StringUtils.isNotEmpty(record.getUsePriceStr())) {
            record.setUsePrice(new BigDecimal(record.getUsePriceStr()).multiply(new BigDecimal(100)).intValue());
        }
        if (StringUtils.isNotEmpty(record.getPriceStr())) {
            record.setPrice(new BigDecimal(record.getPriceStr()).multiply(new BigDecimal(100)).intValue());
        }
        if (StringUtils.isNotEmpty(record.getSubsidyNumStr())) {
            record.setSubsidyNum(new BigDecimal(record.getSubsidyNumStr()).multiply(new BigDecimal(100)).intValue());
        }
        if (StringUtils.isBlank(record.getCoverPicture())) {
            List<String> strList = new ArrayList<String>();
            if (StringUtils.isNotBlank(record.getCoverImg())) {
                strList.add(record.getCoverImg());
            }
            if (strList.size() > 1) {
                record.setCoverPicture(JSONArray.toJSONString(strList));
            }
        }

        if (record.getValidType() != null) {
            if (record.getValidType().equals(EnumCouponValidType.DAYS_AFTER_RECEIVING.getCode())) {
                record.setValidStartDate(null);
                record.setValidEndDate(null);
            } else if (record.getValidType().equals(EnumCouponValidType.BETWEEN_TWO_TIME.getCode())) {
                record.setValidDays(null);
            } else {
                return new ResultData(ErrorCode.SYS_PARAMETER_ERROR.getCode(), "请填写有效时间类型");
            }
        }

        List<JSONObject> merchantParamList = JSONObject.parseArray(record.getMerchantParams(), JSONObject.class);
        //有价券判断商户是否配置了分账账号
        if (record.getSalePrice() != null && record.getSalePrice() > 0) {
            StringBuffer sb = new StringBuffer();
            boolean flag = false;
            for (int i = 0, size = merchantParamList.size(); i < size; i++) {
                JSONObject jsonObject = merchantParamList.get(i);
                Long id = jsonObject.getLong("id");
                WxMerchant wxMerchant = new WxMerchant();
                wxMerchant.setId(id);
                WxMerchant merchant = wxMerchantMapper.queryMerchantByMerchantIdOfSharingReceiver(wxMerchant);
                if (merchant.getId() == null) {
                    flag = true;
                    sb.append("[").append(merchant.getName()).append("]");
                }
            }
            if (flag) {
                String message = sb.toString();
                return new ResultData(ErrorCode.SYS_PARAMETER_ERROR.getCode(), "商户：" + message + "还未配置分账账户");
            }
        }

        final IdWorker idWorker = IdWorker.get();
        if (record.getId() == null) {

            // check 卡券补贴设置
            Integer subsidyType = record.getSubsidyType();
            Integer subsidyNum = record.getSubsidyNum();
            if(subsidyType != null && subsidyNum != null) {
                if (subsidyType.equals(EnumCouponSubsidyType.WECHAT_COUPON.getCode())) {
                    // 微信 立减
                    if (subsidyNum > record.getSalePrice()) {
                        return new ResultData(ErrorCode.SYS_PARAMETER_NOT_NULL.getCode(), "补贴额大于售价");
                    }
                } else if (subsidyType.equals(EnumCouponSubsidyType.OFFLINE_SUBSIDY.getCode())) {
                    // 线下补贴
                    int subsidy_num = record.getPrice() - record.getSalePrice();
                    if (subsidyNum > subsidy_num) {
                        return new ResultData(ErrorCode.SYS_PARAMETER_NOT_NULL.getCode(), "补贴额大于面额与售价的差值");
                    }
                } else if (subsidyType.equals(EnumCouponSubsidyType.WECHAT_MCHPAY.getCode())) {
                    // TODO 微信转账到银行卡

                }
            }

            record.setId(idWorker.nextId());

            if (merchantParamList != null && merchantParamList.size() > 0) {
                List<WxCouponMerchantDto> wxCouponMerchantDtoList = new ArrayList<>();
                merchantParamList.forEach(merchantParam -> {
                    WxCouponMerchant cm = new WxCouponMerchant();
                    WxCouponMerchantDto wxCouponMerchantDto = parseMerchantParam(merchantParam);
                    cm.setId(idWorker.nextId());
                    cm.setMerchantId(wxCouponMerchantDto.getMerchantId());
                    cm.setParameter(wxCouponMerchantDto.getParameter());
                    cm.setProductId(record.getId());
                    cm.setCreateDate(new Date());
                    cm.setUpdateDate(new Date());
                    cm.setStatus(EnumCouponMerchantStatus.COUPON_MERCHANT_STATUS_VALID.getCode());
                    wxCouponMerchantDtoList.add(wxCouponMerchantDto);
                    wxCouponMerchantMapper.insert(cm);
                });
                if (wxCouponMerchantDtoList.stream()
                        .mapToInt(WxCouponMerchantDto::getBusiness).distinct().count() > 1) {
                    record.setBusiness(EnumBusiness.BUSINESS_ID6.getCode());
                } else if (wxCouponMerchantDtoList.size() > 1){
                    record.setBusiness(wxCouponMerchantDtoList.get(0).getBusiness());
                } else {
                    record.setBusiness(wxCouponMerchantDtoList.get(0).getBusiness());
                    record.setSubBusiness(wxCouponMerchantDtoList.get(0).getSubBusiness());
                }

            } else{
                return new ResultData(ErrorCode.SYS_PARAMETER_NOT_NULL);
            }

            if (record.getPasswordSupport() != null && record.getPasswordSupport().equals(EnumCouponPasswordSupport.SUPPORTED.getCode())) {
                // 如果用户启用卡密，生成数据并保存
                couponPasswordService.mkPasswords(record.getTenantId(), record.getId(), record.getInventory());
            }

            record.setCreateDate(new Date());
            record.setUpdateDate(new Date());
            wxCouponMapper.insert(record);

        } else {
            if(record.getInventory() != null && record.getRemainInventory() != null) {
                // 库存修改检查
                WxCoupon oldCoupon = wxCouponMapper.selectById(record.getId());
                if (Objects.equals(oldCoupon.getRemainInventory(), record.getRemainInventory())) {
                    // 库存未变, 不更新库存
                    record.setRemainInventory(null);
                    record.setInventory(null);
                } else {
                    // TODO bug记录
                    logger.info("设置库存：record.getRemainInventory {}，oldCoupon.getRemainInventory {},oldCoupon.getInventory {}",
                            record.getRemainInventory(), oldCoupon.getRemainInventory(), oldCoupon.getInventory());
                    // 库存增加，要同时增加, 库存减少，要同时减少
                    record.setInventory(oldCoupon.getInventory() + record.getRemainInventory() - oldCoupon.getRemainInventory());
                }
            }
            if (merchantParamList != null && merchantParamList.size() > 0) {
                WxCouponMerchant cmParam = new WxCouponMerchant();
                cmParam.setProductId(record.getId());
                List<WxCouponMerchant> oldList = wxCouponMerchantMapper.findList(cmParam);
                List<WxCouponMerchantDto> wxCouponMerchantDtoList = new ArrayList<>();
                merchantParamList.stream().forEach(merchantParam -> {
                    WxCouponMerchant cm = new WxCouponMerchant();
                    WxCouponMerchantDto wxCouponMerchantDto = parseMerchantParam(merchantParam);
                    cm.setMerchantId(wxCouponMerchantDto.getMerchantId());
                    cm.setProductId(record.getId());
                    WxCouponMerchant rcm = wxCouponMerchantMapper.selectOne(new QueryWrapper<>(cm));
                    if (rcm != null) {
                        rcm.setParameter(wxCouponMerchantDto.getParameter());
                        rcm.setStatus(EnumCouponMerchantStatus.COUPON_MERCHANT_STATUS_VALID.getCode());
                        rcm.setUpdateDate(new Date());
                        wxCouponMerchantMapper.updateById(rcm);
                    }else {
                        cm.setId(idWorker.nextId());
                        cm.setStatus(EnumCouponMerchantStatus.COUPON_MERCHANT_STATUS_VALID.getCode());
                        cm.setParameter(wxCouponMerchantDto.getParameter());
                        cm.setCreateDate(new Date());
                        cm.setUpdateDate(new Date());
                        wxCouponMerchantMapper.insert(cm);
                    }
                    wxCouponMerchantDtoList.add(wxCouponMerchantDto);
                    oldList.removeIf(
                            old->old.getProductId().equals(record.getId()) &&
                             old.getMerchantId().equals(wxCouponMerchantDto.getMerchantId()));
                });

                oldList.stream().forEach(old->{
                    old.setStatus(EnumCouponMerchantStatus.COUPON_MERCHANT_STATUS_INVALID.getCode());
                    old.setUpdateDate(new Date());
                    wxCouponMerchantMapper.updateById(old);
                });

                if (wxCouponMerchantDtoList.stream()
                        .mapToInt(WxCouponMerchantDto::getBusiness).distinct().count() > 1) {
                    record.setBusiness(EnumBusiness.BUSINESS_ID6.getCode());
                } else if (wxCouponMerchantDtoList.size() > 1){
                    record.setBusiness(wxCouponMerchantDtoList.get(0).getBusiness());
                } else {
                    record.setBusiness(wxCouponMerchantDtoList.get(0).getBusiness());
                    record.setSubBusiness(wxCouponMerchantDtoList.get(0).getSubBusiness());
                }
            }

            if (record.getStatus() != null &&
                    (record.getStatus().equals(EnumCouponStatus.COUPON_STATUS_TAKE_OFFF.getCode()))) {

                //下架所有投放频道
                wxCouponChannelService
                        .updateStatusByCouponId(record.getId(), record.getTenantId(), EnumCouponChannelStatus.STATUS_TAKE_OFFF.getCode());
                //下架所有场景投放
                wxCouponSendService
                        .updateStatusByCouponId(record.getId(), record.getTenantId(), EnumCouponSendStatus.INVALID.getCode());
                //下架所有已砍价券
                wxOrderService.updateStatusByPressCouponId(record.getId(), record.getTenantId(), EnumOrderStatus.ORDER_STATUS_PRESS_CANCEL.getCode());
                //下架所有相关广告
                wxScreenAdService.updateStatusByCouponId(record.getId(), record.getTenantId(), EnumScreenAdStatus.INVALID.getCode());
                //下架拼团券
                wxOrderService.updateOrderGroupStatusByCouponId(record.getId(), record.getTenantId(), EnumOrderStatus.ORDER_STATUS_COOPERATING_CANCEL.getCode());
                // 卡下架后，转赠找不到卡相关信息，所以修改卡转赠状态为不可转赠
                wxCardInfoMapper.updateTransferStatusByCouponId(record.getId());
                // 卡券下架，未使用的卡密要下架
                couponPasswordMapper.disableByCouponId(record.getId());
            }
            record.setUpdateDate(new Date());
            wxCouponMapper.updateById(record);

        }
        return new ResultData(record.getId());
    }

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

    @Override
    public List<WxCouponStatisVo> findSaleMoneyByDate(WxCoupon wxCoupon) {
        return wxCouponMapper.findSaleMoneyByDate(wxCoupon);
    }

    @Override
    public List<WxCouponStatisVo> findPaymentByDate(WxCoupon wxCoupon) {
        return wxCouponMapper.findPaymentByDate(wxCoupon);
    }

    @Override
    public Long findSaleCardCount(WxCoupon wxCoupon) {
        Long count = wxCouponMapper.findSaleCardCount(wxCoupon);
        return (count==null)?0l:count;
    }

    @Override
    public Long findTranCardCount(WxCoupon wxCoupon) {
        Long count = wxCouponMapper.findTranCardCount(wxCoupon);
        return (count==null)?0l:count;
    }

    @Override
    public String findSubsidyMoney(WxCoupon wxCoupon) {
        String count = wxCouponMapper.findSubsidyMoney(wxCoupon);
        return (count==null)?"0":count;
    }

    @Override
    public PageInfo<WxCouponStatisVo> findCouponData(WxCoupon record, Integer pageNum, Integer pageSize) {
        return PageHelper.startPage(pageNum, pageSize).doSelectPageInfo(() -> wxCouponMapper.findCouponData(record));
    }

    @Override
    public List<WxCouponStatisVo> findCouponOrderCount(WxCoupon wxCoupon) {
        return wxCouponMapper.findCouponOrderCount(wxCoupon);
    }


    @Override
    public List<WxCouponStatisVo> findCouponPaymentCount(WxCoupon wxCoupon) {
        return wxCouponMapper.findCouponPaymentCount(wxCoupon);
    }

    @Override
    public List<WxCouponStatisVo> priceCouponSaleCount(WxCoupon wxCoupon) {
        return wxCouponMapper.priceCouponSaleCount(wxCoupon);
    }

    @Override
    public List<WxCouponStatisVo> priceCouponPaymentCount(WxCoupon wxCoupon) {
        return wxCouponMapper.priceCouponPaymentCount(wxCoupon);
    }

    @Override
    public String findSumPriceSaleMoney(WxCoupon wxCoupon) {
        String count = wxCouponMapper.findSumPriceSaleMoney(wxCoupon);
        return (count==null)?"0":count;
    }

    @Override
    public String findSumPricePayMent(WxCoupon wxCoupon) {
        String count = wxCouponMapper.findSumPricePayMent(wxCoupon);
        return (count==null)?"0":count;
    }

    @Override
    public String findSumSubsidyMoney(WxCoupon wxCoupon) {
        String count = wxCouponMapper.findSumSubsidyMoney(wxCoupon);
        return (count==null)?"0":count;
    }

    @Override
    public PageInfo<WxCouponStatisVo> findPressData(WxCoupon record, Integer pageNum, Integer pageSize) {
        return PageHelper.startPage(pageNum, pageSize).doSelectPageInfo(() -> wxCouponMapper.findPressData(record));
    }

    @Override
    public List<WxCouponStatisVo> pressSendHistory(WxCoupon wxCoupon) {
        return wxCouponMapper.pressSendHistory(wxCoupon);
    }

    @Override
    public List<WxCouponStatisVo> pressSuccHistory(WxCoupon wxCoupon) {
        return wxCouponMapper.pressSuccHistory(wxCoupon);
    }

    @Override
    public List<WxCouponStatisVo> pressPaymentHistory(WxCoupon wxCoupon) {
        return wxCouponMapper.pressPaymentHistory(wxCoupon);
    }

    @Override
    public String pressSuccRate(WxCoupon wxCoupon) {
        String count = wxCouponMapper.pressSuccRate(wxCoupon);
        if (StringUtils.isBlank(count) || "0.00".equals(count)) {
            return "0%";
        } else {
            return count + "%";
        }
    }

    @Override
    public Long sumJoin(WxCoupon wxCoupon) {
        Long count = wxCouponMapper.sumJoin(wxCoupon);
        return (count==null)?0l:count;
    }

    @Override
    public Long priceCouponCancelCount(WxCoupon wxCoupon) {
        Long count = wxCouponMapper.priceCouponCancelCount(wxCoupon);
        return (count==null)?0l:count;
    }

    @Override
    public List<WxCouponStatisVo> findSaleCardCountHistory(WxCoupon wxCoupon) {
        return wxCouponMapper.findSaleCardCountHistory(wxCoupon);
    }

    @Override
    @Transactional(isolation=Isolation.SERIALIZABLE, propagation = Propagation.REQUIRED, rollbackFor = {Exception.class})
    public ResultData updateCouponStockAndEndTime(WxCoupon wxCoupon) {
        // 1. get old coupon info
        // 2. check 库存是否合适
        // 3. check 新的有效期是否合适
        // 4. 更新库存及有效期
        boolean bChanged = false;
        WxCoupon oldCoupon = wxCouponMapper.selectById(wxCoupon.getId());
        if(oldCoupon == null) {
            logger.error(ErrorCode.COUPON_IS_EMPTY.getMessage());
            return new ResultData(ErrorCode.COUPON_IS_EMPTY);
        }
        if(wxCoupon.getInventory() < wxCoupon.getRemainInventory()) {
            // 总库存数要大于等于可用库存数
            logger.error("总库存数要大于等于可用库存数");
            return new ResultData(ErrorCode.COUPON_STOCK_ERR.getCode(), "总库存数要大于等于可用库存数");
        }
        if(wxCoupon.getInventory() < wxCoupon.getRemainInventory()) {
            // 总库存数要大于等于可用库存数
            logger.error("总库存数要大于等于可用库存数");
            return new ResultData(ErrorCode.COUPON_STOCK_ERR.getCode(), "总库存数要大于等于可用库存数");
        }
        if(wxCoupon.getInventory() <= oldCoupon.getInventory() - oldCoupon.getRemainInventory()) {
            // 库存可增, 可减, 但是要保证，总库存数要大于已售卖数
            logger.error("总库存数要大于等于可用库存数");
            return new ResultData(ErrorCode.COUPON_STOCK_ERR.getCode(), "总库存数要大于已售卖数");
        }

        if((!wxCoupon.getInventory().equals(oldCoupon.getInventory())) ||
                (!wxCoupon.getRemainInventory().equals(oldCoupon.getRemainInventory()))) {
            // 库存 是否改变
            bChanged = true;
        }
        if(wxCoupon.getInventory()-wxCoupon.getRemainInventory() != oldCoupon.getInventory() - oldCoupon.getRemainInventory()) {
            // 已售卖数不变
            logger.error("已售卖数不变");
            return new ResultData(ErrorCode.COUPON_STOCK_ERR.getCode(), "已售卖数不变");
        }
        if(wxCoupon.getValidType() != oldCoupon.getValidType()) {
            // 券有效期类型不能改变
            logger.error("券有效期类型不能改变");
            return new ResultData(ErrorCode.COUPON_VALID_DATE_ERR.getCode(), "券有效期类型不能改变");
        }
        if(oldCoupon.getValidType().equals(EnumCouponValidType.BETWEEN_TWO_TIME.getCode())) {
            if(wxCoupon.getValidEndDate().before(oldCoupon.getValidEndDate())) {
                // 券有效期只可增加
                logger.error("券有效期只可增加");
                return new ResultData(ErrorCode.COUPON_VALID_DATE_ERR.getCode(), "券有效期只可增加");
            }
            if(!wxCoupon.getValidEndDate().equals(oldCoupon.getValidEndDate())) {
                bChanged = true;
            }
        } else {
            if(wxCoupon.getValidDays()<oldCoupon.getValidDays()) {
                // 券有效期只可增加
                logger.error("券有效期只可增加");
                return new ResultData(ErrorCode.COUPON_VALID_DATE_ERR.getCode(), "券有效期只可增加");
            }
            if(!wxCoupon.getValidDays().equals(oldCoupon.getValidDays())) {
                bChanged = true;
            }
        }

        if(!bChanged) {
            logger.error("券库存有效期未修改");
            return new ResultData(ErrorCode.COUPON_STOCK_VALID_DATE_SETTING_ERR);
        }

        wxCoupon.setOrgInventory(oldCoupon.getInventory());
        wxCoupon.setOrgRemainInventory(oldCoupon.getRemainInventory());
        if((wxCoupon.getRemainInventory() - wxCoupon.getOrgRemainInventory()) != (wxCoupon.getInventory() - wxCoupon.getOrgInventory())) {
            // 库存要保证，同增同减
            logger.error("券库存要保证同增同减");
            return new ResultData(ErrorCode.COUPON_STOCK_NO_EQUAL_ERR);
        }

        int ret = wxCouponMapper.updateStockAndValidDate(wxCoupon);
        if(ret != 1) {
            throw new MallinkException(ErrorCode.DB_FAIL.getCode(), "数据库更新数量错误");
        }

        // 5. 更新coupon channel 有效期
        if(wxCoupon.getValidType().equals(EnumCouponValidType.BETWEEN_TWO_TIME.getCode())) {
            WxCouponChannel couponChannel = new WxCouponChannel();
            couponChannel.setTenantId(wxCoupon.getTenantId());
            couponChannel.setCouponId(wxCoupon.getId());
            couponChannel.setEndTime(wxCoupon.getValidEndDate());
            wxCouponChannelMapper.updateEndTimeByCouponId(couponChannel);
        }

        return new ResultData();
    }

    @Override
    public void update(WxCoupon record) {
        wxCouponMapper.updateById(record);
    }

    @Override
    public WxCoupon findById(WxCoupon wxCoupon) {
        WxCoupon query = new WxCoupon();
        query.setId(wxCoupon.getId());
        query.setType(wxCoupon.getType());
        List<WxCoupon> list = wxCouponMapper.findCouponList(query);
        if(CollectionUtils.isNotEmpty(list)){
            return list.get(0);
        }
        return null;
    }

    @Override
    @Transactional(isolation= Isolation.SERIALIZABLE, propagation = Propagation.REQUIRED, rollbackFor = {Exception.class})
    public void reduceRemainInventory(Long id, Integer number, Integer remainInventory) {
        int num = wxCouponMapper.reduceInventory(id, number, remainInventory);
        if (num == 0) {
            throw new MallinkException(ErrorCode.ORDER_SAVE_ERR);
        }
    }

    @Override
    @Transactional(isolation= Isolation.SERIALIZABLE, propagation = Propagation.REQUIRED, rollbackFor = {Exception.class})
    public void backRemainInventory(Long id, Integer number, Integer remainInventory) {
        int num = wxCouponMapper.backInventory(id, number, remainInventory);
        if (num == 0) {
            throw new MallinkException(ErrorCode.REMAIN_BACK_FAIL);
        }
    }
}
