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

import cn.hutool.core.collection.CollUtil;
import com.tmerclub.cloud.api.user.feign.UserFeignClient;
import com.tmerclub.cloud.api.user.vo.UserApiVO;
import com.tmerclub.cloud.common.exception.LuckException;
import com.tmerclub.cloud.common.response.ResponseEnum;
import com.tmerclub.cloud.common.response.ServerResponseEntity;
import com.tmerclub.cloud.common.util.BeanUtil;
import com.tmerclub.cloud.common.util.DateUtils;
import com.tmerclub.cloud.group.bo.mongo.MongoGroupTeamBO;
import com.tmerclub.cloud.group.constant.TeamStatusEnum;
import com.tmerclub.cloud.group.mapper.GroupActivityMapper;
import com.tmerclub.cloud.group.mapper.GroupTeamMapper;
import com.tmerclub.cloud.group.model.GroupTeam;
import com.tmerclub.cloud.group.service.GroupTeamService;
import com.tmerclub.cloud.group.vo.GroupActivityVO;
import com.tmerclub.cloud.group.vo.app.AppGroupTeamVO;
import com.mongodb.client.result.UpdateResult;
import org.apache.dubbo.config.annotation.DubboReference;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Sort;
import org.springframework.data.mongodb.core.MongoTemplate;
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.stereotype.Service;

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

/**
 * 拼团团队表
 * @author YXF
 */
@Service
public class GroupTeamServiceImpl implements GroupTeamService {
    private static final Logger logger = LoggerFactory.getLogger(GroupTeamServiceImpl.class);

    @Autowired
    private GroupTeamMapper groupTeamMapper;

    @Autowired
    private GroupActivityMapper groupActivityMapper;

    @DubboReference
    private UserFeignClient userFeignClient;

    @Autowired
    private MongoTemplate mongoTemplate;

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

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

    @Override
    public void update(GroupTeam groupTeam) {
        Update update = new Update();
        if (Objects.nonNull(groupTeam.getJoinNum())) {
            update.set("joinNum", groupTeam.getJoinNum());
        }
        if (Objects.nonNull(groupTeam.getTotalPrice())) {
            update.set("totalPrice", groupTeam.getTotalPrice());
        }
        if (Objects.nonNull(groupTeam.getStatus())) {
            update.set("status", groupTeam.getStatus());
        }
        if (Objects.nonNull(groupTeam.getStartTime())) {
            update.set("startTime", groupTeam.getStartTime());
        }
        if (Objects.nonNull(groupTeam.getEndTime())) {
            update.set("endTime", groupTeam.getEndTime());
        }
        Query query = new Query(Criteria.where("_id").is(groupTeam.getGroupTeamId()));
        mongoTemplate.updateFirst(query, update, MongoGroupTeamBO.class);
    }

    @Override
    public MongoGroupTeamBO getByGroupTeamId(Long groupTeamId) {
        return mongoTemplate.findById(groupTeamId, MongoGroupTeamBO.class);
    }

    @Override
    public List<AppGroupTeamVO> listJoinGroup(Long groupActivityId, Integer showSize) {
        Date date = new Date();
        Criteria criteria = new Criteria();
        criteria.and("groupActivityId").is(groupActivityId).and("status").is(TeamStatusEnum.IN_GROUP.value());
        criteria.and("startTime").lte(Objects.requireNonNull(DateUtils.dateToIsoDate(date)));
        criteria.and("endTime").gte(Objects.requireNonNull(DateUtils.dateToIsoDate(date)));
        Query query = new Query(criteria).with(Sort.by(Sort.Direction.DESC, "startTime")).limit(showSize);
        List<MongoGroupTeamBO> mongoGroupTeamBOList = mongoTemplate.find(query, MongoGroupTeamBO.class);
        if (CollUtil.isEmpty(mongoGroupTeamBOList)) {
            return new ArrayList<>();
        }
        List<AppGroupTeamVO> appGroupTeamList = BeanUtil.mapAsList(mongoGroupTeamBOList, AppGroupTeamVO.class);
        GroupActivityVO groupActivityVO = groupActivityMapper.getByGroupActivityId(groupActivityId);
        Set<Long> userIds = appGroupTeamList.stream().map(AppGroupTeamVO::getShareUserId).collect(Collectors.toSet());
        ServerResponseEntity<List<UserApiVO>> userResponse = userFeignClient.getUserByUserIds(new ArrayList<>(userIds));
        Map<Long, UserApiVO> userMap = userResponse.getData().stream().collect(Collectors.toMap(UserApiVO::getUserId, u -> u));
        for (AppGroupTeamVO appGroupTeamVO : appGroupTeamList) {
            UserApiVO userApiVO = userMap.get(appGroupTeamVO.getShareUserId());
            appGroupTeamVO.setGroupNumber(groupActivityVO.getGroupNumber());
            appGroupTeamVO.setShareNickName(userApiVO.getNickName());
            appGroupTeamVO.setSharePic(userApiVO.getPic());
        }
        return appGroupTeamList;
    }

    @Override
    public AppGroupTeamVO getAppGroupTeam(Long groupTeamId) {
        MongoGroupTeamBO mongoGroupTeamBO = getByGroupTeamId(groupTeamId);
        AppGroupTeamVO appGroupTeam = BeanUtil.map(mongoGroupTeamBO, AppGroupTeamVO.class);
        GroupActivityVO groupActivityVO = groupActivityMapper.getByGroupActivityId(appGroupTeam.getGroupActivityId());
        appGroupTeam.setGroupNumber(groupActivityVO.getGroupNumber());
        return appGroupTeam;
    }

    @Override
    public void cancelGroupTeam(Long groupTeamId) {
        Update update = new Update();
        update.set("status", TeamStatusEnum.FAIL.value());
        Query query = new Query(Criteria.where("_id").is(groupTeamId).and("status").is(TeamStatusEnum.WAITING_GROUP.value()));
        UpdateResult updateResult = mongoTemplate.updateFirst(query, update, MongoGroupTeamBO.class);
        if (updateResult.getModifiedCount() > 0) {
            logger.info("拼团团队取消{}", groupTeamId);
        }
    }

    @Override
    public void updateToSuccess(MongoGroupTeamBO groupTeam) {
        logger.info("团队更新为成功{}", groupTeam);
        Update update = new Update();
        update.set("status", TeamStatusEnum.SUCCESS.value());
        update.set("joinNum", groupTeam.getJoinNum());
        update.set("totalPrice", groupTeam.getTotalPrice());
        Query query = new Query(Criteria.where("_id").is(groupTeam.getGroupTeamId())
                .and("status").is(TeamStatusEnum.IN_GROUP.value()));
        UpdateResult updateResult = mongoTemplate.updateFirst(query, update, MongoGroupTeamBO.class);
        if (updateResult.getModifiedCount() < 1) {
            throw new LuckException(ResponseEnum.EXCEPTION);
        }
    }

    @Override
    public void updateToUnSuccess(Long groupTeamId) {
        logger.info("拼团失败" + groupTeamId);
        Update update = new Update();
        update.set("status", TeamStatusEnum.FAIL.value());
        Query query = new Query(Criteria.where("_id").is(groupTeamId).and("status").is(TeamStatusEnum.IN_GROUP.value()));
        UpdateResult updateResult = mongoTemplate.updateFirst(query, update, MongoGroupTeamBO.class);
        if (updateResult.getModifiedCount() < 1) {
            throw new LuckException(ResponseEnum.EXCEPTION);
        }
    }

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