package com.ym.mec.biz.service.impl;

import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.google.common.collect.Lists;
import com.ym.mec.auth.api.client.SysUserFeignService;
import com.ym.mec.auth.api.entity.SysUser;
import com.ym.mec.biz.dal.dao.TempLittleArtistTrainingCampDao;
import com.ym.mec.biz.dal.dto.ImGroupDto;
import com.ym.mec.biz.dal.dto.TempLittleArtistTrainingCampDto;
import com.ym.mec.biz.dal.entity.*;
import com.ym.mec.biz.dal.enums.MessageTypeEnum;
import com.ym.mec.biz.dal.vo.*;
import com.ym.mec.biz.service.*;
import com.ym.mec.common.exception.BizException;
import com.ym.mec.common.page.PageInfo;
import com.ym.mec.common.page.PageUtil;
import com.ym.mec.common.page.WrapperUtil;
import com.ym.mec.common.tenant.TenantContextHolder;
import com.ym.mec.thirdparty.message.MessageSenderPluginContext;
import com.ym.mec.util.date.DateUtil;
import com.ym.mec.util.excel.POIUtil;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.poi.hssf.usermodel.HSSFWorkbook;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.OutputStream;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.time.LocalDate;
import java.util.*;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.function.BiConsumer;
import java.util.function.Function;
import java.util.stream.Collectors;

/**
 * 小小艺术家训练营活动(TempLittleArtistTrainingCamp)表服务实现类
 *
 * @author hgw
 * @since 2022-05-17 20:56:23
 */
@Service("tempLittleArtistTrainingCampService")
public class TempLittleArtistTrainingCampServiceImpl extends ServiceImpl<TempLittleArtistTrainingCampDao, TempLittleArtistTrainingCamp> implements TempLittleArtistTrainingCampService {

    private final static Logger log = LoggerFactory.getLogger(TempLittleArtistTrainingCampServiceImpl.class);
    @Autowired
    private SysUserFeignService sysUserFeignService;
    @Autowired
    private TempLittleArtistTrainingCampUserRelationService tempLittleArtistTrainingCampUserRelationService;
    @Autowired
    private ImGroupService imGroupService;
    @Autowired
    private SysConfigService sysConfigService;
    @Autowired
    private SysMessageService sysMessageService;

    @Override
    public TempLittleArtistTrainingCampDao getDao() {
        return this.baseMapper;
    }

    /**
     * 新建训练营
     */
    @Transactional(rollbackFor = Exception.class)
    @Override
    public void add(TempLittleArtistTrainingCampDto dto) {
        SysUser user = getUser();
        Date now = DateUtil.toDate(LocalDate.now().toString());
        checkDateTime(dto, now);
        TempLittleArtistTrainingCamp entity = new TempLittleArtistTrainingCamp();
        BeanUtils.copyProperties(dto, entity);
        entity.setState(TempLittleArtistTrainingCamp.NOT_START);
        //报名开始时间 小于等于 今天时间 则报名状态为报名中
        if (dto.getApplyStartDate().getTime() <= now.getTime()) {
            entity.setState(TempLittleArtistTrainingCamp.APPLY);
        }
        entity.setCreateBy(user.getId());
        entity.setCreateTime(now);
        this.save(entity);
    }

    /**
     * 修改训练营
     */
    @Transactional(rollbackFor = Exception.class)
    @Override
    public void update(TempLittleArtistTrainingCampDto dto) {
        SysUser user = getUser();
        Date now = DateUtil.toDate(LocalDate.now().toString());
        checkDateTime(dto, now);
        TempLittleArtistTrainingCamp entity = Optional.ofNullable(dto.getId())
                .map(this::getById)
                .orElseThrow(() -> new BizException("训练营不存在"));
        int count = tempLittleArtistTrainingCampUserRelationService.count(Wrappers.<TempLittleArtistTrainingCampUserRelation>lambdaQuery()
                .eq(TempLittleArtistTrainingCampUserRelation::getActivityId, entity.getId()));
        if (count > 0) {
            throw new BizException("训练营已有学生报名，无法修改");
        }
        entity.setName(dto.getName());
        entity.setApplyStartDate(dto.getApplyStartDate());
        entity.setApplyEndDate(dto.getApplyEndDate());
        entity.setTrainStartDate(dto.getTrainStartDate());
        entity.setTrainEndDate(dto.getTrainEndDate());
        entity.setPicUrl(dto.getPicUrl());
        entity.setUpdateBy(user.getId());
        entity.setUpdateTime(new Date());
        this.updateById(entity);
    }

