package com.qmth.teachcloud.mark.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.qmth.teachcloud.common.bean.dto.DataPermissionRule;
import com.qmth.teachcloud.common.entity.SysUser;
import com.qmth.teachcloud.common.enums.ExceptionResultEnum;
import com.qmth.teachcloud.common.service.BasicRoleDataPermissionService;
import com.qmth.teachcloud.common.util.ExcelUtil;
import com.qmth.teachcloud.common.util.ServletUtil;
import com.qmth.teachcloud.mark.dto.mark.manage.MarkManageDto;
import com.qmth.teachcloud.mark.dto.mark.manage.MarkerInfoDto;
import com.qmth.teachcloud.mark.entity.MarkGroup;
import com.qmth.teachcloud.mark.entity.MarkTask;
import com.qmth.teachcloud.mark.enums.MarkTaskStatus;
import com.qmth.teachcloud.mark.mapper.MarkTaskMapper;
import com.qmth.teachcloud.mark.service.*;
import com.qmth.teachcloud.mark.utils.Calculator;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletResponse;
import java.util.Arrays;
import java.util.List;

/**
 * <p>
 * 评卷任务表 服务实现类
 * </p>
 *
 * @author xf
 * @since 2023-09-22
 */
@Service
public class MarkTaskServiceImpl extends ServiceImpl<MarkTaskMapper, MarkTask> implements MarkTaskService {

    @Resource
    private MarkStudentService markStudentService;
    @Resource
    private MarkGroupService markGroupService;
    @Resource
    private MarkQuestionService markQuestionService;
    @Resource
    private BasicRoleDataPermissionService basicRoleDataPermissionService;

    @Override
    public IPage<MarkManageDto> listPaperManage(Long examId, String courseCode, String paperNumber, Boolean progressStatus, Integer pageNumber, Integer pageSize) {
        Page<MarkManageDto> page = new Page<>(pageNumber, pageSize);
        SysUser sysUser = (SysUser) ServletUtil.getRequestUser();
        DataPermissionRule dpr = basicRoleDataPermissionService.findDataPermission(sysUser.getSchoolId(), sysUser.getId(), ServletUtil.getRequest().getServletPath());
        IPage<MarkManageDto> markManageDtoIPage = this.baseMapper.listPaperManage(page, examId, courseCode, paperNumber, progressStatus, dpr);
        for (MarkManageDto record : markManageDtoIPage.getRecords()) {
//            int totalCount = markStudentService.countByExamIdAndPaperNumberAndMarkStatus(record.getExamId(), record.getPaperNumber(), null);
//            record.setTotalCount(totalCount);
//            int markedCount = markStudentService.countByExamIdAndPaperNumberAndMarkStatus(record.getExamId(), record.getPaperNumber(), SubjectiveStatus.MARKED);
//            record.setMarkedCount(markedCount);
            record.setStatusDisplay(record.getStatus() == null ? null : record.getStatus().getName());
            record.setOmrAbsentCount(markStudentService.countOmrAbsentStudent(record.getExamId(), record.getPaperNumber(), record.getPaperType(), false));
            record.setPercent(Calculator.divide2String(Calculator.multiply(record.getMarkedCount(), 100), Double.valueOf(record.getTotalCount()), 2));
        }
        return markManageDtoIPage;
    }

    @Override
    public void exportMarker(Long examId, String courseCode, String paperNumber, HttpServletResponse response) {
        List<MarkerInfoDto> markerInfoDtoList = this.baseMapper.listUserMarkedCount(examId, courseCode, paperNumber);
        for (MarkerInfoDto markerInfoDto : markerInfoDtoList) {
            MarkGroup markGroup = markGroupService.getByExamIdAndPaperNumberAndGroupNumber(examId, markerInfoDto.getPaperNumber(), markerInfoDto.getGroupNumber());
            markGroup.setQuestionList(markQuestionService.listQuestionByExamIdAndPaperNumberAndGroupNumber(examId, markerInfoDto.getPaperNumber(), markerInfoDto.getGroupNumber(), false));
            markerInfoDto.setGroupName(markGroup.getQuestionTitle());
            markerInfoDto.setTotalScore(markQuestionService.sumTotalScoreByGroupNumber(examId, markerInfoDto.getPaperNumber(), markerInfoDto.getGroupNumber()));
        }
        try {
            ExcelUtil.excelExport("评卷员工作量", MarkerInfoDto.class, markerInfoDtoList, response);
        } catch (Exception e) {
            throw ExceptionResultEnum.ERROR.exception("导出评卷员工作量失败");
        }
    }

