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

import java.util.ArrayList;
import java.util.List;

import javax.annotation.Resource;

import org.apache.commons.collections4.CollectionUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.multipart.MultipartFile;

import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.qmth.boot.core.concurrent.service.ConcurrentService;
import com.qmth.boot.core.exception.ParameterException;
import com.qmth.teachcloud.common.contant.SystemConstant;
import com.qmth.teachcloud.common.entity.SysUser;
import com.qmth.teachcloud.common.service.TeachcloudCommonService;
import com.qmth.teachcloud.mark.bean.answerbatch.*;
import com.qmth.teachcloud.mark.bean.scananswer.SheetUploadVo;
import com.qmth.teachcloud.mark.bean.scanpaper.PaperVo;
import com.qmth.teachcloud.mark.entity.*;
import com.qmth.teachcloud.mark.enums.BatchStatus;
import com.qmth.teachcloud.mark.enums.LockType;
import com.qmth.teachcloud.mark.mapper.ScanBatchMapper;
import com.qmth.teachcloud.mark.service.*;

/**
 * <p>
 * 服务实现类
 * </p>
 *
 * @author xf
 * @since 2023-09-22
 */
@Service
public class ScanBatchServiceImpl extends ServiceImpl<ScanBatchMapper, ScanBatch> implements ScanBatchService {
    @Autowired
    private MarkFileService markFileService;
    @Autowired
    private ConcurrentService concurrentService;
    @Autowired
    private MarkStudentService markStudentService;

    @Autowired
    private ScanPaperService scanPaperService;

    @Autowired
    private ScanPaperPageService scanPaperPageService;

    @Autowired
    private ScanBatchPaperService scanBatchPaperService;

    @Autowired
    private ScanAnswerCardService scanAnswerCardService;
    @Autowired
    private ScanFilePropertyService scanFilePropertyService;
    @Resource
    private TeachcloudCommonService teachcloudCommonService;

    @Transactional
    @Override
    public BatchCreateVo batchCreate(BatchCreateDomain domain, SysUser sysUser) {
        List<Rescan> rescan = new ArrayList<>();
        for (String studentCode : domain.getStudentCodes()) {
            MarkStudent student = markStudentService.findByExamIdAndCoursePaperIdAndStudentCode(domain.getExamId(),
                    domain.getCoursePaperId(), studentCode);
            if (student == null) {
                throw new ParameterException("未找到考生信息:" + studentCode);
            }
            Rescan rc = getRescan(student);
            if (rc != null) {
                rescan.add(rc);
            }
        }

        ScanBatch b = new ScanBatch();
        b.setExamId(domain.getExamId());
        b.setUserId(sysUser.getId());
        b.setCoursePaperId(domain.getCoursePaperId());
        b.setAssignedCount(0);
        b.setScanCount(0);
        b.setStatus(BatchStatus.INIT);
        this.save(b);

        BatchCreateVo vo = new BatchCreateVo();
        vo.setRescan(rescan);
        vo.setId(b.getId());
        vo.setCreateTime(b.getCreateTime());
        return vo;
    }

    private Rescan getRescan(MarkStudent student) {
        Rescan res = new Rescan();
        res.setStudentCode(student.getStudentCode());
        List<PaperVo> papers = scanPaperService.findStudentPaper(student.getId());
        List<Paper> resPapers = new ArrayList<>();
        res.setPapers(resPapers);
        if (CollectionUtils.isEmpty(papers)) {
            return null;
        }
        PaperVo first = papers.get(0);
        res.setBatchId(first.getBatchId());
        res.setUser(first.getUserName());
        res.setCreateTime(first.getCreateTime());
        for (PaperVo paper : papers) {
            Paper p = new Paper();
            p.setId(paper.getId());
            p.setNumber(paper.getNumber());
            p.setMismatch(paper.getMismatch());
            List<String> pages = new ArrayList<>();
            p.setPages(pages);
            List<ScanPaperPage> paperPages = scanPaperPageService.listByPaperId(paper.getId());
            if (CollectionUtils.isNotEmpty(paperPages)) {
                for (ScanPaperPage pp : paperPages) {
                    pages.add(teachcloudCommonService.filePreview(pp.getSheetPath()));
                }
            }
            resPapers.add(p);
        }
        return res;
    }

    @Transactional
    @Override
    public BatchFinishVo batchFinish(ScanBatch scanBatch) {
        scanBatch.setStatus(BatchStatus.FINISH);
        this.saveOrUpdate(scanBatch);
        BatchFinishVo vo = new BatchFinishVo();
        vo.setStatus(scanBatch.getStatus());
        vo.setUpdateTime(System.currentTimeMillis());
        return vo;
    }