    /**
     * 校验时间
     */
    private void checkDateTime(TempLittleArtistTrainingCampDto dto, Date now) {
        if (dto.getApplyEndDate().getTime() < now.getTime()) {
            throw new BizException("报名结束时间不能小于今天");
        }
        if (dto.getApplyStartDate().getTime() > dto.getApplyEndDate().getTime()) {
            throw new BizException("报名开始时间不能大于结束时间");
        }
        if (dto.getTrainStartDate().getTime() > dto.getTrainEndDate().getTime()) {
            throw new BizException("训练开始时间不能大于训练结束时间");
        }
        //报名结束时间必需小于训练开始时间
        if (dto.getTrainStartDate().getTime() < dto.getApplyEndDate().getTime()) {
            throw new BizException("报名结束时间必需小于训练开始时间");
        }
    }

    /**
     * 删除训练营
     */
    @Transactional(rollbackFor = Exception.class)
    @Override
    public void delete(Integer id) {
        TempLittleArtistTrainingCamp entity = Optional.ofNullable(id)
                .map(this::getById)
                .orElseThrow(() -> new BizException("训练营不存在"));
        int count = tempLittleArtistTrainingCampUserRelationService.count(Wrappers.<TempLittleArtistTrainingCampUserRelation>lambdaQuery()
                .eq(TempLittleArtistTrainingCampUserRelation::getActivityId, entity.getId()));
        if (count > 0) {
            throw new BizException("训练营已有学生报名，无法删除");
        }
        entity.setDelFlag(1);
        this.updateById(entity);
    }

    /**
     * 分页查询-训练营列表
     *
     * @param param 条件
     *              <p> - row 条数
     *              <p> - page 页数
     *              <p> - name 训练营标题-模糊搜索
     *              <p> - state 筹备中 READY,报名中 APPLY,未开始 NOT_START,进行中 ING,已结束 END
     *              <p> - applyStartDate 申请报名登记开始日期
     *              <p> - applyEndDate 申请报名登记结束日期
     *              <p> - trainStartDate 训练开始日期
     *              <p> - trainEndDate 训练结束日期
     */
    @Override
    public PageInfo<TempLittleArtistTrainingCamp> queryPageTrainingCamp(Map<String, Object> param) {
        Page<TempLittleArtistTrainingCamp> page = PageUtil.getPageInfo(param);
        page.setAsc("apply_start_date_");
        IPage<TempLittleArtistTrainingCamp> pageList = this.page(page, Wrappers.<TempLittleArtistTrainingCamp>lambdaQuery()
                .eq(TempLittleArtistTrainingCamp::getDelFlag, 0)
                .eq(WrapperUtil.strParamIsNull(param, "name"), TempLittleArtistTrainingCamp::getName, WrapperUtil.toStr(param, "name"))
                .eq(WrapperUtil.strParamIsNull(param, "state"), TempLittleArtistTrainingCamp::getState, WrapperUtil.toStr(param, "state"))
                .ge(Objects.nonNull(param.get("applyStartDate")), TempLittleArtistTrainingCamp::getApplyStartDate, param.get("applyStartDate"))
                .le(Objects.nonNull(param.get("applyEndDate")), TempLittleArtistTrainingCamp::getApplyEndDate, param.get("applyEndDate"))
                .ge(Objects.nonNull(param.get("trainStartDate")), TempLittleArtistTrainingCamp::getTrainStartDate, param.get("trainStartDate"))
                .le(Objects.nonNull(param.get("trainEndDate")), TempLittleArtistTrainingCamp::getTrainEndDate, param.get("trainEndDate")));
        return PageUtil.pageInfo(pageList);
    }