    @Override
    public List<MarkTask> listByExamIdAndPaperNumberAndGroupNumberAndUserIdAndClassName(Long examId, String paperNumber, Integer groupNumber, Long userId, String className) {
        return this.baseMapper.listByExamIdAndPaperNumberAndGroupNumberAndUserIdAndClassName(examId, paperNumber, groupNumber, userId, className);
    }

    @Override
    public Integer markedCount(List<MarkTask> markTask) {
        if (CollectionUtils.isEmpty(markTask)) {
            return 0;
        }
        long count = markTask.stream().filter(m -> m.getStatus().equals(MarkTaskStatus.MARKED) || m.getStatus().equals(MarkTaskStatus.ARBITRATED) || m.getStatus().equals(MarkTaskStatus.WAIT_ARBITRATE)).count();
        return (int) count;
    }

    @Override
    public int countByExamIdAndPaperNumberAndGroupNumberAndUserId(Long examId, String paperNumber, Integer groupNumber, Long userId) {
        QueryWrapper<MarkTask> queryWrapper = new QueryWrapper<>();
        LambdaQueryWrapper<MarkTask> lambdaQueryWrapper = queryWrapper.lambda();
        lambdaQueryWrapper.eq(MarkTask::getExamId, examId)
                .eq(MarkTask::getPaperNumber, paperNumber)
                .eq(MarkTask::getGroupNumber, groupNumber);
        if (userId != null) {
            lambdaQueryWrapper.eq(MarkTask::getUserId, userId);
        }
        return this.count(queryWrapper);
    }

    @Override
    public List<MarkTask> listByExamIdAndPaperNumberAndGroupNumberAndUserIdAndStatusNotIn(Long examId, String paperNumber, Integer groupNumber, Long userId, List<MarkTaskStatus> statusList) {
        QueryWrapper<MarkTask> queryWrapper = new QueryWrapper<>();
        queryWrapper.lambda().eq(MarkTask::getExamId, examId)
                .eq(MarkTask::getPaperNumber, paperNumber)
                .eq(MarkTask::getGroupNumber, groupNumber)
                .eq(MarkTask::getUserId, userId)
                .notIn(MarkTask::getStatus, statusList);
        return this.list(queryWrapper);
    }

    @Override
    public boolean resetById(Long markTaskId, Long userId, Long rejecterId, Long date, MarkTaskStatus newStatus) {
        UpdateWrapper<MarkTask> updateWrapper = new UpdateWrapper<>();
        updateWrapper.lambda().set(MarkTask::getStatus, newStatus)
                .set(MarkTask::getUserId, userId)
                .set(MarkTask::getMarkerTime, null)
                .set(MarkTask::getMarkerScore, null)
                .set(MarkTask::getMarkerScoreList, null)
                .set(MarkTask::getMarkerSpent, null)
                .set(MarkTask::getHeaderId, rejecterId)
                .set(MarkTask::getHeaderTime, date)
                .set(MarkTask::getHeaderScore, null)
                .set(MarkTask::getHeaderScoreList, null)
                .eq(MarkTask::getId, markTaskId);
        return this.update(updateWrapper);
    }

    @Override
    public int countByExamIdAndPaperNumberAndGroupNumberAndStatusIn(Long examId, String paperNumber, Integer groupNumber, List<MarkTaskStatus> statusList) {
        QueryWrapper<MarkTask> queryWrapper = new QueryWrapper<>();
        queryWrapper.lambda().eq(MarkTask::getExamId, examId)
                .eq(MarkTask::getPaperNumber, paperNumber)
                .eq(MarkTask::getGroupNumber, groupNumber)
                .in(MarkTask::getStatus, statusList);
        return this.count(queryWrapper);
    }

    @Override
    public MarkTask getLastOneByUserIdAndStatus(Long examId, String paperNumber, Integer groupNumber, Long userId, MarkTaskStatus status) {
        return this.baseMapper.getLastOneByUserIdAndStatus(examId, paperNumber, groupNumber, userId, status.name());
    }

