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

import java.io.ByteArrayOutputStream;
import java.io.File;
import java.net.URLEncoder;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletResponse;

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 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.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.qmth.boot.core.exception.ParameterException;
import com.qmth.boot.tools.io.ZipWriter;
import com.qmth.teachcloud.common.bean.dto.DataPermissionRule;
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.FileUploadService;
import com.qmth.teachcloud.common.service.TeachcloudCommonService;
import com.qmth.teachcloud.common.util.ServletUtil;
import com.qmth.teachcloud.mark.bean.scananswer.SheetUploadVo;
import com.qmth.teachcloud.mark.bean.scanpackage.ScanPackageFindVo;
import com.qmth.teachcloud.mark.bean.scanpackage.ScanPackageQuery;
import com.qmth.teachcloud.mark.bean.scanpackage.ScanPackageVo;
import com.qmth.teachcloud.mark.entity.MarkPaperPackage;
import com.qmth.teachcloud.mark.entity.ScanPackage;
import com.qmth.teachcloud.mark.mapper.ScanPackageMapper;
import com.qmth.teachcloud.mark.service.*;

/**
 * <p>
 * 服务实现类
 * </p>
 *
 * @author xf
 * @since 2023-09-22
 */
@Service
public class ScanPackageServiceImpl extends ServiceImpl<ScanPackageMapper, ScanPackage> implements ScanPackageService {
    @Autowired
    private MarkFileService markFileService;
    @Autowired
    private ScanFilePropertyService scanFilePropertyService;
    @Autowired
    private MarkPaperService markPaperService;
    @Resource
    private MarkPaperPackageService markPaperPackageService;
    @Resource
    private TeachcloudCommonService teachcloudCommonService;
    @Resource
    private BasicRoleDataPermissionService basicRoleDataPermissionService;
    @Resource
    private FileUploadService fileUploadService;

    @Override
    public int getCount(Long examId, String courseCode, String coursePaperId, MarkPaperStatus status, DataPermissionRule dpr) {
        return baseMapper.countPackageCode(examId, courseCode, coursePaperId, status.name(), dpr);
    }

    @Override
    public List<ScanPackage> listByExamIdAndCoursePaperIdAndPackageCode(Long examId, String coursePaperId,
                                                                        String packageCode) {
        QueryWrapper<ScanPackage> queryWrapper = new QueryWrapper<>();
        LambdaQueryWrapper<ScanPackage> lambdaQueryWrapper = queryWrapper.lambda();
        lambdaQueryWrapper.eq(ScanPackage::getExamId, examId).eq(ScanPackage::getCoursePaperId, coursePaperId);
        if (StringUtils.isNotBlank(packageCode)) {
            lambdaQueryWrapper.eq(ScanPackage::getPackageCode, packageCode).orderByAsc(ScanPackage::getPackageCode);
        }
        lambdaQueryWrapper.orderByAsc(ScanPackage::getPackageNo);
        return this.list(queryWrapper);
    }

    @Transactional
    @Override
    public SheetUploadVo imageUpload(Long examId, String packageCode, Integer packageNo, MultipartFile file,
                                     String md5) {
        SheetUploadVo vo = null;
        List<MarkPaperPackage> mps = markPaperPackageService.listByExamIdAndPackageCode(examId, packageCode);
        if (CollectionUtils.isEmpty(mps)) {
            throw new ParameterException("未找到科目信息");
        }
        for (MarkPaperPackage mp : mps) {
            String coursePaperId = mp.getCoursePaperId();
            try {
                String path = markFileService.uploadPackage(file.getInputStream(), md5, examId, coursePaperId, packageCode,
                        packageNo);
                if (vo == null) {
                    vo = SheetUploadVo.create(path);
                }
                ScanPackage sp = getByExamIdAndCoursePaperIdAndPackageCodeAndPackageNo(examId, coursePaperId,
                        packageCode, packageNo);
                if (sp == null) {
                    sp = new ScanPackage();
                    sp.setId(SystemConstant.getDbUuid());
                    sp.setExamId(examId);
                    sp.setCoursePaperId(coursePaperId);
                    sp.setPackageCode(packageCode);
                    sp.setPackageNo(packageNo);
                    sp.setAssigned(false);
                }
                sp.setMd5(md5);
                sp.setPath(path);
                scanFilePropertyService.save(examId, path, md5, file.getSize());
                this.saveOrUpdate(sp);
            } catch (Exception e) {
                log.error("原图上传失败，examId=" + examId + ", coursePaperId=" + coursePaperId + ",packageCode=" + packageCode
                        + ", packageNo=" + packageNo, e);
                throw new ParameterException("扫描图上传失败", e);
            }
        }
        return vo;
    }

    private ScanPackage getByExamIdAndCoursePaperIdAndPackageCodeAndPackageNo(Long examId, String coursePaperId,
                                                                              String packageCode, Integer packageNo) {
        QueryWrapper<ScanPackage> wrapper = new QueryWrapper<>();
        LambdaQueryWrapper<ScanPackage> lw = wrapper.lambda();
        lw.eq(ScanPackage::getExamId, examId);
        lw.eq(ScanPackage::getCoursePaperId, coursePaperId);
        lw.eq(ScanPackage::getPackageCode, packageCode);
        lw.eq(ScanPackage::getPackageNo, packageNo);
        wrapper.last("LIMIT 1");
        return this.getOne(wrapper);
    }

