package com.qmth.themis.business.service.impl;

import cn.hutool.core.date.DateUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.qmth.themis.business.bean.admin.*;
import com.qmth.themis.business.bean.result.TimeOnlineDataResult;
import com.qmth.themis.business.bean.result.TimeScaleDataResult;
import com.qmth.themis.business.cache.bean.ExamCacheBean;
import com.qmth.themis.business.constant.SystemConstant;
import com.qmth.themis.business.dao.*;
import com.qmth.themis.business.entity.*;
import com.qmth.themis.business.enums.InvigilateMonitorStatusEnum;
import com.qmth.themis.business.service.*;
import com.qmth.themis.business.util.ServletUtil;
import com.qmth.themis.common.contanst.Constants;
import com.qmth.themis.common.exception.BusinessException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;

import javax.annotation.Resource;
import java.time.LocalDateTime;
import java.time.ZoneOffset;
import java.util.*;
import java.util.function.Function;
import java.util.stream.Collectors;

/**
 * @Description: 报表数据
 * @Param:
 * @return:
 * @Author: wangliang
 * @Date: 2022/8/19
 */
@Service
public class TIeReportServiceImpl implements TIeReportService {
    private final static Logger log = LoggerFactory.getLogger(TIeReportServiceImpl.class);

    @Resource
    TEExamStudentMapper examStudentMapper;

    @Resource
    TEExamActivityService examActivityService;

    @Resource
    TEExamService examService;

    @Resource
    TIeInvigilateExceptionInfoMapper invigilateExceptionInfoMapper;

    @Resource
    TIeInvigilateWarnInfoMapper invigilateWarnInfoMapper;

    @Resource
    TEExamReexamMapper examReexamMapper;

    @Resource
    TEExamBreachLogMapper examBreachLogMapper;

    @Resource
    TEExamStudentLogMapper examStudentLogMapper;

    @Resource
    TOeExamRecordMapper tOeExamRecordMapper;

    @Resource
    ThemisCacheService themisCacheService;

    @Resource
    TEExamService teExamService;

    /**
     * 考试概览
     *
     * @param orgId
     * @param examId
     * @param examActivityId
     * @param roomCode
     * @param courseCode
     * @param name
     * @param identity
     * @return
     */
    @Override
    public Map<String, Object> examView(Long orgId, Long examId, Long examActivityId, String roomCode, String courseCode,
                                        String name, String identity) {
        // 缺考人数
        Integer examTotal = 0, actualExamTotal = 0, absentNum = 0;
        ExamCacheBean exam = examService.getExamCacheBean(examId);
        List<TEExamSummary> teExamSummaryList = null;
        if (Objects.nonNull(examId)) {
            teExamSummaryList = themisCacheService.getExamSummaryCache(examId);
        } else if (Objects.nonNull(examId) && Objects.nonNull(examActivityId)) {
            teExamSummaryList = themisCacheService.getExamSummaryCache(examId, examActivityId);
        } else if (Objects.nonNull(examId) && Objects.nonNull(examActivityId) && Objects.nonNull(roomCode)) {
            teExamSummaryList = themisCacheService.getExamSummaryCache(examId, examActivityId, roomCode);
        }
        for (TEExamSummary t : teExamSummaryList) {
            examTotal = examTotal + t.getTotalCount();
            absentNum = absentNum + t.getAbsentCount();
            actualExamTotal = examTotal - absentNum;
        }
        // 每日已考人数
        List<Map<String, Object>> doneCountByDay = tOeExamRecordMapper.getDoneCountByDay(orgId, examId, examActivityId, roomCode, courseCode);

        Map<String, Object> ret = new HashMap<String, Object>();
        ret.put("monitorStatus", exam.getMonitorStatus());
        ret.put("examTotal", examTotal.intValue());
        ret.put("actualExamTotal", actualExamTotal.intValue());
        ret.put("deficiencyExamTotal", absentNum.intValue());
        ret.put("completeOffExamTotal", absentNum);
        ret.put("examTotalList", doneCountByDay);
        return ret;
    }

    /**
     * 情况统计
     *
     * @param orgId
     * @param examId
     * @param examActivityId
     * @param roomCode
     * @param courseCode
     * @param name
     * @param identity
     * @param pageNumber
     * @param pageSize
     * @return
     */
    @Override
    public IPage<ExamViewCountListBean> examViewCount(Long orgId, Long examId, Long examActivityId, String roomCode, String courseCode, String name,
                                                      String identity, int pageNumber, int pageSize) {
        return examStudentMapper.getTotalCountInfo(new Page<>(pageNumber, pageSize), orgId, examId, examActivityId, roomCode, courseCode);
    }