    /**
     * 参与名单
     *
     * @param param 条件
     *              <p> - row 条数
     *              <p> - page 页数
     *              <p> - state 状态：未报名NOT_APPLY ，已报名 APPLY
     *              <p> - search 学员姓名/手机号/编号
     */
    @Override
    public PageInfo<TempCampUserVo> queryPageTrainingCampUser(Map<String, Object> param) {
        Page<TempCampUserVo> pageInfo = PageUtil.getPageInfo(param);
        pageInfo.setDesc("a.create_time_");
        return PageUtil.pageInfo(baseMapper.queryCampUser(pageInfo, param));
    }

    /**
     * 查询指定学生-训练营每日训练时长
     *
     * @param param 参数
     *              <p> - userId 用户id
     */
    @Override
    public List<TempUserTrainingTimeDetailVo> queryUserTrainingTime(Map<String, Object> param) {
        Integer userId = WrapperUtil.toInt(param, "userId", "学员id不能为空");
        //查询训练营的训练时间段
        TempLittleArtistTrainingCampUserRelation campUser = tempLittleArtistTrainingCampUserRelationService.getOne(Wrappers.<TempLittleArtistTrainingCampUserRelation>lambdaQuery()
                .eq(TempLittleArtistTrainingCampUserRelation::getUserId, userId));
        TempLittleArtistTrainingCamp camp = this.getOne(Wrappers.<TempLittleArtistTrainingCamp>lambdaQuery()
                .eq(TempLittleArtistTrainingCamp::getId, campUser.getActivityId())
                .eq(TempLittleArtistTrainingCamp::getDelFlag, 0));
        String startDateStr = DateUtil.dateToString(camp.getTrainStartDate());
        String endDateStr = DateUtil.dateToString(camp.getTrainEndDate());

        //生成训练时间集合
        List<TempUserTrainingTimeDetailVo> resultList = new ArrayList<>();
        LocalDate generateDate = LocalDate.parse(startDateStr);
        boolean flag = true;
        while (flag) {
            if (generateDate.toString().equals(endDateStr)) {
                flag = false;
            }
            TempUserTrainingTimeDetailVo tempUserTrainingTimeDetailVo = new TempUserTrainingTimeDetailVo();
            tempUserTrainingTimeDetailVo.setUserId(userId);
            tempUserTrainingTimeDetailVo.setTrainingDate(DateUtil.toDate(generateDate.toString()));
            tempUserTrainingTimeDetailVo.setPlayTime(BigDecimal.ZERO);
            tempUserTrainingTimeDetailVo.setIsFinish(0);
            resultList.add(tempUserTrainingTimeDetailVo);
            generateDate = generateDate.plusDays(1);
        }
        //查询每日训练时长
        param.put("startTime", startDateStr + " 00:00:00");
        param.put("endTime", endDateStr + " 23:59:59");
        List<TempUserTrainingTimeDetailVo> userTrainingTimeList = baseMapper.queryUserTrainingTime(param);
        //拼接数据
        if (CollectionUtils.isNotEmpty(userTrainingTimeList)) {
            Map<String, BigDecimal> nowTrainingTime = userTrainingTimeList.stream()
                    .collect(Collectors.toMap(k -> DateUtil.dateToString(k.getTrainingDate()), TempUserTrainingTimeDetailVo::getPlayTime));
            resultList.forEach(vo -> {
                String s = DateUtil.dateToString(vo.getTrainingDate());
                BigDecimal t = nowTrainingTime.get(s);
                if (Objects.nonNull(t)) {
                    vo.setPlayTime(t);
                    //大于1200秒
                    if (t.intValue() > 1200) {
                        vo.setIsFinish(1);
                    }
                }
            });
        }
        return resultList;
    }