    private List<ScanPackage> getByExamIdAndCoursePaperId(Long examId, String coursePaperId) {
        QueryWrapper<ScanPackage> wrapper = new QueryWrapper<>();
        LambdaQueryWrapper<ScanPackage> lw = wrapper.lambda();
        lw.eq(ScanPackage::getExamId, examId);
        if (StringUtils.isNotBlank(coursePaperId)) {
            lw.eq(ScanPackage::getCoursePaperId, coursePaperId);
        }
        lw.orderByAsc(ScanPackage::getPackageNo);
        return this.list(wrapper);
    }

    @Override
    public IPage<ScanPackageVo> imagePage(ScanPackageQuery query) {
        SysUser sysUser = (SysUser) ServletUtil.getRequestUser();
        DataPermissionRule dpr = basicRoleDataPermissionService.findDataPermission(sysUser.getSchoolId(), sysUser.getId(), ServletUtil.getRequest().getServletPath());
        IPage<ScanPackageVo> iPage = this.baseMapper.page(new Page<>(query.getPageNumber(), query.getPageSize()), query, MarkPaperStatus.FORMAL.name(), dpr);
        if (CollectionUtils.isNotEmpty(iPage.getRecords())) {
            List<ScanPackage> sps = getByExamIdAndCoursePaperId(query.getExamId(), query.getCoursePaperId());
            if (CollectionUtils.isNotEmpty(sps)) {
                Map<String, List<String>> map = new HashMap<>();
                for (ScanPackage sp : sps) {
                    List<String> tem = map.get(sp.getPackageCode());
                    if (tem == null) {
                        tem = new ArrayList<>();
                        map.put(sp.getPackageCode(), tem);
                    }
                    tem.add(sp.getPath());
                }
                for (ScanPackageVo vo : iPage.getRecords()) {
                    for (String packageCode : vo.getPackageCode().split(",")) {
                        if (!map.containsKey(packageCode)) {
                            continue;
                        }
                        List<String> pages = map.get(packageCode);
                        pages = pages.stream().map(m -> teachcloudCommonService.filePreview(m)).collect(Collectors.toList());
                        vo.setPages(pages);
                        vo.setPagesCount(pages.size());
                    }

                }
            }
        }
        return iPage;
    }

    @Override
    public ScanPackageFindVo find(Long examId, String packageCode) {
        List<MarkPaperPackage> markPaperPackageList = markPaperPackageService.listByExamIdAndPackageCode(examId, packageCode);
        ScanPackageFindVo scanPackageFindVo = new ScanPackageFindVo();
        if (CollectionUtils.isNotEmpty(markPaperPackageList)) {
            scanPackageFindVo.setExamId(examId);
            scanPackageFindVo.setPackageCode(packageCode);
        }
        return scanPackageFindVo;
    }

    @Override
    public List<String> imageGet(Long examId, String coursePaperId, String packageCode) {
        List<String> ret = new ArrayList<>();
        QueryWrapper<ScanPackage> wrapper = new QueryWrapper<>();
        LambdaQueryWrapper<ScanPackage> lw = wrapper.lambda();
        lw.eq(ScanPackage::getExamId, examId);
        lw.eq(ScanPackage::getCoursePaperId, coursePaperId);
        lw.eq(ScanPackage::getPackageCode, packageCode);
        lw.orderByAsc(ScanPackage::getPackageNo);
        List<ScanPackage> list = this.list(wrapper);
        if (CollectionUtils.isNotEmpty(list)) {
            ret = list.stream().map(e -> teachcloudCommonService.filePreview(e.getPath())).collect(Collectors.toList());
        }
        return ret;
    }

    @Override
    public void export(Long examId, String coursePaperId, HttpServletResponse response) {
        QueryWrapper<ScanPackage> wrapper = new QueryWrapper<>();
        LambdaQueryWrapper<ScanPackage> lw = wrapper.lambda();
        lw.eq(ScanPackage::getExamId, examId);
        lw.eq(ScanPackage::getCoursePaperId, coursePaperId);
        lw.orderByAsc(ScanPackage::getPackageNo);
        List<ScanPackage> list = this.list(wrapper);
        if (CollectionUtils.isNotEmpty(list)) {
            try {
                response.setHeader("Content-Disposition", "attachment; filename=" + URLEncoder.encode("签到表.zip","UTF-8"));
                ZipWriter writer = ZipWriter.create(response.getOutputStream());
                ByteArrayOutputStream os = new ByteArrayOutputStream();
                for (ScanPackage s: list) {
                    FilePathVo filePathVo = JSON.parseObject(s.getPath(), FilePathVo.class);
                    File file =  fileUploadService.downloadFile(s.getPath(),filePathVo.getPath());
                    writer.write(file, file.getName());
                    file.delete();
                }
                writer.close();
            }catch (Exception e){
                e.printStackTrace();
                throw new ParameterException("文件下载失败", e);
            }
        }
    }
}