    /**
     * 情况统计考出
     *
     * @param orgId
     * @param examId
     * @param examActivityId
     * @param roomCode
     * @param courseCode
     * @param name
     * @param identity
     * @return
     */
    @Override
    public List<ExamViewCountListBean> examViewCountExport(Long orgId, Long examId, Long examActivityId, String roomCode, String courseCode, String name, String identity) {
        return examStudentMapper.getTotalCountInfoExport(orgId, examId, examActivityId, roomCode, courseCode);
    }

    /**
     * 缺考名单
     *
     * @param orgId
     * @param examId
     * @param examActivityId
     * @param roomCode
     * @param courseCode
     * @param name
     * @param identity
     * @param pageNumber
     * @param pageSize
     * @return
     */
    @Override
    public IPage<ExamDeficiencyListBean> examDeficiencyList(Long orgId, Long examId, Long examActivityId, String roomCode, String courseCode,
                                                            String name, String identity, int pageNumber, int pageSize) {
        List<TEExamActivity> acs = examActivityService.findByExamIdAndOrgId(examId, orgId);
        List<Long> absentActivityIds = new ArrayList<>();
        for (TEExamActivity ac : acs) {
            ExamCacheBean exam = examService.getExamCacheBean(ac.getExamId());
            if (InvigilateMonitorStatusEnum.FINISHED.equals(exam.getMonitorStatus())) {// 结束监考的，未考试的都是缺考
                absentActivityIds.add(ac.getId());
            }
        }
        if (absentActivityIds.size() == 0) {
            return new Page<>(pageNumber, pageSize);
        }
        return examStudentMapper.getExamDeficiencyPage(new Page<>(pageNumber, pageSize), examId, examActivityId,
                roomCode, courseCode, name, identity, absentActivityIds);
    }

    /**
     * 缺考名单导出
     *
     * @param orgId
     * @param examId
     * @param examActivityId
     * @param roomCode
     * @param courseCode
     * @param name
     * @param identity
     * @return
     */
    @Override
    public List<ExamDeficiencyListBean> examDeficiencyListExport(Long orgId, Long examId, Long examActivityId, String roomCode, String courseCode, String name, String identity) {
        List<TEExamActivity> acs = examActivityService.findByExamIdAndOrgId(examId, orgId);
        List<Long> absentActivityIds = new ArrayList<>();
        for (TEExamActivity ac : acs) {
            ExamCacheBean exam = examService.getExamCacheBean(ac.getExamId());
            if (InvigilateMonitorStatusEnum.FINISHED.equals(exam.getMonitorStatus())) {// 结束监考的，未考试的都是缺考
                absentActivityIds.add(ac.getId());
            }
        }
        return examStudentMapper.getExamDeficiencyPageExport(examId, examActivityId, roomCode, courseCode, name, identity, absentActivityIds);
    }

    /**
     * 异常处理
     *
     * @param examId
     * @param examActivityId
     * @param roomCode
     * @param courseCode
     * @param name
     * @param identity
     * @param pageNumber
     * @param pageSize
     * @return
     */
    @Override
    public IPage<ExamExceptionListBean> examExceptionList(Long examId, Long examActivityId, String roomCode, String courseCode, String name,
                                                          String identity, int pageNumber, int pageSize) {
        TBUser tbUser = (TBUser) ServletUtil.getRequestAccount();
        return invigilateExceptionInfoMapper.getExamExceptionPage(new Page<>(pageNumber, pageSize), tbUser.getOrgId(), examId,
                examActivityId, roomCode, courseCode, name, identity);
    }

    /**
     * 异常处理明细
     *
     * @param examStudentId
     * @param pageNumber
     * @param pageSize
     * @return
     */
    @Override
    public IPage<ExamExceptionDetailListBean> examExceptionDetailList(Long examStudentId, int pageNumber, int pageSize) {
        return invigilateExceptionInfoMapper.getExamExceptionDetailList(new Page<>(pageNumber, pageSize), examStudentId);
    }

    /**
     * 重考处理
     *
     * @param examId
     * @param examActivityId
     * @param roomCode
     * @param courseCode
     * @param name
     * @param identity
     * @param pageNumber
     * @param pageSize
     * @return
     */
    @Override
    public IPage<ExamReexamListBean> examReexamList(Long examId, Long examActivityId, String roomCode, String courseCode, String name,
                                                    String identity, int pageNumber, int pageSize) {
        TBUser tbUser = (TBUser) ServletUtil.getRequestAccount();
        return examReexamMapper.getExamReexamPage(new Page<>(pageNumber, pageSize), tbUser.getOrgId(), examId, examActivityId, roomCode,
                courseCode, name, identity);
    }