    /**
     * 分页查询-训练营详情
     *
     * @param param 条件
     *              <p> - row 条数
     *              <p> - page 页数
     *              <p> - imGroupId  所在群组Id
     *              <p> - search 学员姓名/手机号/编号
     */
    @Override
    public PageInfo<TempCampUserTrainingDetailVo> queryUserTrainingDetail(Map<String, Object> param) {
        //训练营详情-查询条件时间设置
        queryUserTrainingDetailOpsParam(param);
        Page<TempCampUserTrainingDetailVo> page = PageUtil.getPageInfo(param);
        page.setDesc("b.playDay");
        return PageUtil.pageInfo(baseMapper.queryUserTrainingDetail(page, param));
    }

    /**
     * 训练营详情-查询条件时间设置
     */
    private void queryUserTrainingDetailOpsParam(Map<String, Object> param) {
        Integer campId = WrapperUtil.toInt(param, "campId", "训练营id不能为空");
        TempLittleArtistTrainingCamp camp = this.getOne(Wrappers.<TempLittleArtistTrainingCamp>lambdaQuery()
                .eq(TempLittleArtistTrainingCamp::getId, campId)
                .eq(TempLittleArtistTrainingCamp::getDelFlag, 0));
        param.put("startTime", camp.getTrainStartDate());
        param.put("endTime", camp.getTrainEndDate());
        param.put("state", TempLittleArtistTrainingCampUserRelation.APPLY);
    }

    /**
     * 根据群组Id查询群组信息
     *
     * @param imGroupIds 群组id，多个用逗号隔开
     */
    @Override
    public List<ImGroup> queryCampImGroup(String imGroupIds) {
        return baseMapper.queryCampImGroup(imGroupIds);
    }

    /**
     * 查询训练营周期表
     *
     * @return result：
     * <p>user 学员信息
     * <p>campList 训练营信息
     */
    @Override
    public Map<String, Object> queryCampCycle() {
        SysUser user = getUser();
        //查询未删除的训练营
        List<TempLittleArtistTrainingCamp> campList = this.list(Wrappers.<TempLittleArtistTrainingCamp>lambdaQuery()
                .eq(TempLittleArtistTrainingCamp::getDelFlag, 0));
        //查询该学员是否购买过该训练营
        TempLittleArtistTrainingCampUserRelation userRelation = tempLittleArtistTrainingCampUserRelationService.getOne(Wrappers.<TempLittleArtistTrainingCampUserRelation>lambdaQuery()
                .eq(TempLittleArtistTrainingCampUserRelation::getUserId, user.getId()));
        Map<String, Object> result = new HashMap<>();
        result.put("user", userRelation);
        if (CollectionUtils.isNotEmpty(campList)) {
            campList = campList.stream()
                    .peek(a -> {
                        int count = tempLittleArtistTrainingCampUserRelationService.count(Wrappers.<TempLittleArtistTrainingCampUserRelation>lambdaQuery()
                                .eq(TempLittleArtistTrainingCampUserRelation::getActivityId, a.getId()));
                        a.setUserCount(count);
                    })
                    .sorted(Comparator.comparing(TempLittleArtistTrainingCamp::getApplyStartDate))
                    .collect(Collectors.toList());
        }
        result.put("campList", campList);
        return result;
    }

