package com.qmth.paper.library.business.service.impl;

import com.alibaba.fastjson.JSON;
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.paper.library.business.bean.result.PaperScanTaskDetailResult;
import com.qmth.paper.library.business.bean.result.PaperScanTaskResult;
import com.qmth.paper.library.business.bean.vo.FilePathVo;
import com.qmth.paper.library.business.entity.ExamCourse;
import com.qmth.paper.library.business.entity.PaperLibrary;
import com.qmth.paper.library.business.entity.PaperScanTask;
import com.qmth.paper.library.business.mapper.PaperScanTaskMapper;
import com.qmth.paper.library.business.service.*;
import com.qmth.paper.library.common.entity.*;
import com.qmth.paper.library.common.enums.ExceptionResultEnum;
import com.qmth.paper.library.common.enums.RecognitionTypeEnum;
import com.qmth.paper.library.common.enums.StoreTypeEnum;
import com.qmth.paper.library.common.enums.UploadFileEnum;
import com.qmth.paper.library.common.lock.LockService;
import com.qmth.paper.library.common.lock.LockType;
import com.qmth.paper.library.common.service.BasicSchoolService;
import com.qmth.paper.library.common.service.BasicSemesterService;
import com.qmth.paper.library.common.util.FileStoreUtil;
import com.qmth.paper.library.common.util.ServletUtil;
import org.apache.commons.collections4.CollectionUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.util.*;
import java.util.stream.Collectors;

/**
 * <p>
 * 扫描任务表 服务实现类
 * </p>
 */
@Service
public class PaperScanTaskServiceImpl extends ServiceImpl<PaperScanTaskMapper, PaperScanTask> implements PaperScanTaskService {
    @Resource
    private BasicSemesterService basicSemesterService;
    @Resource
    private BasicExamService basicExamService;
    @Resource
    private BasicSchoolService basicSchoolService;
    @Resource
    private FileStoreUtil fileStoreUtil;
    @Resource
    private PaperLibraryCommonService paperLibraryCommonService;
    @Resource
    private PaperLibraryService paperLibraryService;
    @Resource
    private PaperLibraryOtherService paperLibraryOtherService;
    @Resource
    private ExamStudentService examStudentService;
    @Resource
    private ExamCourseService examCourseService;
    @Resource
    private LockService lockService;

    @Override
    public IPage<PaperScanTaskResult> paperScanTaskPage(Long examId, String courseCode, int pageNumber, int pageSize) {
        return this.baseMapper.findPaperScanTaskPage(new Page<>(pageNumber, pageSize), examId, courseCode);
    }