    /**
     * 违纪名单
     *
     * @param examId
     * @param examActivityId
     * @param roomCode
     * @param courseCode
     * @param name
     * @param identity
     * @param pageNumber
     * @param pageSize
     * @return
     */
    @Override
    public IPage<ExamBreachListBean> examBreachList(Long examId, Long examActivityId, String roomCode, String courseCode, String name,
                                                    String identity, int pageNumber, int pageSize) {
        TBUser tbUser = (TBUser) ServletUtil.getRequestAccount();
        return examBreachLogMapper.getExamBreachPage(new Page<>(pageNumber, pageSize), tbUser.getOrgId(), examId, examActivityId, roomCode,
                courseCode, name, identity);
    }

    /**
     * 违纪名单导出
     *
     * @param examId
     * @param examActivityId
     * @param roomCode
     * @param courseCode
     * @param name
     * @param identity
     * @return
     */
    @Override
    public List<ExamBreachListExportBean> examBreachListExport(Long examId, Long examActivityId, String roomCode, String courseCode, String name, String identity) {
        TBUser tbUser = (TBUser) ServletUtil.getRequestAccount();
        return examBreachLogMapper.getExamBreachPageExport(tbUser.getOrgId(), examId, examActivityId, roomCode, courseCode, name, identity);
    }

    /**
     * 违纪名单明细
     *
     * @param examStudentId
     * @param status
     * @param pageNumber
     * @param pageSize
     * @return
     */
    @Override
    public IPage<ExamBreachDetailListBean> examBreachListDetail(Long examStudentId, Integer status, int pageNumber, int pageSize) {
        return examBreachLogMapper.getExamBreachDetailList(new Page<>(pageNumber, pageSize), examStudentId, status);
    }

    /**
     * 撤销违纪名单
     *
     * @param examId
     * @param examActivityId
     * @param roomCode
     * @param courseCode
     * @param name
     * @param identity
     * @param pageNumber
     * @param pageSize
     * @return
     */
    @Override
    public IPage<ExamBreachListBean> examRevokeBreachList(Long examId, Long examActivityId, String roomCode, String courseCode,
                                                          String name, String identity, int pageNumber, int pageSize) {
        TBUser tbUser = (TBUser) ServletUtil.getRequestAccount();
        return examBreachLogMapper.getExamRevokeBreachPage(new Page<>(pageNumber, pageSize), tbUser.getOrgId(), examId, examActivityId,
                roomCode, courseCode, name, identity);
    }

    /**
     * 撤销违纪名单明细
     *
     * @param examStudentId
     * @param status
     * @param pageNumber
     * @param pageSize
     * @return
     */
    @Override
    public IPage<ExamBreachDetailListBean> examRevokeBreachListDetail(Long examStudentId, Integer status, int pageNumber, int pageSize) {
        return examBreachLogMapper.getExamBreachDetailList(new Page<>(pageNumber, pageSize), examStudentId, status);
    }

    /**
     * 考生日志
     *
     * @param examId
     * @param examActivityId
     * @param roomCode
     * @param courseCode
     * @param name
     * @param identity
     * @param pageNumber
     * @param pageSize
     * @return
     */
    @Override
    public IPage<ExamStudentLogListBean> examStudentLogList(Long examId, Long examActivityId, String roomCode, String courseCode,
                                                            String name, String identity, int pageNumber, int pageSize) {
        TBUser tbUser = (TBUser) ServletUtil.getRequestAccount();
        return examStudentMapper.getPageForStudentLog(new Page<>(pageNumber, pageSize), tbUser.getOrgId(), examId, examActivityId,
                roomCode, courseCode, name, identity);
    }