    /**
     * 定时任务-修改训练营状态-每天0点执行一次
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void checkCampState() {
        //查询未结束 并 未删除的训练营
        List<TempLittleArtistTrainingCamp> campList = this.list(Wrappers.<TempLittleArtistTrainingCamp>lambdaQuery()
                .eq(TempLittleArtistTrainingCamp::getDelFlag, 0)
                .ne(TempLittleArtistTrainingCamp::getState, TempLittleArtistTrainingCamp.END));
        if (CollectionUtils.isEmpty(campList)) {
            return;
        }
        Date now = DateUtil.stringToDate(LocalDate.now() + " 00:00:00");
        //将训练营数据根据状态分组，未开始 NOT_START,报名中 APPLY,筹备中 READY,进行中 ING,已结束 END
        Map<String, List<TempLittleArtistTrainingCamp>> stateMap = WrapperUtil.groupList(campList, TempLittleArtistTrainingCamp::getState);
        //未开始 NOT_START 修改为 报名中 APPLY
        opsState(now, stateMap, TempLittleArtistTrainingCamp.NOT_START, TempLittleArtistTrainingCamp::getApplyStartDate, TempLittleArtistTrainingCamp.APPLY);
        //报名中 APPLY 修改为 筹备中 READY  如果报名结束日期+1天正好等于训练开始时间 并 训练时间正好是今天那么直接变更为进行中状态，那么直接修改为进行中状态
        opsState(now, stateMap, TempLittleArtistTrainingCamp.APPLY, TempLittleArtistTrainingCamp::getApplyEndDate, TempLittleArtistTrainingCamp.READY);
        //筹备中 READY 修改为 进行中 ING
        opsState(now, stateMap, TempLittleArtistTrainingCamp.READY, TempLittleArtistTrainingCamp::getTrainStartDate, TempLittleArtistTrainingCamp.ING);
        //进行中 ING 修改为 已结束 END
        opsState(now, stateMap, TempLittleArtistTrainingCamp.ING, TempLittleArtistTrainingCamp::getTrainEndDate, TempLittleArtistTrainingCamp.END);
        //修改数据
        campList.forEach(this::updateById);
        //对今天开始训练的人进行分组
        this.studentGrouping(now);
    }

    /**
     * 修改训练营状态
     *
     * @param now       当前时间
     * @param stateMap  训练营状态分组
     * @param oldState  原状态
     * @param dateField 时间字段
     * @param newState  新状态
     */
    private void opsState(Date now, Map<String, List<TempLittleArtistTrainingCamp>> stateMap, String oldState,
                          Function<TempLittleArtistTrainingCamp, Date> dateField, String newState) {
        List<TempLittleArtistTrainingCamp> list = stateMap.get(oldState);
        if (CollectionUtils.isNotEmpty(list)) {
            list.forEach(camp -> {
                //报名中的状态
                if (oldState.equals(TempLittleArtistTrainingCamp.APPLY)) {
                    //报名结束日期+1天
                    long appleEndAddTime = DateUtil.addDays(camp.getApplyEndDate(), 1).getTime();
                    //训练开始时间
                    long trainStartTime = camp.getTrainStartDate().getTime();
                    //今天
                    long nowTime = DateUtil.toDate(LocalDate.now().toString()).getTime();
                    //报名结束日期+1天正好等于训练开始时间 并 训练时间正好是今天那么直接变更为进行中状态
                    if (appleEndAddTime == trainStartTime && nowTime == trainStartTime) {
                        camp.setState(TempLittleArtistTrainingCamp.ING);
                        return;
                    }
                }
                if (now.getTime() >= dateField.apply(camp).getTime()) {
                    camp.setState(newState);
                }
            });
        }
    }

