
package com.tmerclub.cloud.group.service.impl;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.date.DateUtil;
import com.tmerclub.cloud.api.feign.SearchOrderFeignClient;
import com.tmerclub.cloud.api.group.bo.GroupOrderNotifyBO;
import com.tmerclub.cloud.api.group.vo.GroupOrderVO;
import com.tmerclub.cloud.api.order.feign.OrderFeignClient;
import com.tmerclub.cloud.api.order.vo.GroupInfoVO;
import com.tmerclub.cloud.api.user.feign.UserFeignClient;
import com.tmerclub.cloud.api.user.vo.UserApiVO;
import com.tmerclub.cloud.common.cache.constant.GroupCacheNames;
import com.tmerclub.cloud.common.cache.util.CacheManagerUtil;
import com.tmerclub.cloud.common.constant.Constant;
import com.tmerclub.cloud.common.constant.SendTypeEnum;
import com.tmerclub.cloud.common.exception.LuckException;
import com.tmerclub.cloud.common.leaf.manager.SegmentManager;
import com.tmerclub.cloud.common.order.bo.OrderIdWithRefundIdBO;
import com.tmerclub.cloud.common.order.bo.PayNotifyBO;
import com.tmerclub.cloud.common.order.vo.SendNotifyBO;
import com.tmerclub.cloud.common.response.ResponseEnum;
import com.tmerclub.cloud.common.response.ServerResponseEntity;
import com.tmerclub.cloud.common.rocketmq.config.RocketMqConstant;
import com.tmerclub.cloud.common.security.AuthUserContext;
import com.tmerclub.cloud.common.util.BeanUtil;
import com.tmerclub.cloud.group.bo.GroupOpenNotifyBO;
import com.tmerclub.cloud.group.bo.GroupOrderBO;
import com.tmerclub.cloud.group.bo.GroupSaveNotifyBO;
import com.tmerclub.cloud.group.bo.mongo.MongoGroupOrderBO;
import com.tmerclub.cloud.group.bo.mongo.MongoGroupTeamBO;
import com.tmerclub.cloud.group.constant.DistributedIdKey;
import com.tmerclub.cloud.group.constant.GroupOrderStatusEnum;
import com.tmerclub.cloud.group.constant.TeamStatusEnum;
import com.tmerclub.cloud.group.mapper.GroupActivityMapper;
import com.tmerclub.cloud.group.mapper.GroupOrderMapper;
import com.tmerclub.cloud.group.service.GroupOrderService;
import com.tmerclub.cloud.group.service.GroupTeamService;
import com.tmerclub.cloud.group.vo.GroupActivityVO;
import com.tmerclub.cloud.group.vo.mongo.MongoAppGroupUserVO;
import com.tmerclub.cloud.group.vo.mongo.MongoGroupOrderCountVO;
import com.tmerclub.cloud.group.vo.mongo.MongoGroupOrderVO;
import com.tmerclub.cloud.group.vo.mongo.MongoSuccessGroupOrderVO;
import org.apache.dubbo.config.annotation.DubboReference;
import org.apache.rocketmq.client.producer.LocalTransactionState;
import org.apache.rocketmq.client.producer.SendStatus;
import org.apache.rocketmq.client.producer.TransactionSendResult;
import org.apache.rocketmq.spring.core.RocketMQTemplate;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.data.mongodb.core.aggregation.*;
import org.springframework.data.mongodb.core.query.Criteria;
import org.springframework.data.mongodb.core.query.Query;
import org.springframework.data.mongodb.core.query.Update;
import org.springframework.messaging.support.GenericMessage;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.*;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

/**
 * 拼团订单表
 *
 * @author YXF
 * @date 2021-03-20 10:39:32
 */
@Service
public class GroupOrderServiceImpl implements GroupOrderService {
    private static final Logger logger = LoggerFactory.getLogger(GroupOrderServiceImpl.class);

    @Autowired
    private GroupOrderMapper groupOrderMapper;
    @DubboReference
    private UserFeignClient userFeignClient;
    @Autowired
    private GroupTeamService groupTeamService;
    @Autowired
    private GroupActivityMapper groupActivityMapper;
    @Autowired
    private CacheManagerUtil cacheManagerUtil;
    @Autowired
    private RocketMQTemplate groupOrderSuccessTemplate;
    @Autowired
    private RocketMQTemplate groupOrderUnSuccessTemplate;
    @Autowired
    private RocketMQTemplate sendGroupNotifyToUserTemplate;
    @Autowired
    private RocketMQTemplate groupOrderUnSuccessRefundTemplate;
    @Autowired
    private RocketMQTemplate sendGroupOrderSaveTemplate;
    @Autowired
    private RocketMQTemplate sendGroupOrderOpenAndJoinGroupTemplate;
    @Autowired
    private SegmentManager segmentManager;
    @DubboReference
    private OrderFeignClient orderFeignClient;
    @DubboReference
    private SearchOrderFeignClient searchOrderFeignClient;
    @Autowired
    private MongoTemplate mongoTemplate;