    /**
     * 考生日志明细
     *
     * @param examStudentId
     * @param pageNumber
     * @param pageSize
     * @return
     */
    @Override
    public IPage<ExamStudentLogDetailListBean> examStudentLogListDetail(Long examStudentId, int pageNumber, int pageSize) {
        IPage<ExamStudentLogDetailListBean> examStudentLogDetailListBeanIPage = examStudentLogMapper.getExamStudentLogList(new Page<>(pageNumber, pageSize), examStudentId);
        if (Objects.nonNull(examStudentLogDetailListBeanIPage) && !CollectionUtils.isEmpty(examStudentLogDetailListBeanIPage.getRecords())) {
            IPage<ExamStudentLogDetailListBean> examStudentLogDetailListBeanIPageAll = examStudentLogMapper.getExamStudentLogList(new Page<>(SystemConstant.PAGE_NUMBER_MIN, SystemConstant.SELECT_PAGE_SIZE_MAX), examStudentId);
            examStudentLogDetailListBeanIPageAll = examStudentLogDetailListBeanIPageAll.getRecords().get(0).ipChange(examStudentLogDetailListBeanIPageAll);
            Map<Long, ExamStudentLogDetailListBean> examStudentLogDetailListBeanMap = examStudentLogDetailListBeanIPageAll.getRecords().stream()
                    .collect(Collectors.toMap(ExamStudentLogDetailListBean::getId, Function.identity(), (dto1, dto2) -> dto1));
            for (ExamStudentLogDetailListBean e : examStudentLogDetailListBeanIPage.getRecords()) {
                if (Objects.nonNull(examStudentLogDetailListBeanMap.containsKey(e.getId()))) {
                    e.setIpChange(examStudentLogDetailListBeanMap.get(e.getId()).getIpChange());
                }
            }
        }
        return examStudentLogDetailListBeanIPage;
    }

    /**
     * 在线巡考报表接口
     *
     * @param examId
     * @param userId
     * @return
     */
    @Override
    public List<InvigilateListPatrolReportBean> patrolReport(Long examId, Long userId) {
        TBUser tbUser = (TBUser) ServletUtil.getRequestAccount();
        return tOeExamRecordMapper.patrolReport(tbUser.getOrgId(), examId, userId);
    }

    /**
     * 考情监控-人数
     */
    @Override
    public ExaminationMonitorCountBean examinationMonitorCount() {
        TBUser tbUser = (TBUser) ServletUtil.getRequestAccount();
        ExaminationMonitorCountBean ret = null;
        if (Objects.isNull(tbUser.getOrgId())) {
            return ret;
        } else {
            TBOrg tbOrg = themisCacheService.addOrgCache(tbUser.getOrgId());
            ret = new ExaminationMonitorCountBean(tbOrg.getId(), tbOrg.getName(), tbOrg.getCode());
        }
        List<TEExam> teExamList = teExamService.list(new QueryWrapper<TEExam>().lambda().eq(TEExam::getOrgId, tbUser.getOrgId()));
        if (!CollectionUtils.isEmpty(teExamList)) {
            List<TEExamSummary> teExamSummaryAllList = new ArrayList<>();
            for (TEExam t : teExamList) {
                List<ExamListBean> examListBeanList = themisCacheService.getCurrentExamListCache(t.getId().toString());
                if (!CollectionUtils.isEmpty(examListBeanList)) {
                    for (ExamListBean e : examListBeanList) {
                        Set<String> roomCodeSet = new HashSet<>(Arrays.asList(e.getRoomCode().split(", ")));
                        for (String s : roomCodeSet) {
                            teExamSummaryAllList.addAll(themisCacheService.getExamSummaryCache(t.getId(), e.getExamActivityId(), s));
                        }
                    }
                }
            }
            Integer onlineCount = 0, waitingCount = 0, examingCount = 0, warnCount = 0;
            for (TEExamSummary t : teExamSummaryAllList) {
                onlineCount = onlineCount + t.getOnlineCount();
                waitingCount = waitingCount + t.getPrepareCount();
                examingCount = examingCount + t.getExamCount();
                warnCount = warnCount + t.getWarningCount();
            }
            // 在线人数
            ret.setOnlineCount(Long.parseLong(onlineCount.toString()));
            // 待考人数
            ret.setWaitingCount(Long.parseLong(waitingCount.toString()));
            // 考试人数
            ret.setExamingCount(Long.parseLong(examingCount.toString()));
            // 预警人数
            ret.setWarnCount(Long.parseLong(warnCount.toString()));
        }
//         通讯故障人数
//        ret.setExceptionCount(tOeExamRecordMapper.getExceptionCount(tbUser.getOrgId()));
//         机构在考人数
//        ret.setOrgExamingCount(tOeExamRecordMapper.getOrgExamingCount(tbUser.getOrgId()));
        //违纪人数
        ret.setBreachCount(tOeExamRecordMapper.getBreachCount(tbUser.getOrgId()));
        return ret;
    }

    /**
     * 考情监控-预警类型排行
     */
    @Override
    public List<ExaminationMonitorWarnDistributionBean> warnDistribution() {
        TBUser tbUser = (TBUser) ServletUtil.getRequestAccount();
        return tOeExamRecordMapper.getWarnDistribution(tbUser.getOrgId());
    }

    @Resource
    TBUserService tbUserService;