    @Override
    public List<MarkTask> listByExamIdAndPaperNumberAndGroupNumberAndStudentId(Long examId, String paperNumber, Integer groupNumber, Long studentId) {
        QueryWrapper<MarkTask> queryWrapper = new QueryWrapper<>();
        queryWrapper.lambda().eq(MarkTask::getExamId, examId)
                .eq(MarkTask::getPaperNumber, paperNumber)
                .eq(MarkTask::getGroupNumber, groupNumber)
                .eq(MarkTask::getStudentId, studentId);
        return this.list(queryWrapper);
    }

    @Override
    public List<MarkTask> listByStudentIdAndGroupNumber(Long studentId, Integer groupNumber) {
        QueryWrapper<MarkTask> queryWrapper = new QueryWrapper<>();
        queryWrapper.lambda().eq(MarkTask::getStudentId, studentId)
                .eq(MarkTask::getGroupNumber, groupNumber);
        return this.list(queryWrapper);
    }

    @Override
    public void updateHeaderResult(Long examId, String paperNumber, Integer groupNumber, Long studentId, Long updateUserId, Double totalScore, String scoreList, Long updateTime, MarkTaskStatus arbitrated) {
        UpdateWrapper<MarkTask> updateWrapper = new UpdateWrapper<>();
        updateWrapper.lambda().set(MarkTask::getHeaderId, updateUserId)
                .set(MarkTask::getHeaderScore, totalScore)
                .set(MarkTask::getHeaderScoreList, scoreList)
                .set(MarkTask::getHeaderTime, updateTime)
                .set(MarkTask::getStatus, arbitrated)
                .eq(MarkTask::getExamId, examId)
                .eq(MarkTask::getPaperNumber, paperNumber)
                .eq(MarkTask::getGroupNumber, groupNumber)
                .eq(MarkTask::getStudentId, studentId);
        this.update(updateWrapper);
    }

    @Override
    public void deleteByStudentId(Long studentId) {
        UpdateWrapper<MarkTask> updateWrapper = new UpdateWrapper<>();
        updateWrapper.lambda().eq(MarkTask::getStudentId, studentId);
        this.remove(updateWrapper);
    }

    @Override
    public int countByExamIdAndPaperNumberAndGroupNumber(Long examId, String paperNumber, Integer groupNumber) {
        QueryWrapper<MarkTask> queryWrapper = new QueryWrapper<>();
        queryWrapper.lambda().eq(MarkTask::getExamId, examId)
                .eq(MarkTask::getPaperNumber, paperNumber)
                .eq(MarkTask::getGroupNumber, groupNumber);
        return this.count(queryWrapper);
    }

    @Override
    public int countByExamIdAndPaperNumberAndGroupNumberAndUserIdAndAndClassNameStatusIn(Long examId, String paperNumber, Integer groupNumber, Long userId, List<String> className, MarkTaskStatus... status) {
        return this.baseMapper.countByExamIdAndPaperNumberAndGroupNumberAndUserIdAndAndClassNameStatusIn(examId, paperNumber, groupNumber, userId, className, status);
    }

    @Override
    public void deleteByExamIdAndPaperNumberAndGroupNumber(Long examId, String paperNumber, Integer groupNumber) {
        UpdateWrapper<MarkTask> updateWrapper = new UpdateWrapper<>();
        updateWrapper.lambda().eq(MarkTask::getExamId, examId)
                .eq(MarkTask::getPaperNumber, paperNumber)
                .eq(MarkTask::getGroupNumber, groupNumber);
        this.remove(updateWrapper);
    }

    @Override
    public IPage<MarkTask> listPageHistory(Page<MarkTask> page, Long userId, Long examId, String paperNumber,
                                           Integer groupNumber, String secretNumber, Double markerScore) {
        return this.baseMapper.listPageHistory(page, userId, examId, paperNumber, groupNumber, secretNumber, markerScore);
    }

    @Override
    public List<MarkTask> findUnMarked(Page<MarkTask> page, Long examId, String paperNumber, Integer groupNumber,
                                       Long userId) {
        return this.baseMapper.findUnMarked(page, examId, paperNumber, groupNumber, userId);
    }

    @Override
    public List<MarkTask> findUnMarkedFilterClass(Page<MarkTask> page, Long examId, String paperNumber,
                                                  Integer groupNumber, Long userId) {
        return this.baseMapper.findUnMarkedFilterClass(page, examId, paperNumber, groupNumber, userId);
    }

