package co.yixiang.yshop.module.product.service.campaigninfo;

import cn.hutool.core.util.ObjectUtil;
import co.yixiang.yshop.framework.common.constant.ShopConstants;
import co.yixiang.yshop.framework.common.pojo.PageResult;
import co.yixiang.yshop.framework.common.util.date.DateUtils;
import co.yixiang.yshop.framework.redis.util.RedissonUtil;
import co.yixiang.yshop.module.product.controller.admin.campaigndetail.vo.CampaignDetailCreateReqVO;
import co.yixiang.yshop.module.product.controller.admin.campaigndetail.vo.CampaignDetailRespVO;
import co.yixiang.yshop.module.product.controller.admin.campaigndetail.vo.CampaignSkuDetailRespVO;
import co.yixiang.yshop.module.product.controller.admin.campaigninfo.param.CampaignJudgmentParam;
import co.yixiang.yshop.module.product.controller.admin.campaigninfo.vo.*;
import co.yixiang.yshop.module.product.convert.campaigndetail.CampaignDetailConvert;
import co.yixiang.yshop.module.product.convert.campaigninfo.CampaignInfoConvert;
import co.yixiang.yshop.module.product.dal.dataobject.campaigndetail.CampaignDetailDO;
import co.yixiang.yshop.module.product.dal.dataobject.campaigninfo.CampaignInfoDO;
import co.yixiang.yshop.module.product.dal.dataobject.storeproduct.StoreProductDO;
import co.yixiang.yshop.module.product.dal.dataobject.storeproductattrvalue.StoreProductAttrValueDO;
import co.yixiang.yshop.module.product.dal.mysql.campaigndetail.CampaignDetailMapper;
import co.yixiang.yshop.module.product.dal.mysql.campaigninfo.CampaignInfoMapper;
import co.yixiang.yshop.module.product.enums.common.PageTypeEnum;
import co.yixiang.yshop.module.product.enums.spu.ProductSpuStatusEnum;
import co.yixiang.yshop.module.product.mq.producer.PayRefundProducer;
import co.yixiang.yshop.module.product.service.storeproduct.StoreProductService;
import co.yixiang.yshop.module.product.service.storeproductattrvalue.StoreProductAttrValueService;
import co.yixiang.yshop.module.product.service.teamworkinfo.TeamworkInfoService;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.redisson.api.RedissonClient;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.validation.annotation.Validated;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.util.*;
import java.util.concurrent.TimeUnit;
import java.util.function.Function;
import java.util.stream.Collectors;

import static co.yixiang.yshop.framework.common.exception.util.ServiceExceptionUtil.exception;
import static co.yixiang.yshop.module.product.enums.ErrorCodeConstants.*;
import static co.yixiang.yshop.module.product.enums.campaign.CampaignCommonEnum.DEACTIVATE;
import static co.yixiang.yshop.module.product.enums.campaign.CampaignCommonEnum.ENABLE;
import static co.yixiang.yshop.module.product.enums.campaign.CampaignStateEnum.*;
import static co.yixiang.yshop.module.product.enums.campaign.CampaignTypeEnum.TEAMWORK;

/**
 * 活动信息 Service 实现类
 *
 * @author moxiangrong
 */
@Service
@Validated
@Slf4j
public class CampaignInfoServiceImpl implements CampaignInfoService {

    @Resource
    private CampaignInfoMapper campaignInfoMapper;
    @Resource
    private StoreProductAttrValueService productAttrValueService;
    @Resource
    private CampaignDetailMapper campaignDetailMapper;
    @Resource
    private StoreProductService productService;

    @Resource
    private RedissonClient redissonClient;

    @Resource
    private PayRefundProducer payRefundProducer;

    @Resource
    private TeamworkInfoService teamworkInfoService;