    @Transactional
    @Override
    public AnswerSaveVo batchSave(AnswerDomain domain, ScanBatch scanBatch, SysUser user) {
        String studentCode = domain.getStudentCode();
        MarkStudent student = markStudentService.findByExamIdAndCoursePaperIdAndStudentCode(scanBatch.getExamId(), scanBatch.getCoursePaperId(), studentCode);
        if (student == null) {
            throw new ParameterException("未找到考生信息:" + studentCode);
        }
        ScanAnswerCard answerCard = scanAnswerCardService.findByExamAndNumber(scanBatch.getExamId(),
                domain.getCardNumber());
        if (answerCard == null) {
            throw new ParameterException("卡格式信息未找到");
        }
        List<ScanStudentPaper> studentPaperList = new ArrayList<>();
        for (AnswerPaper answerPaper : domain.getPapers()) {
            // 验证page数量
            answerPaper.answerCardValidate(answerCard);
            //验证强制输入必须为人工绑定
            if (answerPaper.getInvalid() && !answerPaper.getAssigned()) {
                throw new ParameterException("强制输入必须为人工绑定");
            }
            Integer paperNumber = answerPaper.getNumber();
            ScanPaper paper = findOrCreatePaper(scanBatch, student, paperNumber, user);
            // 设置paper属性
            paper.setExamId(scanBatch.getExamId());
            paper.setCardNumber(answerCard.getNumber());
            paper.setNumber(paperNumber);
            paper.setMismatch(false);
            paper.setQuestionFilled(false);
            paper.setAssigned(answerPaper.getAssigned());
            paper.setInvalid(answerPaper.getInvalid());
            // 保存paper与page到数据库
            scanPaperService.savePaperAndPages(paper, answerPaper.buildPageList());
            // 记录paper与batch关联关系
            scanBatchPaperService.update(scanBatch, paper, student.getId(), paperNumber);
            // 创建student与paper的关联关系
            studentPaperList.add(new ScanStudentPaper(student.getId(), paperNumber, paper.getId()));
        }
        // 更新批次统计数量
        updateAssignedCount(scanBatch.getId());
        updateScanCount(scanBatch.getId());
        //直接更新考生扫描状态
        concurrentService.getReadWriteLock(LockType.STUDENT + "-" + student.getId()).writeLock().lock();
        try {
            markStudentService.updateStudentAndPaper(user, student.getId(), studentPaperList);
        } finally {
            concurrentService.getReadWriteLock(LockType.STUDENT + "-" + student.getId()).writeLock().unlock();
        }
        return AnswerSaveVo.create(findStudentCountByBatch(scanBatch.getId()));
    }

    @Override
    public Integer findStudentCountByBatch(Long batchId) {
        return baseMapper.findStudentCountByBatch(batchId);
    }

    @Transactional
    @Override
    public void updateAssignedCount(Long id) {
        baseMapper.updateAssignedCount(id);
    }

    @Transactional
    @Override
    public void updateScanCount(Long id) {
        baseMapper.updateScanCount(id);
    }

    private ScanPaper findOrCreatePaper(ScanBatch batch, MarkStudent student, Integer paperNumber, SysUser user) {
        ScanPaper paper = null;
        // 尝试重用已有paper对象
        ScanBatchPaper batchPaper = scanBatchPaperService.findByBatchIdAndStudentIdAndPaperNumber(batch.getId(),
                student.getId(), paperNumber);
        if (batchPaper != null) {
            paper = scanPaperService.getById(batchPaper.getPaperId());
        }
        // 构造全新paper对象
        if (paper == null) {
            paper = new ScanPaper();
            paper.setId(SystemConstant.getDbUuid());
            paper.setCreateTime(System.currentTimeMillis());
            paper.setCreatorId(user.getId());
        }
        return paper;
    }



    @Transactional
    @Override
    public SheetUploadVo sheetUpload(ScanBatch batch, String coursePaperId, String studentCode, Integer paperNumber,
                                     Integer pageIndex, MultipartFile file, String md5) {
        try {
            String path = markFileService.uploadSheet(file.getInputStream(), md5, batch.getExamId(), batch.getId(), coursePaperId,
                    studentCode, paperNumber, pageIndex);
            scanFilePropertyService.save(batch.getExamId(), path, md5, file.getSize());
            return SheetUploadVo.create(path);
        } catch (Exception e) {
            log.error("原图上传失败，batchId=" + batch + ", coursePaperId=" + coursePaperId + ",studentCode=" + studentCode
                    + ", paperNumber=" + paperNumber + ", pageIndex=" + pageIndex, e);
            throw new ParameterException("原图上传失败", e);
        }
    }
}