    @Override
    public IPage<PaperScanTaskDetailResult> findPaperScanTaskDetailPageByScanTaskId(Long paperScanTaskId, int pageNumber, int pageSize) {
        return this.baseMapper.findPaperScanTaskDetailPageByScanTaskId(new Page<>(pageNumber, pageSize), paperScanTaskId);
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public void clearScanData(Long paperScanTaskId) {
        SysUser sysUser = (SysUser) ServletUtil.getRequestUser();
        // 扫描任务校验
        PaperScanTask paperScanTask = this.getById(paperScanTaskId);
        if (Objects.isNull(paperScanTask)) {
            throw ExceptionResultEnum.ERROR.exception("扫描任务不存在");
        }
        // 要删除的图片数据集合
        List<PaperLibrary> paperLibraryList = paperLibraryService.list(new QueryWrapper<PaperLibrary>().lambda().eq(PaperLibrary::getPaperScanTaskId, paperScanTaskId));
        Set<Long> studentIds = paperLibraryList.stream().filter(m -> m.getStudentId() != null).map(PaperLibrary::getStudentId).collect(Collectors.toSet());
        // 重置考生绑定数量为0
        if (CollectionUtils.isNotEmpty(studentIds)) {
            UpdateWrapper<ExamStudent> updateWrapper = new UpdateWrapper<>();
            updateWrapper.lambda().set(ExamStudent::getBindCount, 0).in(ExamStudent::getId, studentIds);
            examStudentService.update(updateWrapper);

            for (Long studentId : studentIds) {
                // 清除pdf文件记录
                examStudentService.clearPdfFilePath(studentId);
            }
        }
        // 删除该任务扫描的的数据
        paperLibraryService.removeByPaperScanTaskId(paperScanTaskId);
        // 删除任务扫描的其它文件
        paperLibraryOtherService.removeByPaperScanTaskId(paperScanTaskId);

        // 重置扫描数量为0
        paperScanTask.setScanCount(0);
        paperScanTask.setScanStudentCount(0);
        paperScanTask.updateInfo(sysUser.getId());
        this.updateById(paperScanTask);

        // 删除所有扫描文件
        try {
            BasicSchool basicSchool = basicSchoolService.getById(paperScanTask.getSchoolId());
            BasicExam basicExam = basicExamService.getById(paperScanTask.getExamId());
            BasicSemester basicSemester = basicSemesterService.getById(basicExam.getSemesterId());
            String courseNameCode = String.format("%s(%s)", paperScanTask.getCourseName(), paperScanTask.getCourseCode());
            String rootPath = fileStoreUtil.buildPath(UploadFileEnum.IMAGE, false, basicSchool.getName(), basicSemester.getName(), basicExam.getName(), courseNameCode);
            fileStoreUtil.deleteFile(rootPath);
        } catch (Exception e) {
            log.error("删除文件失败" + e.getMessage());
        }

    }

    @Override
    public void addScanTask(Long examId, RecognitionTypeEnum recognitionType, StoreTypeEnum storeType, ExamStudent examStudent) {
        Long schoolId = Long.valueOf(ServletUtil.getRequestHeaderSchoolId().toString());
        ExamCourse examCourse = examCourseService.selectByMultiId(new ExamCourse(examId, examStudent.getCourseCode()));
        if (examCourse != null) {
            PaperScanTask paperScanTask = this.getByExamIdAndCourseCode(examId, examStudent.getCourseCode());
            if (paperScanTask == null) {
                String scanTaskName = String.format("%s（%s）", examCourse.getCourseName(), examCourse.getCourseCode());
                String scanTaskCode = paperLibraryCommonService.getScanTaskCode(schoolId);
                paperScanTask = new PaperScanTask(schoolId, examId, scanTaskCode, scanTaskName, examCourse.getCourseCode(), examCourse.getCourseName(), recognitionType, storeType, 1);
                this.save(paperScanTask);
            } else {
                this.updateStudentCount(paperScanTask);
            }
        }
    }

    @Override
    public PaperScanTask getByExamIdAndCourseCode(Long examId, String courseCode) {
        QueryWrapper<PaperScanTask> queryWrapper = new QueryWrapper<>();
        queryWrapper.lambda().eq(PaperScanTask::getExamId, examId)
                .eq(PaperScanTask::getCourseCode, courseCode);
        return this.getOne(queryWrapper);
    }

    @Override
    public void updateStudentCount(PaperScanTask paperScanTask) {
        int count = examStudentService.countByExamIdAndCourseCode(paperScanTask.getExamId(), paperScanTask.getCourseCode());
        UpdateWrapper<PaperScanTask> updateWrapper = new UpdateWrapper<>();
        updateWrapper.lambda().set(PaperScanTask::getStudentCount, count)
                .eq(PaperScanTask::getId, paperScanTask.getId());
        this.update(updateWrapper);
    }

    @Transactional
    @Override
    public void updatePaperScanTask(Long examId, RecognitionTypeEnum recognitionType, StoreTypeEnum storeType, List<ExamStudent> examStudentList, TBTask tbTask) {
        Map<String, String> stringMap = examStudentList.stream().collect(Collectors.toMap(ExamStudent::getCourseCode, ExamStudent::getCourseName, (oldValue, newValue) -> oldValue));
        List<ExamCourse> examCourses = new ArrayList<>();
        for (Map.Entry<String, String> entry : stringMap.entrySet()) {
            examCourses.add(new ExamCourse(examId, entry.getKey(), entry.getValue()));
        }
        examCourseService.saveOrUpdateBatchByMultiId(examCourses);

        List<PaperScanTask> paperScanTaskList = new ArrayList<>();
        for (ExamCourse examCourse : examCourses) {
            int studentCount = Math.toIntExact(examStudentList.stream().filter(m -> m.getCourseCode().equals(examCourse.getCourseCode())).count());
            PaperScanTask paperScanTask = this.getByExamIdAndCourseCode(examId, examCourse.getCourseCode());
            if (paperScanTask == null) {
                String scanTaskName = String.format("%s（%s）", examCourse.getCourseName(), examCourse.getCourseCode());
                String scanTaskCode = paperLibraryCommonService.getScanTaskCode(tbTask.getSchoolId());
                paperScanTask = new PaperScanTask(tbTask.getSchoolId(), examId, scanTaskCode, scanTaskName, examCourse.getCourseCode(), examCourse.getCourseName(), recognitionType, storeType, studentCount);
            } else {
                paperScanTask.setStudentCount(studentCount);
            }
            paperScanTaskList.add(paperScanTask);
        }
        this.saveOrUpdateBatch(paperScanTaskList);
    }

    @Override
    public List<PaperScanTask> listByExamId(Long examId) {
        QueryWrapper<PaperScanTask> queryWrapper = new QueryWrapper<>();
        queryWrapper.lambda().eq(PaperScanTask::getExamId, examId);
        return this.list(queryWrapper);
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public void clearSingleStudentData(Long paperScanTaskId, Long studentId) {
        SysUser sysUser = (SysUser) ServletUtil.getRequestUser();
        ExamStudent student = examStudentService.getById(studentId);
        if (Objects.isNull(student)) {
            throw ExceptionResultEnum.ERROR.exception("考生不存在");
        }

        //需要删除的图片集合
        LambdaQueryWrapper<PaperLibrary> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(PaperLibrary::getPaperScanTaskId, paperScanTaskId).eq(PaperLibrary::getStudentId, studentId);

        //更新任务的扫描考生数、扫描张数
        List<PaperLibrary> paperLibraryList = paperLibraryService.list(queryWrapper);
        if (CollectionUtils.isEmpty(paperLibraryList)) {
            return;
        }

        PaperScanTask task = this.getById(paperScanTaskId);
        if (!Objects.isNull(task)) {
            task.setScanCount(Math.max((task.getScanCount() - paperLibraryList.size()), 0));
            task.setScanStudentCount(Math.max(task.getScanStudentCount() - 1, 0));
            task.setUpdateId(sysUser.getId());
            task.setUpdateTime(System.currentTimeMillis());
            this.updateById(task);
        }

        //删除考生的扫描数据
        paperLibraryService.remove(queryWrapper);

        //重置考生的扫描张数
        examStudentService.updateBindCount(studentId);

        //删除考生的图片数据
        for (PaperLibrary paperLibrary : paperLibraryList) {
            try {
                List<FilePathVo> filePathVoList = JSON.parseArray(paperLibrary.getPath(), FilePathVo.class);
                for (FilePathVo filePathVo : filePathVoList) {
                    fileStoreUtil.deleteFile(filePathVo.getPath());
                }
            } catch (Exception e) {
                log.error("文件删除失败" + e.getMessage());
            }
        }

        // 清除pdf文件记录
        examStudentService.clearPdfFilePath(studentId);
    }

    @Override
    public void updateScanCount(Long paperScanTaskId) {
        try {
            lockService.waitlock(LockType.UPDATE_SCAN_PAPER_COUNT, paperScanTaskId);
          /*  // 统计扫描张数
            int scanCount = paperLibraryService.countScanCount(paperScanTaskId);
            // 统计扫描学生数
            int scanStudentCount = paperLibraryService.countScanStudentCount(paperScanTaskId);
            // 总扫描数
            UpdateWrapper<PaperScanTask> updateWrapper = new UpdateWrapper<>();
            updateWrapper.lambda().set(PaperScanTask::getScanStudentCount, scanStudentCount)
                    .set(PaperScanTask::getScanCount, scanCount)
                    .eq(PaperScanTask::getId, paperScanTaskId);
            this.update(updateWrapper);*/
            updateScanCountNoLock(paperScanTaskId);
            //            this.baseMapper.updateScanCount(paperScanTaskId);
        } finally {
            lockService.unlock(LockType.UPDATE_SCAN_PAPER_COUNT, paperScanTaskId);
        }
    }

    @Override
    public void updateScanCountNoLock(Long paperScanTaskId) {
        // 统计扫描张数
        int scanCount = paperLibraryService.countScanCount(paperScanTaskId);
        // 统计扫描学生数
        int scanStudentCount = paperLibraryService.countScanStudentCount(paperScanTaskId);
        // 总扫描数
        UpdateWrapper<PaperScanTask> updateWrapper = new UpdateWrapper<>();
        updateWrapper.lambda().set(PaperScanTask::getScanStudentCount, scanStudentCount)
                .set(PaperScanTask::getScanCount, scanCount)
                .eq(PaperScanTask::getId, paperScanTaskId);
        this.update(updateWrapper);
    }
}