    /**
     * 对开始训练的的学员进行分组
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void studentGrouping(Date now) {
        now = Optional.ofNullable(now).orElse(DateUtil.stringToDate(LocalDate.now() + " 00:00:00"));
        //待数据修改后-查询训练开始时间为今天并且没有分组并且状态为进行中的数据
        List<TempLittleArtistTrainingCamp> groupCampList = this.list(Wrappers.<TempLittleArtistTrainingCamp>lambdaQuery()
                .eq(TempLittleArtistTrainingCamp::getDelFlag, 0)
                .eq(TempLittleArtistTrainingCamp::getState, TempLittleArtistTrainingCamp.ING)
                .isNull(TempLittleArtistTrainingCamp::getImGroupIds)
                .eq(TempLittleArtistTrainingCamp::getTrainStartDate, now)
        );
        if (CollectionUtils.isEmpty(groupCampList)) {
            return;
        }
        TenantContextHolder.setTenantId(1);
        String groupType = "TRAINING";
        //每个房间最大人数
        BigDecimal maxUserNum = Optional.of("temp_little_artist_training_camp_grouping_num")
                .map(sysConfigService::findByParamName)
                .filter(a -> StringUtils.isNotBlank(a.getParanValue()))
                .map(SysConfig::getParanValue)
                .map(BigDecimal::new)
                .orElse(new BigDecimal("60"));
        //key-训练营id  value-训练营集合
        groupCampList.forEach(camp -> {
            List<String> imGroupIds = new ArrayList<>();
            //查询该训练营 已报名且没分组的学员
            List<Integer> userList = baseMapper.queryUserGroup(camp.getId());
            if (CollectionUtils.isEmpty(userList)) {
                return;//训练营没人报名
            }
            List<String> userStrList = userList.stream().map(String::valueOf).collect(Collectors.toList());
            //报名人数
            int totalUserNum = userStrList.size();
            BigDecimal applyNum = new BigDecimal(totalUserNum + "");
            //修改修改关系表 imGroup
            BiConsumer<String, List<String>> updateGroup = (groupId, list) -> tempLittleArtistTrainingCampUserRelationService.update(Wrappers.<TempLittleArtistTrainingCampUserRelation>lambdaUpdate()
                    .set(TempLittleArtistTrainingCampUserRelation::getImGroupId, groupId)
                    .eq(TempLittleArtistTrainingCampUserRelation::getActivityId, camp.getId())
                    .in(TempLittleArtistTrainingCampUserRelation::getUserId, list)
                    .isNull(TempLittleArtistTrainingCampUserRelation::getImGroupId));
            //如果人数小于最大人数 则直接分组
            if (maxUserNum.intValue() >= applyNum.intValue()) {
                //分组
                ImGroupDto imGroupDto = new ImGroupDto();
                imGroupDto.setGroupType(ImGroup.GroupTypeEnum.TRAINING);
                imGroupDto.setType(groupType);
                imGroupDto.setGroupName(camp.getName() + "-1群");
                imGroupDto.setUserIdList(userStrList);
                String groupId = imGroupService.createGroup(imGroupDto);
                imGroupIds.add(groupId);
                //修改关系表
                updateGroup.accept(groupId, userStrList);
            } else {
                //分组数 ->报名人数 ➗ 每组最大人数 有小数就向上取整 1.01 -> 2
                BigDecimal groupNum = applyNum.divide(maxUserNum, 0, RoundingMode.UP);
                //每组分配人数 向下取整 1.01 -> 2
                BigDecimal groupUserNum = applyNum.divide(groupNum, 0, RoundingMode.UP);
                //切分人数
                List<List<String>> partition = Lists.partition(userStrList, groupUserNum.intValue());
                //群号
                AtomicInteger i = new AtomicInteger(1);
                partition.forEach(list -> {
                    ImGroupDto imGroupDto = new ImGroupDto();
                    imGroupDto.setGroupType(ImGroup.GroupTypeEnum.TRAINING);
                    imGroupDto.setType(groupType);
                    imGroupDto.setGroupName(camp.getName() + "-" + i.get() + "群");
                    imGroupDto.setUserIdList(list);
                    String groupId = imGroupService.createGroup(imGroupDto);
                    updateGroup.accept(groupId, list);
                    //修改关系表
                    imGroupIds.add(groupId);
                    i.getAndIncrement();
                });
            }
            camp.setImGroupIds(String.join(",", imGroupIds));
            this.updateById(camp);
        });
        TenantContextHolder.clearTenantId();
    }

    /**
     * 每天早上8点执行-查询当天开启训练营并已分群的用户
     * <p>您已加入小小艺术家训练营{群组标题}，及时查看群聊消息完成老师布置的任务哦
     */
    @Override
    public void pushStartTrain() {
        //查询学员id  对应的训练营名称
        List<BaseVo> baseVos = baseMapper.queryStartTrainInfo(LocalDate.now().toString());
        if (CollectionUtils.isEmpty(baseVos)) {
            return;
        }
        Map<String, List<BaseVo>> pushUserList = WrapperUtil.groupList(baseVos, BaseVo::getName);
        pushUserList.forEach((imGroupName, list) -> {
            Map<Integer, String> push = new HashMap<>();
            for (BaseVo obj : list) {
                push.put(obj.getId(), obj.getId().toString());
            }
            try {
                //训练营开始训练推送
                sysMessageService.batchSendMessage(MessageSenderPluginContext.MessageSender.JIGUANG,
                        MessageTypeEnum.JIGUANG_TEMP_LITTLE_ARTIST_START_TRAIN, push,
                        null, 0, null, "STUDENT", imGroupName);
            } catch (Exception e) {
                log.error("推送消息失败", e);
            }
        });
    }