    /**
     * 考情监控-预警时间趋势
     */
    @Override
    public List<TimeScaleDataResult> warnTrend() {
        TBUser tbUser = (TBUser) ServletUtil.getRequestAccount();
//        TBUser tbUser = tbUserService.getById(321565832042266624L);//测试用
        SysConfig onlineWarnScaleSize = themisCacheService.addSysConfigCache(SystemConstant.ONLINE_WARN_SCALESIZE);
        Optional.ofNullable(onlineWarnScaleSize).orElseThrow(() -> new BusinessException("在线人数/预警时间趋势统计格数未配置"));

        SysConfig onlineWarnInterval = themisCacheService.addSysConfigCache(SystemConstant.ONLINE_WARN_INTERVAL);
        Optional.ofNullable(onlineWarnInterval).orElseThrow(() -> new BusinessException("在线人数/预警时间趋势统计间隔未配置"));

        int scaleSize = Integer.parseInt(onlineWarnScaleSize.getConfigValue()), interval = Integer.parseInt(onlineWarnInterval.getConfigValue());
//        scaleSize = 90;//测试用
        List<Integer> timeSize = new ArrayList<>(scaleSize);
        for (int i = interval; i <= scaleSize * interval; i = i + interval) {
            timeSize.add(i);
        }
        LocalDateTime now = LocalDateTime.now();
        Date date = Date.from(now.atZone(ZoneOffset.ofHours(8)).toInstant());
        LocalDateTime minusDays = now.minusDays(1);
        LocalDateTime minusMinutes = now.minusMinutes(scaleSize);

        String currentDate = DateUtil.format(date, Constants.DEFAULT_DATE_PATTERN);
//        currentDate = "2022-11-06 16:31:00";//测试用
        Map<String, String> map = this.getTimeScale(timeSize, currentDate);

        Long longtimestamp = now.toInstant(ZoneOffset.ofHours(8)).toEpochMilli();
        Long minusDayslongtimestamp = minusDays.toInstant(ZoneOffset.ofHours(8)).toEpochMilli();
        Long minusMinuteslongtimestamp = minusMinutes.toInstant(ZoneOffset.ofHours(8)).toEpochMilli();

        List<String> timeData = new ArrayList<>(map.values());
        List<TimeScaleDataResult> timeScaleDataResultList = tOeExamRecordMapper.getWarnTrend(tbUser.getOrgId(), timeData, longtimestamp, interval, minusMinuteslongtimestamp);
        List<TimeOnlineDataResult> timeOnlineDataResultList = tOeExamRecordMapper.getTimeOnlineData(tbUser.getOrgId(), timeData, longtimestamp, minusDayslongtimestamp);
        if (!CollectionUtils.isEmpty(timeOnlineDataResultList) && !CollectionUtils.isEmpty(timeScaleDataResultList)
                && timeOnlineDataResultList.size() == timeScaleDataResultList.size()) {
            for (int i = 0; i < timeOnlineDataResultList.size(); i++) {
                TimeOnlineDataResult t = timeOnlineDataResultList.get(i);
                int onlineCount = t.getOnlineCount() - t.getOfflineCount();
                onlineCount = onlineCount < 0 ? 0 : onlineCount;
                timeScaleDataResultList.get(i).setOnlineCount(onlineCount);
            }
        }
        return timeScaleDataResultList;
    }

    @Override
    public List<WarningNotifyBean> warnMsg() {
        TBUser tbUser = (TBUser) ServletUtil.getRequestAccount();
        return invigilateWarnInfoMapper.findLastMsg(6, tbUser.getOrgId());
    }

    /**
     * 考情监控-预警地区排行
     *
     * @return
     */
    @Override
    public List<ExaminationMonitorWarnRegionDistributionBean> warnRegionDistribution() {
        TBUser tbUser = (TBUser) ServletUtil.getRequestAccount();
        return tOeExamRecordMapper.getWarnRegionDistribution(tbUser.getOrgId());
    }

    /**
     * 考情监控-地图数据
     *
     * @return
     */
    @Override
    public List<ExaminationMonitorMapBean> map() {
        TBUser tbUser = (TBUser) ServletUtil.getRequestAccount();
        return tOeExamRecordMapper.getMap(tbUser.getOrgId());
    }

    /**
     * 获取时间尺度
     *
     * @param timeSize
     * @param currentDate
     * @return
     */
    @Override
    public Map<String, String> getTimeScale(List<Integer> timeSize, String currentDate) {
        return tOeExamRecordMapper.getTimeScale(timeSize, currentDate);
    }
}