    @Override
    public void saveToMongodb(MongoGroupOrderBO mongoGroupOrderBO) {
        if (Objects.isNull(mongoGroupOrderBO) || Objects.isNull(mongoGroupOrderBO.getGroupOrderId())) {
            throw new LuckException("拼团团队信息不全");
        }
        mongoGroupOrderBO.setCreateTime(new Date());
        mongoGroupOrderBO.setUpdateTime(new Date());
        logger.info("保存拼团订单到mongodb{}", mongoGroupOrderBO);
        mongoTemplate.save(mongoGroupOrderBO);
    }

    @Override
    public void saveBatchToMongodb(List<MongoGroupOrderBO> list) {
        logger.info("批量保存拼团订单到mongodb{}", list);
        for (MongoGroupOrderBO mongoGroupOrderBO : list) {
            if (Objects.isNull(mongoGroupOrderBO) || Objects.isNull(mongoGroupOrderBO.getGroupOrderId())) {
                throw new LuckException("拼团团队信息不全");
            }
            mongoGroupOrderBO.setCreateTime(new Date());
            mongoGroupOrderBO.setUpdateTime(new Date());
        }
        mongoTemplate.insertAll(list);
    }

    @Override
    public GroupOrderVO getByOrderId(Long orderId) {
        MongoGroupOrderBO mongoGroupOrderBO = mongoTemplate.findOne(new Query(Criteria.where("orderId").is(orderId)), MongoGroupOrderBO.class);
        return BeanUtil.map(mongoGroupOrderBO, GroupOrderVO.class);
    }

    @Override
    public List<MongoAppGroupUserVO> listApiGroupUserDto(Long groupTeamId) {
        Criteria criteria = Criteria.where("groupTeamId").is(groupTeamId).and("status").is(GroupOrderStatusEnum.SUCCESS.value());
        ProjectionOperation projectionOperation = Aggregation.project()
                .and("userId").as("userId")
                .and("identityType").as("identityType")
                .and("createTime").as("createTime");
        // 按顺序组合每一个聚合步骤
        TypedAggregation<MongoAppGroupUserVO> typedAggregation =
                Aggregation.newAggregation(
                        MongoAppGroupUserVO.class,
                        Aggregation.match(criteria),
                        projectionOperation
                );
        logger.info("listApiGroupUserDto()的mongodb查询语句： {}", typedAggregation);
        // 执行聚合操作
        AggregationResults<MongoAppGroupUserVO> aggregationResults =
                mongoTemplate.aggregate(typedAggregation, MongoAppGroupUserVO.class);
        // 取出最终结果
        List<MongoAppGroupUserVO> appGroupUserList = aggregationResults.getMappedResults();
        if (CollUtil.isEmpty(appGroupUserList)) {
            return null;
        }
        Set<Long> userIds = appGroupUserList.stream().map(MongoAppGroupUserVO::getUserId).collect(Collectors.toSet());
        ServerResponseEntity<List<UserApiVO>> userResponse = userFeignClient.getUserByUserIds(new ArrayList<>(userIds));
        List<UserApiVO> data = userResponse.getData();
        Map<Long, UserApiVO> userMap = data.stream().collect(Collectors.toMap(UserApiVO::getUserId, u -> u));
        for (MongoAppGroupUserVO groupUserVO : appGroupUserList) {
            // 机器人参团
            if (Objects.isNull(groupUserVO.getUserId()) || Objects.equals(groupUserVO.getUserId(), 0L)) {
                groupUserVO.setNickName(Constant.GROUP_SYSTEM_USER);
            } else {
                UserApiVO userApiVO = userMap.get(groupUserVO.getUserId());
                groupUserVO.setNickName(userApiVO.getNickName());
                groupUserVO.setPic(userApiVO.getPic());
            }
        }
        return appGroupUserList;
    }

