package com.qmth.teachcloud.mark.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.extension.service.impl.ServiceImpl;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.qmth.boot.core.exception.ParameterException;
import com.qmth.teachcloud.common.bean.dto.DataPermissionRule;
import com.qmth.teachcloud.common.bean.marking.CardJpgResult;
import com.qmth.teachcloud.common.bean.marking.scanAnswerCard.AnswerCard;
import com.qmth.teachcloud.common.bean.marking.scanAnswerCard.AnswerCardPage;
import com.qmth.teachcloud.common.bean.vo.FilePathVo;
import com.qmth.teachcloud.common.contant.SystemConstant;
import com.qmth.teachcloud.common.entity.SysUser;
import com.qmth.teachcloud.common.enums.mark.MarkPaperStatus;
import com.qmth.teachcloud.common.service.BasicRoleDataPermissionService;
import com.qmth.teachcloud.common.service.TeachcloudCommonService;
import com.qmth.teachcloud.common.util.HttpUtil;
import com.qmth.teachcloud.common.util.ServletUtil;
import com.qmth.teachcloud.mark.bean.UriVo;
import com.qmth.teachcloud.mark.bean.answercard.AnswerCardSaveDomain;
import com.qmth.teachcloud.mark.bean.answercard.AnswerCardVo;
import com.qmth.teachcloud.mark.bean.answercard.CardFile;
import com.qmth.teachcloud.mark.entity.MarkPaper;
import com.qmth.teachcloud.mark.entity.ScanAnswerCard;
import com.qmth.teachcloud.mark.enums.CardSource;
import com.qmth.teachcloud.mark.mapper.ScanAnswerCardMapper;
import com.qmth.teachcloud.mark.service.*;
import com.qmth.teachcloud.mark.utils.FileStoreUtils;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
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 javax.annotation.Resource;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;

/**
 * <p>
 * 题卡卡格式表 服务实现类
 * </p>
 *
 * @author xf
 * @since 2023-09-22
 */