    @Resource
    private RedissonUtil redissonUtil;

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Long createCampaignInfo(CampaignInfoCreateReqVO createReqVO) {
        List<CampaignDetailCreateReqVO> details = createReqVO.getDetails();
        // 判断是否选择商品
        if (CollectionUtils.isEmpty(details)) {
            throw exception(CAMPAIGN_NOT_PRODUCT_ERROR);
        }
        // 判断活动是否重复
        List<Long> productIds =
                details.stream().map(CampaignDetailCreateReqVO::getProductId).distinct().collect(Collectors.toList());
        CampaignJudgmentParam param = new CampaignJudgmentParam();
        param.setProductIds(productIds);
        param.setStartTime(createReqVO.getStartTime());
        param.setEndTime(createReqVO.getEndTime());
        if (CollectionUtils.isNotEmpty(campaignInfoMapper.checkRepeat(param))) {
            throw exception(CAMPAIGN_REPEAT_ERROR);
        }
        // 查询商品数据
        List<StoreProductDO> products = productService.getStoreProductList(productIds);
        Map<Long, StoreProductDO> productMap =
                products.stream().collect(Collectors.toMap(StoreProductDO::getId, Function.identity()));
        List<Long> skuIds = details.stream().map(CampaignDetailCreateReqVO::getSkuId).collect(Collectors.toList());
        List<StoreProductAttrValueDO> productAttrValueDOS =
                productAttrValueService.getStoreProductAttrValueList(skuIds);
        Map<Long, StoreProductAttrValueDO> productAttrValueDOMap =
                productAttrValueDOS.stream().collect(Collectors
                        .toMap(StoreProductAttrValueDO::getId, Function.identity()));
        // 准备扣除库存数据
        List<StoreProductAttrValueDO> updateProductAttrValues = new ArrayList<>();
        Map<Long, StoreProductDO> updateProductMap = new HashMap<>();
        for (CampaignDetailCreateReqVO detail : details) {
            StoreProductAttrValueDO productAttrValueDO = productAttrValueDOMap.get(detail.getSkuId());
            if (ObjectUtil.isNull(productAttrValueDO)) throw exception(STORE_PRODUCT_ATTR_VALUE_NOT_EXISTS);
            // 检测价格
            if (productAttrValueDO.getPrice().compareTo(detail.getPrice()) < 0)
                throw exception(CAMPAIGN_PASS_ORIGINAL_PRICE_ERROR, productAttrValueDO.getSku());
            // 检测库存
            if (productAttrValueDO.getStock() < detail.getStock())
                throw exception(CAMPAIGN_OUT_OF_STOCK_ERROR, productAttrValueDO.getSku());
            productAttrValueDO.setStock(productAttrValueDO.getStock() - detail.getStock());
            updateProductAttrValues.add(productAttrValueDO);
            Long productId = productAttrValueDO.getProductId();
            StoreProductDO updateProduct = updateProductMap.get(productId);
            if (ObjectUtil.isNotNull(updateProduct)) {
                updateProduct.setStock(updateProduct.getStock() - detail.getStock());
            } else {
                StoreProductDO product = productMap.get(productId);
                if (ObjectUtil.isNull(product)) throw exception(STORE_PRODUCT_NOT_EXISTS);
                product.setStock(product.getStock() - detail.getStock());
                updateProductMap.put(productId, product);
            }
        }
        // 转换
        CampaignInfoDO campaignInfo = CampaignInfoConvert.INSTANCE.convert(createReqVO);
        LocalDateTime time = null;
        // 设置活动状态
        if (ObjectUtil.isNotNull(campaignInfo.getStartTime()) && ObjectUtil.isNotNull(campaignInfo.getEndTime())) {
            if (DateUtils.isBelong(campaignInfo.getStartTime(), campaignInfo.getEndTime())) {
                // 如果当前时间在这个范围内,状态为进行中
                campaignInfo.setState(IN_PROGRESS.getValue());
                time = campaignInfo.getEndTime();
            } else if (DateUtils.isBefore(campaignInfo.getStartTime())) {
                // 如果活动开始时间大于当前时间,状态为未开始
                campaignInfo.setState(NOT_STARTED.getValue());
                time = campaignInfo.getStartTime();
            } else {
                // 如果不在,状态为已结束
                campaignInfo.setState(ENDED.getValue());
            }
        }
        // 预热开始时间
        LocalDateTime preheatStartTime = null;
        if (ENABLE.getValue().equals(campaignInfo.getIfEnable()) &&
                NOT_STARTED.getValue().equals(campaignInfo.getState())) {
            preheatStartTime = DateUtils.getMoreMinuteAfter(campaignInfo.getStartTime(),
                    -1 * campaignInfo.getEnableTime());
            // 当前时间在预热期间，直接开始预热
            if (DateUtils.isBelong(preheatStartTime, campaignInfo.getStartTime())) {
                campaignInfo.setState(PREHEAT.getValue());
            } else {
                time = preheatStartTime;
            }
        }
        List<CampaignDetailDO> campaignDetailDOS = CampaignDetailConvert.INSTANCE.convertDetails(details);
        // 插入营销活动数据
        campaignInfoMapper.insert(campaignInfo);
        campaignDetailDOS.forEach(res -> {
            res.setCampaignId(campaignInfo.getId());
            res.setTotal(res.getStock());
        });
        campaignDetailMapper.insertBatch(campaignDetailDOS);
        if (!ENDED.getValue().equals(campaignInfo.getState())) {
            // 扣除库存
            productAttrValueService.updateBatchById(updateProductAttrValues);
            productService.updateBatchById(updateProductMap.values());
            //加入延时队列
            this.addQueue(campaignInfo.getId(), DateUtils.getMoreMillisecondAfter(time));
        }
        // 返回
        return campaignInfo.getId();
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void updateCampaignInfo(CampaignInfoUpdateReqVO updateReqVO) {
        List<CampaignDetailCreateReqVO> details = updateReqVO.getDetails();
        // 校验存在
        this.validateCampaignInfoExists(updateReqVO.getId());
        // 判断是否选择商品
        if (CollectionUtils.isEmpty(details)) {
            throw exception(CAMPAIGN_NOT_PRODUCT_ERROR);
        }
        // 回退库存
        this.stackBack(updateReqVO.getId());
        // 删除活动明细
        campaignDetailMapper.deleteCampaignDetails(updateReqVO.getId());
        // 判断活动是否重复
        List<Long> productIds =
                details.stream().map(CampaignDetailCreateReqVO::getProductId).distinct().collect(Collectors.toList());
        CampaignJudgmentParam param = new CampaignJudgmentParam();
        param.setProductIds(productIds);
        param.setCampaignId(updateReqVO.getId());
        param.setStartTime(updateReqVO.getStartTime());
        param.setEndTime(updateReqVO.getEndTime());
        if (CollectionUtils.isNotEmpty(campaignInfoMapper.checkRepeat(param))) {
            throw exception(CAMPAIGN_REPEAT_ERROR);
        }
        // 查询商品数据
        List<StoreProductDO> products = productService.getStoreProductList(productIds);
        Map<Long, StoreProductDO> productMap =
                products.stream().collect(Collectors.toMap(StoreProductDO::getId, Function.identity()));
        List<Long> skuIds = details.stream().map(CampaignDetailCreateReqVO::getSkuId).collect(Collectors.toList());
        List<StoreProductAttrValueDO> productAttrValueDOS =
                productAttrValueService.getStoreProductAttrValueList(skuIds);
        Map<Long, StoreProductAttrValueDO> productAttrValueDOMap =
                productAttrValueDOS.stream().collect(Collectors
                        .toMap(StoreProductAttrValueDO::getId, Function.identity()));
        // 准备扣除库存数据
        List<StoreProductAttrValueDO> updateProductAttrValues = new ArrayList<>();
        Map<Long, StoreProductDO> updateProductMap = new HashMap<>();
        for (CampaignDetailCreateReqVO detail : details) {
            StoreProductAttrValueDO productAttrValueDO = productAttrValueDOMap.get(detail.getSkuId());
            if (ObjectUtil.isNull(productAttrValueDO)) throw exception(STORE_PRODUCT_ATTR_VALUE_NOT_EXISTS);
            // 检测价格
            if (productAttrValueDO.getPrice().compareTo(detail.getPrice()) < 0)
                throw exception(CAMPAIGN_PASS_ORIGINAL_PRICE_ERROR, productAttrValueDO.getSku());
            // 检测库存
            if (productAttrValueDO.getStock() < detail.getStock())
                throw exception(CAMPAIGN_OUT_OF_STOCK_ERROR, productAttrValueDO.getSku());
            productAttrValueDO.setStock(productAttrValueDO.getStock() - detail.getStock());
            updateProductAttrValues.add(productAttrValueDO);
            Long productId = productAttrValueDO.getProductId();
            StoreProductDO updateProduct = updateProductMap.get(productId);
            if (ObjectUtil.isNotNull(updateProduct)) {
                updateProduct.setStock(updateProduct.getStock() - detail.getStock());
            } else {
                StoreProductDO product = productMap.get(productId);
                if (ObjectUtil.isNull(product)) throw exception(STORE_PRODUCT_NOT_EXISTS);
                product.setStock(product.getStock() - detail.getStock());
                updateProductMap.put(productId, product);
            }
        }
        // 转换
        CampaignInfoDO campaignInfo = CampaignInfoConvert.INSTANCE.convert(updateReqVO);
        LocalDateTime time = null;
        // 设置活动状态
        if (ObjectUtil.isNotNull(campaignInfo.getStartTime()) && ObjectUtil.isNotNull(campaignInfo.getEndTime())) {
            if (DateUtils.isBelong(campaignInfo.getStartTime(), campaignInfo.getEndTime())) {
                // 如果当前时间在这个范围内,状态为进行中
                campaignInfo.setState(IN_PROGRESS.getValue());
                time = campaignInfo.getEndTime();
            } else if (DateUtils.isBefore(campaignInfo.getStartTime())) {
                // 如果活动开始时间大于当前时间,状态为未开始
                campaignInfo.setState(NOT_STARTED.getValue());
                time = campaignInfo.getStartTime();
            } else {
                // 如果不在,状态为已结束
                campaignInfo.setState(ENDED.getValue());
            }
        }
        // 预热开始时间
        LocalDateTime preheatStartTime = null;
        if (ENABLE.getValue().equals(campaignInfo.getIfEnable()) &&
                NOT_STARTED.getValue().equals(campaignInfo.getState())) {
            preheatStartTime = DateUtils.getMoreMinuteAfter(campaignInfo.getStartTime(),
                    -1 * campaignInfo.getEnableTime());
            // 当前时间在预热期间，直接开始预热
            if (DateUtils.isBelong(preheatStartTime, campaignInfo.getStartTime())) {
                campaignInfo.setState(PREHEAT.getValue());
            } else {
                time = preheatStartTime;
            }
        }
        campaignInfoMapper.updateById(campaignInfo);
        List<CampaignDetailDO> campaignDetailDOS = CampaignDetailConvert.INSTANCE.convertDetails(details);
        campaignDetailDOS.forEach(res -> {
            res.setCampaignId(campaignInfo.getId());
            res.setTotal(res.getStock());
        });
        campaignDetailMapper.insertBatch(campaignDetailDOS);
        // 扣除库存
        productAttrValueService.updateBatchById(updateProductAttrValues);
        productService.updateBatchById(updateProductMap.values());
        if (!ENDED.getValue().equals(campaignInfo.getState())) {
            this.removeQueue(campaignInfo.getId());
            //加入延时队列
            this.addQueue(campaignInfo.getId(), DateUtils.getMoreMillisecondAfter(time));
        }
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void deleteCampaignInfo(Long id) {
        // 校验存在
        CampaignInfoDO campaignInfo = this.validateCampaignInfoExists(id);
        // 进行中无法删除活动
        if (IN_PROGRESS.getValue().equals(campaignInfo.getState())) {
            throw exception(CAMPAIGN_IN_PROGRESS_ERROR);
        }
        // 删除
        campaignInfoMapper.deleteById(id);
        // 删除活动明细
        campaignDetailMapper.deleteCampaignDetails(id);
        // 删除等待队列数据
        if (NOT_STARTED.getValue().equals(campaignInfo.getState())) {
            this.removeQueue(id);
        }
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void closeCampaignInfo(Long id) {
        // 校验存在
        CampaignInfoDO campaignInfoDO = this.validateCampaignInfoExists(id);
        // 自动取消未成团订单
        if (TEAMWORK.getValue().equals(campaignInfoDO.getType())) {
            // 查询未成团订单
            List<Long> ids = teamworkInfoService.getNotTeamwork(id);
            if (CollectionUtils.isNotEmpty(ids)) {
                // 取消订单并退款
                payRefundProducer.sendPayRefundMessage(ids);
                // 修改拼团失败状态
                teamworkInfoService.updateTeamworkFail(id);
            }
        }
        // 变更活动状态
        CampaignInfoDO update = new CampaignInfoDO();
        update.setId(id);
        update.setState(ENDED.getValue());
        campaignInfoMapper.updateById(update);
        // 回退库存
        this.stackBack(id);
        // 删除自动关闭队列数据
        this.removeQueue(id);
    }

    @Override
    public void startCampaignInfo(Long id) {
        // 校验存在
        CampaignInfoDO campaignInfo = this.validateCampaignInfoExists(id);
        // 变更活动状态
        CampaignInfoDO update = new CampaignInfoDO();
        update.setId(id);
        update.setState(IN_PROGRESS.getValue());
        campaignInfoMapper.updateById(update);
        // 删除自动开始队列数据
        this.removeQueue(id);
        long time = DateUtils.getMoreMillisecondAfter(campaignInfo.getEndTime());
        // 加入延时队列，到时间自动结束
        this.addQueue(id, time);
    }

    private CampaignInfoDO validateCampaignInfoExists(Long id) {
        CampaignInfoDO campaignInfoDO = campaignInfoMapper.selectById(id);
        if (ObjectUtil.isNull(campaignInfoDO)) throw exception(CAMPAIGN_NOT_EXISTS);
        return campaignInfoDO;
    }

    @Override
    public CampaignInfoRespVO getCampaignInfo(Long id) {
        // 校验存在
        CampaignInfoDO campaignInfo = this.validateCampaignInfoExists(id);
        CampaignInfoRespVO vo = CampaignInfoConvert.INSTANCE.convert(campaignInfo);
        List<CampaignDetailRespVO> details = new ArrayList<>();
        // 获取商品规格数据
        List<CampaignSkuDetailRespVO> skus = campaignDetailMapper.getCampaignDetails(id);
        if (CollectionUtils.isEmpty(skus)) return vo;
        Map<Long, List<CampaignSkuDetailRespVO>> skuMap =
                skus.stream().collect(Collectors.groupingBy(CampaignSkuDetailRespVO::getProductId));
        for (List<CampaignSkuDetailRespVO> list : skuMap.values()) {
            CampaignDetailRespVO detailRespVO = CampaignInfoConvert.INSTANCE.convert(list.get(0));
            detailRespVO.setOriginalStock(list.stream().mapToInt(CampaignSkuDetailRespVO::getOriginalStock).sum());
            detailRespVO.setSkus(list);
            details.add(detailRespVO);
        }
        vo.setNow(LocalDateTime.now());
        vo.setDetails(details);
        return vo;
    }

    @Override
    public PageResult<CampaignInfoPageRespVO> getCampaignInfoPage(CampaignInfoPageReqVO pageReqVO) {
        PageResult<CampaignInfoPageRespVO> result =
                CampaignInfoConvert.INSTANCE.convertPage(campaignInfoMapper.selectPage(pageReqVO));
        List<CampaignInfoPageRespVO> list = result.getList();
        if (CollectionUtils.isEmpty(list)) {
            return result;
        }
        // 获取拼团订单数据
        List<Long> campaignIds = list.stream().map(CampaignInfoPageRespVO::getId).collect(Collectors.toList());
        List<CampaignOrderVo> campaignOrderVos = campaignInfoMapper.getCampaignInfoList(campaignIds);
        if (CollectionUtils.isEmpty(list)) {
            return result;
        }
        Map<Long, List<CampaignOrderVo>> orderMap =
                campaignOrderVos.stream().collect(Collectors.groupingBy(CampaignOrderVo::getCampaignId));
        for (CampaignInfoPageRespVO campaignInfoPageRespVO : list) {
            List<CampaignOrderVo> campaignOrders = orderMap.get(campaignInfoPageRespVO.getId());
            if (CollectionUtils.isEmpty(campaignOrders)) continue;
            // 计算订单数
            campaignInfoPageRespVO.setOrderQuantity(campaignOrders.stream()
                    .map(CampaignOrderVo::getOid).distinct().collect(Collectors.toList()).size());
            // 计算销售额
            campaignInfoPageRespVO.setSalesAmount(campaignOrders.stream()
                    .map(CampaignOrderVo::getPrice).reduce(BigDecimal::add).orElse(BigDecimal.ZERO));
            // 计算销售量
            campaignInfoPageRespVO.setSalesQuantity(campaignOrders.size());
        }
        return result;
    }

    @Override
    public List<CampaignInfoDO> getCampaignInfoList(CampaignInfoExportReqVO exportReqVO) {
        return campaignInfoMapper.selectList(exportReqVO);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void campaignStateHandle(Long id) {
        // 校验存在
        CampaignInfoDO campaignInfo = this.validateCampaignInfoExists(id);
        Integer state = null;
        // 判断下个状态
        if (IN_PROGRESS.getValue().equals(campaignInfo.getState())) {
            state = ENDED.getValue();
            // 回退库存
            this.stackBack(id);
            // 自动取消未成团订单
            if (TEAMWORK.getValue().equals(campaignInfo.getType())) {
                // 查询未成团订单
                List<Long> ids = teamworkInfoService.getNotTeamwork(id);
                if (CollectionUtils.isNotEmpty(ids)) {
                    // 取消订单并退款
                    payRefundProducer.sendPayRefundMessage(ids);
                    // 修改拼团失败状态
                    teamworkInfoService.updateTeamworkFail(id);
                }
            }
        } else {
            if (NOT_STARTED.getValue().equals(campaignInfo.getState())
                    && ENABLE.getValue().equals(campaignInfo.getIfEnable())) {
                state = PREHEAT.getValue();
            } else if (NOT_STARTED.getValue().equals(campaignInfo.getState())
                    && DEACTIVATE.getValue().equals(campaignInfo.getIfEnable())) {
                state = IN_PROGRESS.getValue();
            } else if (PREHEAT.getValue().equals(campaignInfo.getState())) {
                state = IN_PROGRESS.getValue();
            }
            long time = DateUtils.getMoreMillisecondAfter(IN_PROGRESS.getValue().equals(state) ?
                    campaignInfo.getEndTime() : campaignInfo.getStartTime());
            //加入延时队列
            this.addQueue(id, time);
        }
        // 修改活动状态
        CampaignInfoDO update = new CampaignInfoDO();
        update.setId(id);
        update.setState(state);
        campaignInfoMapper.updateById(update);
    }

    @Override
    public CampaignDataRespVO getCampaignData(Long id) {
        // 校验存在
        CampaignInfoDO campaignInfo = this.validateCampaignInfoExists(id);
        CampaignDataRespVO campaignDataRespVO = new CampaignDataRespVO();
        campaignDataRespVO.setId(id);
        campaignDataRespVO.setName(campaignInfo.getName());
        List<CampaignOrderVo> campaignOrderVos = campaignInfoMapper.getCampaignInfoList(Arrays.asList(id));
        if (CollectionUtils.isEmpty(campaignOrderVos)) return campaignDataRespVO;
        // 成交金额
        campaignDataRespVO.setDealAmount(campaignOrderVos.stream()
                .map(CampaignOrderVo::getPrice).reduce(BigDecimal::add).orElse(BigDecimal.ZERO));
        // 成交单量
        campaignDataRespVO.setDealQuantity(campaignOrderVos.stream()
                .map(CampaignOrderVo::getOid).distinct().collect(Collectors.toList()).size());
        // 成交人数
        campaignDataRespVO.setPeopleNumber(campaignOrderVos.stream()
                .map(CampaignOrderVo::getUid).distinct().collect(Collectors.toList()).size());
        // 成交商品数
        campaignDataRespVO.setProductQuantity(campaignOrderVos.size());
        // 客单价
        campaignDataRespVO.setAveragePrice(campaignDataRespVO.getDealAmount()
                .divide(new BigDecimal(campaignDataRespVO.getDealQuantity())));
        return campaignDataRespVO;
    }

    @Override
    public PageResult<CampaignDataDetailRespVO> getCampaignDataDetail(CampaignDataDetailPageReqVO reqVO) {
        Page<CampaignDataDetailRespVO> page = new Page<>(reqVO.getPageNo(), reqVO.getPageSize());
        List<CampaignDataDetailRespVO> list = campaignDetailMapper.getCampaignDataDetail(page, reqVO);
        if (CollectionUtils.isEmpty(list)) return new PageResult<>();
        // 获取订单数据
        List<CampaignOrderVo> campaignOrderVos =
                campaignInfoMapper.getCampaignInfoList(Arrays.asList(reqVO.getId()));
        if (CollectionUtils.isEmpty(campaignOrderVos)) return new PageResult<>(list, page.getTotal());
        Map<String, List<CampaignOrderVo>> skuOrderMap =
                campaignOrderVos.stream().collect(Collectors.groupingBy(CampaignOrderVo::getUnique));
        for (CampaignDataDetailRespVO respVO : list) {
            List<CampaignOrderVo> skuOrders = skuOrderMap.get(respVO.getUnique());
            if (CollectionUtils.isEmpty(skuOrders)) continue;
            // 成交金额
            respVO.setDealAmount(skuOrders.stream()
                    .map(CampaignOrderVo::getPrice).reduce(BigDecimal::add).orElse(BigDecimal.ZERO));
            // 成交单量
            respVO.setDealQuantity(skuOrders.stream()
                    .map(CampaignOrderVo::getOid).distinct().collect(Collectors.toList()).size());
            // 成交人数
            respVO.setPeopleNumber(skuOrders.stream()
                    .map(CampaignOrderVo::getUid).distinct().collect(Collectors.toList()).size());
            // 成交商品数
            respVO.setProductQuantity(skuOrders.size());
            // 客单价
            respVO.setAveragePrice(respVO.getDealAmount().divide(new BigDecimal(respVO.getDealQuantity())));
        }
        return new PageResult<>(list, page.getTotal());
    }

    @Override
    public PageResult<CanvasCampaignPageRespVO> getCanvasCampaignPage(CanvasCampaignPageReqVO pageReqVO) {
        if (PageTypeEnum.NOT_PAGE.getValue().equals(pageReqVO.getIsPage())) pageReqVO.setPageSize(Integer.MAX_VALUE);
        return CampaignInfoConvert.INSTANCE.convertCanvasPage(campaignInfoMapper.getCanvasCampaignPage(pageReqVO));
    }

    /**
     * 回退库存
     *
     * @param campaignId 营销活动id
     */
    private void stackBack(Long campaignId) {
        // 查询活动的商品明细数据
        List<CampaignDetailDO> details =
                campaignDetailMapper.selectList(new LambdaQueryWrapper<CampaignDetailDO>()
                        .eq(CampaignDetailDO::getCampaignId, campaignId));
        if (CollectionUtils.isEmpty(details)) return;
        List<Long> productIds =
                details.stream().map(CampaignDetailDO::getProductId).distinct().collect(Collectors.toList());
        // 查询商品数据
        List<StoreProductDO> products = productService.getStoreProductList(productIds);
        if (CollectionUtils.isEmpty(products)) return;
        // 过滤未上架商品
        products = products.stream().filter(res -> ProductSpuStatusEnum.ENABLE.getStatus().equals(res.getIsShow()))
                .collect(Collectors.toList());
        if (CollectionUtils.isEmpty(products)) return;
        Map<Long, StoreProductDO> productMap =
                products.stream().collect(Collectors.toMap(StoreProductDO::getId, Function.identity()));
        List<Long> skuIds = details.stream().map(CampaignDetailDO::getSkuId).collect(Collectors.toList());
        List<StoreProductAttrValueDO> skus = productAttrValueService.getStoreProductAttrValueList(skuIds);
        Map<Long, StoreProductAttrValueDO> skuMap =
                skus.stream().collect(Collectors.toMap(StoreProductAttrValueDO::getId, Function.identity()));
        // 返还库存
        List<StoreProductAttrValueDO> updateSkus = new ArrayList<>();
        Map<Long, StoreProductDO> updateProductMap = new HashMap<>();
        for (CampaignDetailDO detail : details) {
            StoreProductAttrValueDO sku = skuMap.get(detail.getSkuId());
            if (ObjectUtil.isNull(sku)) continue;
            sku.setStock(sku.getStock() + detail.getStock());
            updateSkus.add(sku);
            StoreProductDO updateProduct = updateProductMap.get(detail.getProductId());
            if (ObjectUtil.isNull(updateProduct)) {
                StoreProductDO product = productMap.get(detail.getProductId());
                product.setStock(product.getStock() + detail.getStock());
                updateProductMap.put(detail.getProductId(), product);
            } else {
                updateProduct.setStock(updateProduct.getStock() + detail.getStock());
            }
        }
        // 回退库存
        productAttrValueService.updateBatchById(updateSkus);
        productService.updateBatchById(updateProductMap.values());
    }

    /**
     * 加入延时队列
     *
     * @param id
     * @param time
     */
    private void addQueue(Long id, long time) {
        log.info("添加延时队列 ，营销活动id：{}, 延时时间：{}", id, time);
        redissonUtil.delayedOfferThrow(ShopConstants.CAMPAIGN_CHANGE, id, time, TimeUnit.MILLISECONDS, CAMPAIGN_ADD_QUEUE_ERROR);
    }

    /**
     * 从延时队列中移除
     *
     * @param id
     */
    private void removeQueue(Long id) {
        redissonUtil.delayedRemoveThrow(ShopConstants.CAMPAIGN_CHANGE, id, CAMPAIGN_REMOVE_QUEUE_ERROR);
        log.info("移除延时队列成功 ，营销活动id：{}", id);
    }
}