    @Override
    public GroupOrderVO getUserGroupOrderByGroupTeamId(Long groupTeamId) {
        Long userId = AuthUserContext.get().getUserId();
        Criteria criteria = Criteria.where("groupTeamId").is(groupTeamId)
                .and("userId").is(userId)
                .and("status").is(GroupOrderStatusEnum.SUCCESS.value());
        MongoGroupOrderBO mongoGroupOrderBO = mongoTemplate.findOne(new Query(criteria), MongoGroupOrderBO.class);
        return BeanUtil.map(mongoGroupOrderBO, GroupOrderVO.class);
    }

    @Override
    public Integer getUserHadSpuCountByGroupActivityId(Long userId, Long groupActivityId) {
        Criteria criteria = Criteria.where("groupActivityId").is(groupActivityId)
                .and("userId").is(userId)
                .and("status").ne(GroupOrderStatusEnum.FAIL.value());
        ProjectionOperation projectionOperation = Aggregation.project("orderId");
        // 按顺序组合每一个聚合步骤
        TypedAggregation<MongoGroupOrderVO> typedAggregation =
                Aggregation.newAggregation(
                        MongoGroupOrderVO.class,
                        Aggregation.match(criteria),
                        projectionOperation
                );
        logger.info("getUserHadSpuCountByGroupActivityId()的mongodb查询语句： {}", typedAggregation);
        // 执行聚合操作
        AggregationResults<MongoGroupOrderVO> aggregationResults =
                mongoTemplate.aggregate(typedAggregation, MongoGroupOrderVO.class);
        // 取出最终结果
        List<MongoGroupOrderVO> list = aggregationResults.getMappedResults();
        if (CollUtil.isEmpty(list)) {
            return 0;
        }
        List<Long> orderIds = list.stream().map(MongoGroupOrderVO::getOrderId).collect(Collectors.toList());
        if (CollUtil.isEmpty(orderIds)) {
            return 0;
        }
        ServerResponseEntity<Integer> orderResponse = orderFeignClient.countNormalOrderByOrderIds(orderIds);
        if (!orderResponse.isSuccess()) {
            throw new LuckException(orderResponse.getMsg());
        }
        return orderResponse.getData();
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void submit(GroupOrderBO groupOrderBO) {
        // 插入拼团订单
        MongoGroupOrderBO groupOrder = new MongoGroupOrderBO();
        MongoGroupTeamBO groupTeam;
        if (Objects.equals(groupOrderBO.getGroupTeamId(), 0L)) {
            // 如果为团长，则需新建拼团团队
            groupTeam = new MongoGroupTeamBO();
            Long groupTeamId = segmentManager.getSegmentIdWithDateTime(DistributedIdKey.tmerclub_GROUP_TEAM, groupOrderBO.getGroupActivityId());
            groupTeam.setGroupTeamId(groupTeamId);
            groupTeam.setShareUserId(groupOrderBO.getShareUserId());
            groupTeam.setGroupSpuId(groupOrderBO.getSpuId());
            groupTeam.setGroupActivityId(groupOrderBO.getGroupActivityId());
            groupTeam.setJoinNum(1);
            groupTeam.setShopId(groupOrderBO.getShopId());
            groupTeam.setStatus(TeamStatusEnum.WAITING_GROUP.value());
            groupTeam.setTotalPrice(groupOrder.getPayPrice());

            groupOrder.setGroupTeamId(groupTeam.getGroupTeamId());
        } else {
            groupTeam = groupTeamService.getByGroupTeamId(groupOrderBO.getGroupTeamId());
            groupOrder.setGroupTeamId(groupOrderBO.getGroupTeamId());
        }

        Long groupOrderId = segmentManager.getSegmentIdWithDateTime(DistributedIdKey.tmerclub_GROUP_ORDER, groupOrderBO.getGroupActivityId());
        groupOrder.setGroupOrderId(groupOrderId);
        groupOrder.setGroupActivityId(groupOrderBO.getGroupActivityId());
        groupOrder.setUserId(groupOrderBO.getUserId());
        groupOrder.setOrderId(groupOrderBO.getOrderId());
        groupOrder.setActivityProdPrice(groupOrderBO.getActivityProdPrice());
        groupOrder.setPayPrice(groupOrderBO.getPayPrice());
        groupOrder.setShopId(groupOrderBO.getShopId());
        groupOrder.setIdentityType(Objects.equals(groupOrderBO.getGroupTeamId(), 0L) ? 1 : 0);
        groupOrder.setStatus(GroupOrderStatusEnum.WAITING_PAY.value());
        groupOrder.setCount(groupOrderBO.getCount());

        GroupSaveNotifyBO groupSaveNotifyBO = new GroupSaveNotifyBO();
        groupSaveNotifyBO.setMongoGroupTeamBO(groupTeam);
        groupSaveNotifyBO.setMongoGroupOrderBO(groupOrder);
        SendStatus sendStatus = sendGroupOrderSaveTemplate.syncSend(RocketMqConstant.GROUP_ORDER_SAVE_TOPIC, new GenericMessage<>(groupSaveNotifyBO)).getSendStatus();
        if (!Objects.equals(sendStatus, SendStatus.SEND_OK)) {
            // 消息发不出去就抛异常，发的出去无所谓
            throw new LuckException(ResponseEnum.EXCEPTION);
        }
    }

    @Override
    public void cancelGroupOrder(GroupOrderVO groupOrder, List<Long> orderIds) {
        logger.info("拼团订单取消{}", groupOrder);
        Update update = new Update();
        update.set("status", GroupOrderStatusEnum.FAIL.value());
        Query query = new Query(Criteria.where("groupActivityId").is(groupOrder.getGroupActivityId())
                .and("status").is(GroupOrderStatusEnum.WAITING_PAY.value())
                .and("orderId").in(orderIds));
        mongoTemplate.updateFirst(query, update, MongoGroupOrderBO.class);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void payNotifyGroupOrder(PayNotifyBO message) {
        Long orderId = message.getOrderIds().get(0);
        // 获取用户拼团订单信息
        GroupOrderVO groupOrder = getByOrderId(orderId);
        if (Objects.equals(groupOrder.getStatus(), GroupOrderStatusEnum.SUCCESS.value())) {
            return;
        }
        // 如果为团长则直接开团，否则判断是否拼团已满
        if (Objects.equals(groupOrder.getIdentityType(), 1)) {
            logger.info("拼团开团" + orderId);
            // 开团
            openGroup(orderId, groupOrder);
        } else {
            // 获取拼团团队订单
            MongoGroupTeamBO groupTeam = groupTeamService.getByGroupTeamId(groupOrder.getGroupTeamId());
            // 如果团已满，或回调的时候团已经失败了（之前的团退款了）则开新团
            // 否则加入该团
            if (Objects.equals(groupTeam.getStatus(), TeamStatusEnum.SUCCESS.value())
                    || Objects.equals(groupTeam.getStatus(), TeamStatusEnum.FAIL.value())) {
                logger.info("拼团开新团" + orderId);
                // 开新团
                openNewGroup(orderId, groupOrder, groupTeam);
            } else if (Objects.equals(groupTeam.getStatus(), TeamStatusEnum.IN_GROUP.value())) {
                // 参团
                logger.info("拼团参团" + orderId);
                joinGroup(orderId, groupOrder, groupTeam);
            }
        }
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void unSuccess(Long groupTeamId) {
        Date nowDate = new Date();
        // 机器人列表
        List<GroupOrderVO> robot = new ArrayList<>(Constant.INITIAL_CAPACITY);
        MongoGroupTeamBO groupTeam = groupTeamService.getByGroupTeamId(groupTeamId);
        if (!Objects.equals(groupTeam.getStatus(), TeamStatusEnum.IN_GROUP.value())) {
            return;
        }
        GroupActivityVO groupActivity = groupActivityMapper.getByGroupActivityId(groupTeam.getGroupActivityId());

        List<MongoSuccessGroupOrderVO> successGroupOrders = listSuccessOrderIdByTeamId(groupTeam.getGroupTeamId(), false);

        if (CollectionUtil.isEmpty(successGroupOrders)) {
            return;
        }
        List<Long> orderIds = successGroupOrders.stream().map(MongoSuccessGroupOrderVO::getOrderId).collect(Collectors.toList());

        // 如果未成团，有机器人可以成团，不需要进行退款的操作
        if (groupActivity.getHasRobot() == 1) {
            logger.info("机器人成团" + groupTeamId);
            addRobot(nowDate, robot, groupTeam, groupActivity, orderIds);
            return;
        }
        logger.info("订单拼团失败，退款" + groupTeamId);

        List<OrderIdWithRefundIdBO> orderIdWithRefundIds = new ArrayList<>(Constant.INITIAL_CAPACITY);
        for (MongoSuccessGroupOrderVO successGroupOrder : successGroupOrders) {
            // 由于用户id不一定相同，不能批量获取id
            Long segmentId = segmentManager.getSegmentIdWithDateTime(DistributedIdKey.tmerclub_REFUND, successGroupOrder.getUserId());
            OrderIdWithRefundIdBO orderIdWithRefundIdBO = new OrderIdWithRefundIdBO();
            orderIdWithRefundIdBO.setOrderId(successGroupOrder.getOrderId());
            orderIdWithRefundIdBO.setRefundId(segmentId);
            orderIdWithRefundIdBO.setShopId(successGroupOrder.getShopId());
            orderIdWithRefundIds.add(orderIdWithRefundIdBO);
        }

        // 发送退款服务进行退款的通知 - 事务消息，更改拼团队伍的状态和更新订单退款相关信息
        TransactionSendResult transactionSendResult = groupOrderUnSuccessRefundTemplate.sendMessageInTransaction(RocketMqConstant.GROUP_ORDER_UN_SUCCESS_REFUND_TOPIC, new GenericMessage<>(orderIdWithRefundIds), groupTeamId);

        if (!Objects.equals(transactionSendResult.getLocalTransactionState(), LocalTransactionState.COMMIT_MESSAGE)) {
            throw new LuckException(ResponseEnum.EXCEPTION);
        }

        // 消息推送-拼团失败
        for (Long orderId : orderIds) {
            SendNotifyBO sendNotifyBO = new SendNotifyBO();
            sendNotifyBO.setSendType(SendTypeEnum.GROUP_FAIL.getValue());
            sendNotifyBO.setBizId(orderId);
            SendStatus sendBizStatus = sendGroupNotifyToUserTemplate.syncSend(RocketMqConstant.SEND_GROUP_NOTIFY_TO_USER_TOPIC, new GenericMessage<>(sendNotifyBO)).getSendStatus();
        }

    }

    private List<MongoSuccessGroupOrderVO> listSuccessOrderIdByTeamId(Long groupTeamId, boolean isNeedUnPay) {
        Criteria criteria = Criteria.where("groupTeamId").is(groupTeamId);
        if (isNeedUnPay) {
            // 参团需要获取还未更新成功的，因为这是到后面用mq去保证成功
            criteria.and("status").in(0, 1);
        } else {
            criteria.and("status").is(GroupOrderStatusEnum.SUCCESS.value());
        }
        ProjectionOperation projectionOperation = Aggregation.project("orderId", "userId", "shopId");
        // 按顺序组合每一个聚合步骤
        TypedAggregation<MongoSuccessGroupOrderVO> typedAggregation =
                Aggregation.newAggregation(
                        MongoSuccessGroupOrderVO.class,
                        Aggregation.match(criteria),
                        projectionOperation
                );
        logger.info("listSuccessOrderIdByTeamId()的mongodb查询语句： {}", typedAggregation);
        // 执行聚合操作
        AggregationResults<MongoSuccessGroupOrderVO> aggregationResults =
                mongoTemplate.aggregate(typedAggregation, MongoSuccessGroupOrderVO.class);
        // 取出最终结果
        return aggregationResults.getMappedResults();
    }

    /**
     * 如果未成团，有机器人可以成团，则添加机器人
     *
     * @param nowDate       当前时间
     * @param robot         机器人列表
     * @param groupTeam     拼团队伍
     * @param groupActivity 团购活动
     * @param orderIds      订单id列表
     */
    private void addRobot(Date nowDate, List<GroupOrderVO> robot, MongoGroupTeamBO groupTeam, GroupActivityVO groupActivity, List<Long> orderIds) {

        // 模拟参团操作（添加机器人）
        for (int i = 0; i < groupActivity.getGroupNumber() - groupTeam.getJoinNum(); i++) {
            GroupOrderVO groupOrder = new GroupOrderVO();
            groupOrder.setShopId(groupTeam.getShopId());
            groupOrder.setGroupTeamId(groupTeam.getGroupTeamId());
            groupOrder.setGroupActivityId(groupActivity.getGroupActivityId());
            groupOrder.setUserId(0L);
            groupOrder.setIdentityType(0);
            groupOrder.setStatus(GroupOrderStatusEnum.SUCCESS.value());
            groupOrder.setCreateTime(nowDate);
            robot.add(groupOrder);
        }
        if (CollectionUtil.isNotEmpty(robot)) {
            for (GroupOrderVO groupOrder : robot) {
                Long id = segmentManager.getSegmentIdWithDateTime(DistributedIdKey.tmerclub_GROUP_ORDER, groupTeam.getGroupActivityId());
                groupOrder.setGroupOrderId(id);
            }
        }

        // 更新已成团人数
        updateGroupOrderInfo(groupActivity.getGroupActivityId());

        GroupOrderNotifyBO groupOrderNotifyBO = new GroupOrderNotifyBO();
        groupOrderNotifyBO.setOrderIds(orderIds);
        groupOrderNotifyBO.setGroupOrders(robot);
        groupOrderNotifyBO.setIsJoin(0);
        // 消息-更改团队状态-发送通知更新拼团订单，发送通知给订单，将订单状态变为待发货
        TransactionSendResult transactionSendResult = groupOrderSuccessTemplate.sendMessageInTransaction(RocketMqConstant.GROUP_ORDER_SUCCESS_TOPIC, new GenericMessage<>(groupOrderNotifyBO), groupTeam);
        if (!Objects.equals(transactionSendResult.getLocalTransactionState(), LocalTransactionState.COMMIT_MESSAGE)) {
            throw new LuckException(ResponseEnum.EXCEPTION);
        }

        for (Long orderId : orderIds) {
            // 消息推送-拼团成功
            SendStatus sendBizStatus = sendGroupNotifyToUserTemplate.syncSend(RocketMqConstant.SEND_GROUP_NOTIFY_TO_USER_TOPIC, new GenericMessage<>(orderId)).getSendStatus();
        }
    }

    @Override
    public Integer getOrderBySpuIdAndUserId(Long groupActivityId, Long spuId, Long userId) {
        Criteria criteria = Criteria.where("userId").is(userId).and("groupActivityId").is(groupActivityId).and("status").ne(GroupOrderStatusEnum.FAIL.value());
        ProjectionOperation projectionOperation = Aggregation.project("groupTeamId", "groupActivityId");
        LookupOperation lookupOperation = Aggregation.lookup("group_team", "groupTeamId", "_id", "groupTeam");
        Criteria teamCriteria = Criteria.where("groupTeam.status").in(0, 1).and("groupTeam.groupSpuId").is(spuId);
        GroupOperation groupOperation = Aggregation.group("groupActivityId").count().as("count");
        // 按顺序组合每一个聚合步骤
        TypedAggregation<MongoGroupOrderCountVO> typedAggregation = Aggregation.newAggregation(
                MongoGroupOrderCountVO.class,
                Aggregation.match(criteria),
                projectionOperation,
                lookupOperation,
                Aggregation.match(teamCriteria),
                groupOperation
        );
        logger.info("getOrderBySpuIdAndUserId()的mongodb查询语句： {}", typedAggregation);

        // 执行聚合操作
        AggregationResults<MongoGroupOrderCountVO> aggregationResults =
                mongoTemplate.aggregate(typedAggregation, MongoGroupOrderCountVO.class);
        // 取出最终结果
        List<MongoGroupOrderCountVO> list = aggregationResults.getMappedResults();
        if (CollUtil.isEmpty(list)) {
            return 0;
        }
        return Objects.isNull(list.get(0).getCount()) ? 0 : list.get(0).getCount();
    }

    @Override
    public void updateGroupOrderInfo(Long groupActivityId) {
        // mongo数据更新存在一定延迟，导致统计的成团数据不准确，稍微加点延迟等待mongo更新
        try {
            TimeUnit.SECONDS.sleep(1L);
        } catch (InterruptedException ie) {
            Thread.currentThread().interrupt();
        }
        ServerResponseEntity<GroupInfoVO> serverResponse = orderFeignClient.getGroupInfoById(groupActivityId);
        if (!serverResponse.isSuccess()) {
            throw new LuckException(serverResponse.getMsg());
        }
        GroupInfoVO groupInfo = serverResponse.getData();
        if (Objects.nonNull(groupInfo)) {
            groupActivityMapper.updateGroupOrderInfo(groupActivityId, groupInfo.getOrderCount(), groupInfo.getNumberCount());
        }
    }

    @Override
    public void updateToPaySuccess(Long orderId, Integer identityType, Long groupTeamId) {
        logger.info("拼团订单更新为支付成功" + orderId);
        Update update = new Update();
        update.set("status", GroupOrderStatusEnum.SUCCESS.value());
        if (Objects.nonNull(groupTeamId)) {
            update.set("groupTeamId", groupTeamId);
        }
        if (Objects.nonNull(identityType)) {
            update.set("identityType", identityType);
        }
        Query query = new Query(Criteria.where("orderId").is(orderId)
                .and("status").ne(GroupOrderStatusEnum.SUCCESS.value()));
        mongoTemplate.updateFirst(query, update, MongoGroupOrderBO.class);
    }


    private void openGroup(Long orderId, GroupOrderVO groupOrder) {
        updateGroupOrderInfo(groupOrder.getGroupActivityId());
        Date now = new Date();
        MongoGroupTeamBO newGroupTeam = groupTeamService.getByGroupTeamId(groupOrder.getGroupTeamId());
        newGroupTeam.setTotalPrice(groupOrder.getPayPrice());
        newGroupTeam.setGroupTeamId(groupOrder.getGroupTeamId());
        newGroupTeam.setStatus(TeamStatusEnum.IN_GROUP.value());
        newGroupTeam.setStartTime(now);
        newGroupTeam.setEndTime(DateUtil.offsetMillisecond(now, RocketMqConstant.CANCEL_TIME_INTERVAL));

        updateTeamAndOrder(orderId, null, null, newGroupTeam);

        sendMsg(orderId, groupOrder);
    }

    private void sendMsg(Long orderId, GroupOrderVO groupOrder) {
        // 发送延迟消息
        // 发送消息，如果三十分钟后没有成团，则取消订单进行退款
        SendStatus sendStatus = groupOrderUnSuccessTemplate.syncSend(RocketMqConstant.GROUP_ORDER_UN_SUCCESS_TOPIC, new GenericMessage<>(groupOrder.getGroupTeamId()), RocketMqConstant.TIMEOUT, RocketMqConstant.CANCEL_ORDER_DELAY_LEVEL).getSendStatus();
        if (!Objects.equals(sendStatus, SendStatus.SEND_OK)) {
            // 消息发不出去就抛异常，发的出去无所谓
            throw new LuckException(ResponseEnum.EXCEPTION);
        }

        // 消息推送-开团成功
        SendNotifyBO sendNotifyBO = new SendNotifyBO();
        sendNotifyBO.setSendType(SendTypeEnum.GROUP_START.getValue());
        sendNotifyBO.setBizId(orderId);
        SendStatus sendBizStatus = sendGroupNotifyToUserTemplate.syncSend(RocketMqConstant.SEND_GROUP_NOTIFY_TO_USER_TOPIC, new GenericMessage<>(sendNotifyBO)).getSendStatus();
    }

    private void openNewGroup(Long orderId, GroupOrderVO groupOrder, MongoGroupTeamBO groupTeam) {

        // 获取订单id列表
        Long groupTeamId = segmentManager.getSegmentIdWithDateTime(DistributedIdKey.tmerclub_GROUP_TEAM, groupTeam.getGroupActivityId());
        Date now = new Date();
        // 满员开团
        MongoGroupTeamBO newGroupTeam = new MongoGroupTeamBO();
        newGroupTeam.setGroupTeamId(groupTeamId);
        newGroupTeam.setJoinNum(1);
        newGroupTeam.setCreateTime(now);
        newGroupTeam.setUpdateTime(now);
        newGroupTeam.setStartTime(now);
        newGroupTeam.setShopId(groupTeam.getShopId());
        newGroupTeam.setTotalPrice(groupOrder.getPayPrice());
        newGroupTeam.setShareUserId(groupOrder.getUserId());
        newGroupTeam.setStatus(TeamStatusEnum.IN_GROUP.value());
        newGroupTeam.setGroupSpuId(groupTeam.getGroupSpuId());
        newGroupTeam.setGroupActivityId(groupTeam.getGroupActivityId());
        newGroupTeam.setEndTime(DateUtil.offsetMillisecond(now, RocketMqConstant.CANCEL_TIME_INTERVAL));

        updateGroupOrderInfo(groupOrder.getGroupActivityId());

        updateTeamAndOrder(orderId, 1, newGroupTeam.getGroupTeamId(), newGroupTeam);

        // 发送延迟消息
        // 发送消息，如果三十分钟后没有成团，则取消订单进行退款
        sendMsg(orderId, groupOrder);
    }

    private void updateTeamAndOrder(Long orderId, Integer identityType, Long groupTeamId, MongoGroupTeamBO newGroupTeam) {
        GroupOpenNotifyBO groupOpenNotifyBO = new GroupOpenNotifyBO();
        groupOpenNotifyBO.setOrderId(orderId);
        groupOpenNotifyBO.setIdentityType(identityType);
        groupOpenNotifyBO.setGroupTeamId(groupTeamId);
        // 事务消息-更改团队状态-发送通知更新拼团订单
        TransactionSendResult transactionSendResult = sendGroupOrderOpenAndJoinGroupTemplate.sendMessageInTransaction(RocketMqConstant.GROUP_ORDER_OPEN_AND_JOIN_GROUP_TOPIC,
                new GenericMessage<>(groupOpenNotifyBO), newGroupTeam);
        if (!Objects.equals(transactionSendResult.getLocalTransactionState(), LocalTransactionState.COMMIT_MESSAGE)) {
            throw new LuckException(ResponseEnum.EXCEPTION);
        }
    }

    private void joinGroup(Long orderId, GroupOrderVO groupOrder, MongoGroupTeamBO groupTeam) {
        // 拼团活动
        GroupActivityVO groupActivity = groupActivityMapper.getByGroupActivityId(groupTeam.getGroupActivityId());
        MongoGroupTeamBO newGroupTeam = groupTeamService.getByGroupTeamId(groupOrder.getGroupTeamId());
        newGroupTeam.setGroupTeamId(groupOrder.getGroupTeamId());
        // 参团
        newGroupTeam.setJoinNum(groupTeam.getJoinNum() + 1);
        newGroupTeam.setTotalPrice(groupTeam.getTotalPrice() + groupOrder.getPayPrice());

        // 参团人数未满，更新人数，金额
        if (newGroupTeam.getJoinNum() < groupActivity.getGroupNumber()) {
            updateTeamAndOrder(orderId, null, null, newGroupTeam);
            return;
        }

        updateGroupOrderInfo(groupActivity.getGroupActivityId());
        // 清除缓存-更新了已成团订单数及人数
        cacheManagerUtil.evictCache(GroupCacheNames.GROUP_BY_SPU_KEY, String.valueOf(groupActivity.getSpuId()));
        // 发送通知给订单，将所有同一个团并且已支付订单的状态变为待发货
        if (newGroupTeam.getJoinNum() >= groupActivity.getGroupNumber()) {
            List<MongoSuccessGroupOrderVO> successGroupOrders = listSuccessOrderIdByTeamId(groupTeam.getGroupTeamId(), true);
            List<Long> orderIds = successGroupOrders.stream().map(MongoSuccessGroupOrderVO::getOrderId).collect(Collectors.toList());

            GroupOrderNotifyBO groupOrderNotifyBO = new GroupOrderNotifyBO();
            groupOrderNotifyBO.setOrderIds(orderIds);
            groupOrderNotifyBO.setGroupOrders(Collections.singletonList(groupOrder));
            groupOrderNotifyBO.setIsJoin(1);
            // 事务消息-更改团队状态-发送通知更新拼团订单，发送通知给订单，将订单状态变为待发货
            TransactionSendResult transactionSendResult = groupOrderSuccessTemplate.sendMessageInTransaction(RocketMqConstant.GROUP_ORDER_SUCCESS_TOPIC, new GenericMessage<>(groupOrderNotifyBO), groupTeam);
            if (!Objects.equals(transactionSendResult.getLocalTransactionState(), LocalTransactionState.COMMIT_MESSAGE)) {
                throw new LuckException(ResponseEnum.EXCEPTION);
            }

            for (Long id : orderIds) {
                // 消息推送-拼团成功
                SendNotifyBO sendNotifyBO = new SendNotifyBO();
                sendNotifyBO.setSendType(SendTypeEnum.GROUP_SUCCESS.getValue());
                sendNotifyBO.setBizId(id);
                SendStatus sendBizStatus = sendGroupNotifyToUserTemplate.syncSend(RocketMqConstant.SEND_GROUP_NOTIFY_TO_USER_TOPIC, new GenericMessage<>(sendNotifyBO)).getSendStatus();
            }
        }
    }

    @Override
    public void initGroupOrderToMongo() {
        int start = 0;
        int size = 10000;
        mongoTemplate.remove(MongoGroupOrderBO.class);
        while (true) {
            // 批量以10000条处理
            List<MongoGroupOrderBO> mongoGroupOrderList = groupOrderMapper.listToMongodb(start, size);
            if (CollUtil.isEmpty(mongoGroupOrderList)) {
                break;
            }
            mongoTemplate.insertAll(mongoGroupOrderList);
            if (mongoGroupOrderList.size() <= size) {
                break;
            }
            start = start + size;
        }
    }
}