@Service
public class ScanAnswerCardServiceImpl extends ServiceImpl<ScanAnswerCardMapper, ScanAnswerCard>
        implements ScanAnswerCardService {

    @Autowired
    private MarkPaperService markPaperService;
    @Autowired
    private ScanPaperService scanPaperService;
    @Resource
    private MarkFileService markFileService;
    @Resource
    private MarkStudentService markStudentService;
    @Resource
    private BasicRoleDataPermissionService basicRoleDataPermissionService;
    @Resource
    private TeachcloudCommonService teachcloudCommonService;
    @Resource
    private FileStoreUtils fileStoreUtils;

    @Override
    public ScanAnswerCard findByExamAndNumber(Long examId, Integer cardNumber) {
        if (examId == null) {
            throw new ParameterException("examId不能为空");
        }
        if (cardNumber == null) {
            throw new ParameterException("cardNumber不能为空");
        }
        QueryWrapper<ScanAnswerCard> wrapper = new QueryWrapper<>();
        LambdaQueryWrapper<ScanAnswerCard> lw = wrapper.lambda();
        lw.eq(ScanAnswerCard::getExamId, examId);
        lw.eq(ScanAnswerCard::getNumber, cardNumber);
        return baseMapper.selectOne(wrapper);
    }

    @Override
    public List<AnswerCardVo> cardList(Long examId, String coursePaperId) {
        SysUser sysUser = (SysUser) ServletUtil.getRequestUser();
        DataPermissionRule dpr = basicRoleDataPermissionService.findDataPermission(sysUser.getSchoolId(), sysUser.getId(), ServletUtil.getRequest().getServletPath());
        List<AnswerCardVo> answerCardVos = baseMapper.cardList(examId, coursePaperId, MarkPaperStatus.FORMAL.name(), dpr);
        for (AnswerCardVo answerCardVo : answerCardVos) {
            answerCardVo.setCanAdapte(scanPaperService.getCountByExamAndCardNumber(examId, answerCardVo.getNumber()) == 0);
            answerCardVo.setUri(fileStoreUtils.filePreview(answerCardVo.getUri()));
            answerCardVo.setAdapteUri(fileStoreUtils.filePreview(answerCardVo.getAdapteUri()));
        }
        return answerCardVos;
    }

    @Transactional
    @Override
    public ScanAnswerCard cardSave(AnswerCardSaveDomain domain) {
        boolean singlePage = false;
        MarkPaper mp = markPaperService.getByExamIdAndCoursePaperId(domain.getExamId(), domain.getCoursePaperId());
        if (MarkPaperStatus.FINISH.equals(mp.getStatus())) {
            throw new ParameterException("阅卷已结束");
        }

        ScanAnswerCard card;
        if (domain.getNumber() != null) {
            card = findByExamAndNumber(domain.getExamId(), domain.getNumber());
            if (card == null) {
                throw new ParameterException("未找到卡格式信息");
            }
            if (CardSource.WEB.equals(card.getSource())) {
                throw new ParameterException("电子卡格式，不能修改");
            }
            int studentCount = scanPaperService.getCountByExamAndCardNumber(domain.getExamId(), domain.getNumber());
            if (studentCount > 0) {
                throw new ParameterException("卡格式已被使用，不能修改");
            }
        } else {
            card = new ScanAnswerCard();
            card.setId(SystemConstant.getDbUuid());
            card.setExamId(domain.getExamId());
            card.setPaperNumber(mp.getPaperNumber());
            card.setPaperType(mp.getPaperType());
            card.setCoursePaperId(domain.getCoursePaperId());
            card.setPaperCount(domain.getPaperCount());
            card.setSinglePage(singlePage);
            card.setRemark(domain.getRemark());
            card.setDpi(domain.getDpi());
            card.setSource(CardSource.CLIENT);
            card.setNumber(findMaxCardNumberByExamId(domain.getExamId()) + 1);
            card.setNeedAdapte(false);
        }

//        CardFile cardFile;
//        byte[] fileData;
//        String sliceConfig;
//        try {
//            fileData = domain.getFile().getBytes();
//            // 解析卡格式文件
//            cardFile = parseCardFile(fileData);
//            if (singlePage && domain.getPaperCount() != cardFile.getPages().size()) {
//                throw new ParameterException("卡格式数量不一致");
//            }
//            if (!singlePage && domain.getPaperCount() * 2 != cardFile.getPages().size()) {
//                throw new ParameterException("卡格式数量不一致");
//            }
////            // 提取裁切坐标
//            sliceConfig = cardFile.getSliceConfig().toString();
//        } catch (IOException e) {
//            throw new ParameterException("文件解析失败", e);
//        }
        String filePath = null;
        try {
            filePath = markFileService.uploadAnswerCard(domain.getFile().getInputStream(), domain.getMd5(), domain.getExamId(), domain.getCoursePaperId(), card.getNumber());
        } catch (IOException e) {
            throw new ParameterException("文件上传失败", e);
        }
//        card.setSliceConfig(sliceConfig);
        card.setMd5(domain.getMd5());
        card.setUri(filePath);
        card.setAdapteMd5(domain.getMd5());
        card.setAdapteUri(filePath);
        this.saveOrUpdate(card);
        return card;
    }

    /**
     * 解析卡格式文件中的裁切图坐标，用于云阅卷同步
     *
     * @param data
     */
    private CardFile parseCardFile(byte[] data) throws IOException {
        ObjectMapper objectMapper = new ObjectMapper();
        return objectMapper.readValue(data, CardFile.class);
    }

    @Override
    public Integer findMaxCardNumberByExamId(Long examId) {
        int number = 0;
        QueryWrapper<ScanAnswerCard> queryWrapper = new QueryWrapper<>();
        queryWrapper.lambda().eq(ScanAnswerCard::getExamId, examId);
        List<ScanAnswerCard> list = this.list(queryWrapper);
        for (ScanAnswerCard card : list) {
            if (number < card.getNumber()) {
                number = card.getNumber();
            }
        }
        return number;
    }

    @Transactional
    @Override
    public void cardDelete(ScanAnswerCard card) {
        int studentCount = scanPaperService.getCountByExamAndCardNumber(card.getExamId(), card.getNumber());
        if (studentCount != 0) {
            throw new ParameterException("卡格式已被使用，无法删除");
        }
        UpdateWrapper<ScanAnswerCard> updateWrapper = new UpdateWrapper<>();
        updateWrapper.lambda().eq(ScanAnswerCard::getExamId, card.getExamId());
        updateWrapper.lambda().eq(ScanAnswerCard::getNumber, card.getNumber());
        int count = this.baseMapper.delete(updateWrapper);
        if (count == 0) {
            throw new ParameterException("未找到卡格式");
        }
    }

    @Transactional
    @Override
    public UriVo adapteUpload(Long examId, String coursePaperId, Integer cardNumber, String md5, Integer dpi,
                              MultipartFile file, String remark) {
        MarkPaper mp = markPaperService.getByExamIdAndCoursePaperId(examId, coursePaperId);
        if (MarkPaperStatus.FINISH.equals(mp.getStatus())) {
            throw new ParameterException("阅卷已结束");
        }
        ScanAnswerCard card = findByExamAndNumber(examId, cardNumber);
        if (card == null) {
            throw new ParameterException("未找到卡格式信息");
        }
        if (!card.getNeedAdapte() || CardSource.CLIENT.equals(card.getSource())) {
            throw new ParameterException("卡格式无需适配");
        }
        int studentCount = scanPaperService.getCountByExamAndCardNumber(examId, cardNumber);
        if (studentCount > 0) {
            throw new ParameterException("卡格式已被使用，无法适配");
        }
        String filePath;
        try {
            filePath = markFileService.uploadAdapteFile(file.getInputStream(), md5, examId, coursePaperId, cardNumber);
        } catch (IOException e) {
            throw new ParameterException("文件上传失败", e);
        }
        card.setDpi(dpi);
        card.setAdapteMd5(md5);
        card.setAdapteUri(filePath);
        this.updateById(card);
        UriVo vo = new UriVo();
        vo.setUri(teachcloudCommonService.filePreview(filePath));
        return vo;
    }

    @Override
    public AnswerCardVo cardGet(Long examId, Integer number) {
        List<AnswerCardVo> list = baseMapper.cardGet(examId, number);
        if (CollectionUtils.isEmpty(list)) {
            throw new ParameterException("未找到卡格式信息");
        }
        AnswerCardVo answerCardVo = list.get(0);
        answerCardVo.setUri(fileStoreUtils.filePreview(answerCardVo.getUri()));
        answerCardVo.setAdapteUri(fileStoreUtils.filePreview(answerCardVo.getAdapteUri()));
        return answerCardVo;
    }

    @Override
    public ScanAnswerCard getByExamIdAndCoursePaperIdAndCardId(Long examId, String coursePaperId, Long cardId) {
        QueryWrapper<ScanAnswerCard> queryWrapper = new QueryWrapper<>();
        queryWrapper.lambda().eq(ScanAnswerCard::getExamId, examId)
                .eq(ScanAnswerCard::getCoursePaperId, coursePaperId)
                .eq(ScanAnswerCard::getCardId, cardId);
        return this.getOne(queryWrapper);
    }

    @Override
    public List<ScanAnswerCard> listByExamIdAndPaperNumber(Long examId, String paperNumber) {
        QueryWrapper<ScanAnswerCard> queryWrapper = new QueryWrapper<>();
        queryWrapper.lambda().eq(ScanAnswerCard::getExamId, examId)
                .eq(ScanAnswerCard::getPaperNumber, paperNumber);
        return this.list(queryWrapper);
    }

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

    @Override
    public List<CardJpgResult> listPageImage(Long examId, String paperNumber, String paperType) {
        List<CardJpgResult> cardJpgResultList = new ArrayList<>();
        Integer maxCardNumber = markStudentService.maxCardNumber(examId, paperNumber, paperType);
        if (maxCardNumber != null) {
            ScanAnswerCard scanAnswerCard = this.findByExamAndNumber(examId, maxCardNumber);
            if (scanAnswerCard != null && StringUtils.isNotBlank(scanAnswerCard.getAdapteUri())) {
                FilePathVo filePathVo = JSON.parseObject(scanAnswerCard.getAdapteUri(), FilePathVo.class);
                if (filePathVo != null && StringUtils.isNotBlank(filePathVo.getPath())) {
                    String url = fileStoreUtils.getPrivateUrl(filePathVo.getPath(), filePathVo.getUploadType().getFssType());
                    try {
                        String jsonContent = HttpUtil.get(url, null, null, null);
                        if (StringUtils.isNotBlank(jsonContent)) {
                            AnswerCard answerCard = JSON.parseObject(jsonContent, AnswerCard.class);
                            if (answerCard != null && CollectionUtils.isNotEmpty(answerCard.getPages())) {
                                int pageIndex = 1;
                                for (AnswerCardPage page : answerCard.getPages()) {
                                    if (page.getExchange() != null && StringUtils.isNotBlank(page.getExchange().getPageImage())) {
                                        String pageImage = page.getExchange().getPageImage().replaceAll("\\r\\n", "");
                                        cardJpgResultList.add(new CardJpgResult("page" + pageIndex, pageIndex, "data:image/png;base64," + pageImage));
                                    }
                                }
                            }
                        }
                    } catch (IOException e) {
                        return cardJpgResultList;
                    }
                }
            }
        }
        return cardJpgResultList;
    }

}