    /**
     * 云教练训练是否达标
     */
    @Override
    public TempCampUserTrainingPlayTimeVo queryUserTrainingPlayTime() {
        SysUser user = getUser();
        //查询训练营人员关系
        TempLittleArtistTrainingCampUserRelation campUser = tempLittleArtistTrainingCampUserRelationService.getOne(Wrappers.<TempLittleArtistTrainingCampUserRelation>lambdaQuery()
                .eq(TempLittleArtistTrainingCampUserRelation::getUserId, user.getId())
                .eq(TempLittleArtistTrainingCampUserRelation::getState, TempLittleArtistTrainingCampUserRelation.APPLY)
        );
        if (Objects.isNull(campUser)) {
            return null;
        }
        //查询在训练中的训练营
        TempLittleArtistTrainingCamp camp = this.getOne(Wrappers.<TempLittleArtistTrainingCamp>lambdaQuery()
                .eq(TempLittleArtistTrainingCamp::getId, campUser.getActivityId())
                .eq(TempLittleArtistTrainingCamp::getState, TempLittleArtistTrainingCamp.ING)
                .eq(TempLittleArtistTrainingCamp::getDelFlag, 0));
        if (Objects.isNull(camp)) {
            return null;
        }
        LocalDate now = LocalDate.now();
        TempCampUserTrainingPlayTimeVo vo = new TempCampUserTrainingPlayTimeVo();
        Map<String, Object> param = new HashMap<>();
        param.put("userId", user.getId());
        param.put("startTime", now + " 00:00:00");
        param.put("endTime", now + " 23:59:59");
        Integer playTime = baseMapper.queryUserTrainingPlayTime(param);
        vo.setPlayTime(playTime);
        vo.setTrainStartDate(camp.getTrainStartDate());
        vo.setTrainEndDate(camp.getTrainEndDate());
        vo.setIsFinish(playTime >= 1200 ? 0 : 1);
        return vo;
    }

    /**
     * 导出小小训练营想详情
     */
    public void exportUserTrainingDetail(Map<String, Object> param, HttpServletResponse response) throws IOException {
        //训练营详情-查询条件时间设置
        queryUserTrainingDetailOpsParam(param);
        List<TempCampUserTrainingDetailVo> list = baseMapper.queryUserTrainingDetail(param);
        OutputStream outputStream = response.getOutputStream();
        HSSFWorkbook workbook = null;
        try {
            String[] header = {"学员编号", "学员姓名", "手机号", "群组", "打卡天数", "训练时长（分钟）"};
            String[] body = {"id", "username", "phone", "imGroupName", "playDay", "playTime"};
            workbook = POIUtil.exportExcel(header, body, list);
            response.setContentType("application/octet-stream");
            response.setHeader("Content-Disposition", "attachment;filename=replacement-" + DateUtil.getDate(new Date()) + ".xls");
            response.flushBuffer();
            outputStream = response.getOutputStream();
            workbook.write(outputStream);
            outputStream.flush();
            workbook.close();
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            if (outputStream != null) {
                try {
                    workbook.close();
                    outputStream.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }

    private SysUser getUser() {
        return Optional.ofNullable(sysUserFeignService.queryUserInfo())
                .orElseThrow(() -> new BizException("用户信息获取失败,请刷新页面或者重新登录!"));
    }

}