    @Override
    public int countByIdAndStatus(Long id, MarkTaskStatus status) {
        QueryWrapper<MarkTask> queryWrapper = new QueryWrapper<>();
        queryWrapper.lambda().eq(MarkTask::getId, id)
                .eq(MarkTask::getStatus, status);
        return this.count(queryWrapper);
    }

    @Override
    public List<MarkTask> findByStudentIdAndGroupNumberAndStatus(Long studentId, Integer groupNumber,
                                                                 MarkTaskStatus... status) {
        QueryWrapper<MarkTask> queryWrapper = new QueryWrapper<>();
        queryWrapper.lambda().eq(MarkTask::getStudentId, studentId)
                .eq(MarkTask::getGroupNumber, groupNumber)
                .in(MarkTask::getStatus, Arrays.asList(status));
        return this.list(queryWrapper);
    }

    @Override
    public boolean updateProblemResult(Long taskId, Long userId, Long now, int spent) {
        UpdateWrapper<MarkTask> updateWrapper = new UpdateWrapper<>();
        updateWrapper.lambda().eq(MarkTask::getId, taskId)
                .in(MarkTask::getStatus, Arrays.asList(MarkTaskStatus.WAITING, MarkTaskStatus.REJECTED, MarkTaskStatus.MARKED))
                .set(MarkTask::getStatus, MarkTaskStatus.PROBLEM)
                .set(MarkTask::getUserId, userId)
                .set(MarkTask::getMarkerScore, null)
                .set(MarkTask::getMarkerScoreList, null)
                .set(MarkTask::getMarkerTime, now)
                .set(MarkTask::getMarkerSpent, spent);
        return this.update(updateWrapper);
    }

    @Override
    public boolean updateStatusByStudentIdAndGroupNumber(Long studentId, Integer groupNumber, MarkTaskStatus status) {
        UpdateWrapper<MarkTask> updateWrapper = new UpdateWrapper<>();
        updateWrapper.lambda().eq(MarkTask::getStudentId, studentId)
                .eq(MarkTask::getGroupNumber, groupNumber)
                .set(MarkTask::getStatus, status);
        return this.update(updateWrapper);
    }

    @Override
    public int countByStudentIdAndMarkerIdAndIdNotEqual(Long studentId, Long examId, String paperNumber, Integer groupNumber, Long userId, Long taskId) {
        QueryWrapper<MarkTask> queryWrapper = new QueryWrapper<>();
        queryWrapper.lambda().eq(MarkTask::getStudentId, studentId)
                .eq(MarkTask::getExamId, examId)
                .eq(MarkTask::getPaperNumber, paperNumber)
                .eq(MarkTask::getGroupNumber, groupNumber)
                .eq(MarkTask::getUserId, userId)
                .ne(MarkTask::getId, taskId);
        return this.count(queryWrapper);
    }

    @Override
    public boolean updateMarkerResult(Long taskId, MarkTaskStatus status, Long userId, Double markerScore,
                                      String scoreList, Long now, int spent, MarkTaskStatus... inStatus) {
        UpdateWrapper<MarkTask> updateWrapper = new UpdateWrapper<>();
        updateWrapper.lambda().eq(MarkTask::getId, taskId)
                .in(MarkTask::getStatus, Arrays.asList(inStatus))
                .set(MarkTask::getStatus, status)
                .set(MarkTask::getUserId, userId)
                .set(MarkTask::getMarkerScore, markerScore)
                .set(MarkTask::getMarkerScoreList, scoreList)
                .set(MarkTask::getMarkerTime, now)
                .set(MarkTask::getMarkerSpent, spent);
        return this.update(updateWrapper);
    }

    @Override
    public int countByExamIdAndPaperNumberAndGroupNumberAndTaskNumber(Long examId, String paperNumber, Integer groupNumber, int taskNumber) {
        QueryWrapper<MarkTask> queryWrapper = new QueryWrapper<>();
        queryWrapper.lambda().eq(MarkTask::getExamId, examId)
                .eq(MarkTask::getPaperNumber, paperNumber)
                .eq(MarkTask::getGroupNumber, groupNumber)
                .eq(MarkTask::getTaskNumber, taskNumber);
        return this.count(queryWrapper);
    }
}
