package com.qmth.jkserver.controller.system;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.qmth.jkserver.constant.SpringContextHolder;
import com.qmth.jkserver.constant.SystemConstant;
import com.qmth.jkserver.core.exception.ApiException;
import com.qmth.jkserver.core.exception.JkServerException;
import com.qmth.jkserver.dao.ExamPlanDao;
import com.qmth.jkserver.dto.ExamPlanDto;
import com.qmth.jkserver.dto.result.ExamPlanAnaTaskResult;
import com.qmth.jkserver.enums.ExamStatus;
import com.qmth.jkserver.enums.ExamType;
import com.qmth.jkserver.enums.TaskResultEnum;
import com.qmth.jkserver.enums.TaskStatusEnum;
import com.qmth.jkserver.model.*;
import com.qmth.jkserver.service.*;
import com.qmth.jkserver.templete.execute.AsyncCloudMarkTempleteService;
import com.qmth.jkserver.util.FileStoreUtil;
import com.qmth.jkserver.util.ServletUtil;
import io.swagger.annotations.*;
import org.apache.commons.codec.digest.DigestUtils;
import org.apache.commons.io.IOUtils;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.springframework.context.annotation.Lazy;
import org.springframework.data.domain.PageImpl;
import org.springframework.data.domain.PageRequest;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;
import org.springframework.web.multipart.MultipartHttpServletRequest;
import org.springframework.web.multipart.commons.CommonsMultipartResolver;

import javax.annotation.Resource;
import javax.servlet.MultipartConfigElement;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.*;
import java.net.URLDecoder;
import java.util.*;

@Api(tags = "考务任务管理Controller")
@RestController
@RequestMapping("/" + SystemConstant.SYSTEM_EXAM_TASK)
public class ExamTaskController extends BaseSystemController {
    private static final Logger logger = org.slf4j.LoggerFactory.getLogger(ExamTaskController.class);

//    @Resource
//    MongoTemplate mongoTemplate;

    @Resource
    @Lazy
    ExamTaskService examTaskService;

    @Resource
    @Lazy
    JkExamPlanService examPlanService;

    @Resource
    @Lazy
    JointFlowSimulationService jointFlowSimulationService;

    @Resource
    AsyncCloudMarkTempleteService asyncCloudMarkTempleteService;

    @Resource
    ExamPlanDao examPlanDao;

    @Resource
    @Lazy
    KWService kwService;

    @ApiOperation(value = "考务任务管理查询接口")
    @RequestMapping(value = "/query", method = RequestMethod.POST)
    @ApiResponses({@ApiResponse(code = 200, message = "任务管理列表信息", response = ExamPlanDto.class)})
    public Object taskQuery(@ApiParam(value = "考试编码", required = false) @RequestParam(required = false) String examCode,
                            @ApiParam(value = "任务状态", required = false) @RequestParam(required = false) TaskStatusEnum status,
                            @ApiParam(value = "云阅卷同步数据结果", required = false) @RequestParam(required = false) TaskResultEnum result,
                            @ApiParam(value = "分页页码", required = true) @RequestParam int pageNo,
                            @ApiParam(value = "分页数", required = true) @RequestParam int pageSize, HttpServletRequest request) throws IOException {
//        Query query = new Query();
//        if (Objects.nonNull(examCode)) {
//            query.addCriteria(Criteria.where("examCode").is(examCode));
//        }
//        if (Objects.nonNull(status)) {
//            query.addCriteria(Criteria.where("exam_task.status").is(status.name()));
//        }
//        if (Objects.nonNull(result)) {
//            query.addCriteria(Criteria.where("exam_task.result").is(result.name()));
//        }
//        query.addCriteria(Criteria.where("examType").is(ExamType.NORMAL.name()));
//        query.addCriteria(Criteria.where("examStatus").is(ExamStatus.PUBLISHED.name()));
//        query.addCriteria(Criteria.where("enable").is(true));
//
//        pageNo = pageNo <= 0 ? 1 : pageNo;
//        query.with(new Sort(Sort.Direction.DESC, "createTime"));
//        long count = this.mongoTemplate.count(query, ExamPlan.class);
//        query.limit(pageSize);
//        query.skip((pageNo - 1) * pageSize);
//        List<ExamPlan> examPlanList = mongoTemplate.find(query, ExamPlan.class);
//        User user = super.getCachedUser(request);
        Long creatorId = null;
//        if (user != null && !user.getUserName().equals("super")) {
//            creatorId = user.getId();
//        }

        Long schoolId = (Long) ServletUtil.getRequestHeaderSchoolId();
        if (Objects.nonNull(schoolId) && schoolId.longValue() < 0) {
            schoolId = null;
        }
//        long count = examPlanDao.findByExamCodeAndExamTaskCount(examCode, Objects.nonNull(status) ? status.name() : null, Objects.nonNull(result) ? result.name() : null,
//                ExamType.NORMAL.name(), ExamStatus.PUBLISHED.name(), true, schoolId, creatorId);
        IPage<ExamPlanAnaTaskResult> examPlanIPage = examPlanDao.findByExamCodeAndExamTask(new com.baomidou.mybatisplus.extension.plugins.pagination.Page<>(pageNo, pageSize)
                , examCode, Objects.nonNull(status) ? status.name() : null, Objects.nonNull(result) ? result.name() : null,
                ExamType.NORMAL.name(), ExamStatus.PUBLISHED.name(), true, schoolId, creatorId);
        return new PageImpl<ExamPlanAnaTaskResult>(examPlanIPage.getRecords(), PageRequest.of(pageNo - 1, pageSize), examPlanIPage.getTotal());
    }

    @ApiOperation(value = "考务任务管理云阅卷同步接口")
    @RequestMapping(value = "/sync", method = RequestMethod.POST)
    @ApiResponses({@ApiResponse(code = 200, message = "任务管理云阅卷同步", response = Object.class)})
    public Object sync(@ApiParam(value = "考试编码", required = true) @RequestParam(required = true) String examCode) throws Exception {
        ExamPlan examPlan = examPlanService.findByExamCode(examCode);
        if (Objects.isNull(examPlan)) {
            throw new JkServerException("考试编码" + examCode + "的考试不存在");
        }
        Map<String, Object> map = new HashMap<>();
        Long schoolId = (Long) ServletUtil.getRequestHeaderSchoolId();
        if (Objects.nonNull(schoolId) && schoolId.longValue() == -1L) {
            throw new JkServerException("超级管理员不能推送");
        }
        if (Objects.nonNull(examPlan.getExamTaskId())) {
            ExamTask examTask = examTaskService.getById(examPlan.getExamTaskId());
            if (examTask.getStatus() == TaskStatusEnum.FINISH && Objects.nonNull(examTask.getResult()) && examTask.getResult() == TaskResultEnum.SUCCESS) {
                throw new JkServerException("考试编码" + examCode + "已经同步成功");
            }
            map.computeIfAbsent(SystemConstant.TASK, v -> examTask);
            map.computeIfAbsent(SystemConstant.USER, v -> super.getCachedUser(getRequest()));
        } else {
            map = examTaskService.saveExamTask(examCode, super.getCachedUser(getRequest()), false);
        }
        map.put(SystemConstant.SCHOOL_ID, schoolId);
        asyncCloudMarkTempleteService.cloudMarkTask(map, null);
        return true;
    }

//    @ApiOperation(value = "考务任务管理云阅卷key和secret绑定接口")
//    @RequestMapping(value = "/bind", method = RequestMethod.POST)
//    @ApiResponses({@ApiResponse(code = 200, message = "考务任务管理云阅卷key和secret绑定", response = Object.class)})
//    public Object bind(@ApiParam(value = "考试编码", required = true) @RequestParam(required = true) String examCode,
//                       @ApiParam(value = "考试key", required = true) @RequestParam(required = true) String accessKey,
//                       @ApiParam(value = "考试secret", required = true) @RequestParam(required = true) String accessSecret) throws IOException {
//        ExamPlan examPlan = examPlanService.findByExamCode(examCode);
//        if (Objects.isNull(examPlan)) {
//            throw new JkServerException("考试编码" + examCode + "的考试不存在");
//        }
//        examPlan.updateKeyAndSecret(accessKey, accessSecret);
////        mongoTemplate.save(examPlan);
//        examPlanService.saveOrUpdate(examPlan);
//        return true;
//    }

    @ApiOperation(value = "清除考试同步任务数据接口")
    @RequestMapping(value = "/clean", method = RequestMethod.POST)
    @ApiResponses({@ApiResponse(code = 200, message = "清除考试同步任务数据接口", response = Object.class)})
    @Transactional(rollbackFor = Exception.class)
    public Object clean(@ApiParam(value = "考试编码", required = true) @RequestParam(required = true) String examCode) {
        ExamPlan examPlan = examPlanService.findByExamCode(examCode);
        if (Objects.isNull(examPlan)) {
            throw new JkServerException("考试编码" + examCode + "的考试不存在");
        }
        jointFlowSimulationService.cleanExamDataByExamCode(examCode);
        return true;
    }

    @ApiOperation(value = "考务任务管理上传考试试卷答案接口")
    @RequestMapping(value = "/{examCode}/{examType}", method = RequestMethod.POST)
    @ResponseBody
    public Object uploadPaperAnswer(HttpServletRequest request, HttpServletResponse response,
                                    @PathVariable(value = "examCode") String examCode,
                                    @PathVariable(value = "examType") ExamType examType)
            throws Exception {
        FileStoreUtil fileStoreConfig = SpringContextHolder.getBean(FileStoreUtil.class);
        AttachmentService attachmentService = SpringContextHolder.getBean(AttachmentService.class);
        JkExamPlanService examPlanService = SpringContextHolder.getBean(JkExamPlanService.class);
        CommonsMultipartResolver multipartResolver = new CommonsMultipartResolver(
                request.getSession().getServletContext());
        MultipartConfigElement multipartConfigElement = SpringContextHolder.getBean(MultipartConfigElement.class);
        logger.info("-------multipartConfigElement fileSize:" + multipartConfigElement.getMaxFileSize());
        logger.info("-------multipartConfigElement fileRequestSize:" + multipartConfigElement.getMaxRequestSize());
        multipartResolver.setMaxUploadSizePerFile(multipartConfigElement.getMaxFileSize());
        multipartResolver.setMaxUploadSize(multipartConfigElement.getMaxRequestSize());
        List<Attachment> results = new ArrayList<>();
        InputStream inputStream = null;
        OutputStream outputStream = null;
        String md5;
        try {
            if (multipartResolver.isMultipart(request)) {
                MultipartHttpServletRequest multiRequest = (MultipartHttpServletRequest) request;
                examCode = StringUtils.isEmpty(examCode) ? multiRequest.getHeader("examCode") : examCode;
                if (StringUtils.isEmpty(examCode)) {
                    throw ApiException.EXAM_CODE_INVALID;
                }
                ExamCode checkExamCode = examPlanService.findExamCode(examCode);
                ExamPlan examPlan = examPlanService.findByExamCode(examCode);
                if (checkExamCode != null && checkExamCode.getUsed() && examPlan == null) {
                    throw ApiException.EXAM_CODE_INVALID;
                }
                if (checkExamCode.getUsed() && !examPlan.getEnable()) {
                    throw ApiException.EXAM_PLAN_DISABLED;
                }
                md5 = multiRequest.getHeader("md5");
                String fileName = multiRequest.getHeader("fileName");
                if (StringUtils.isNotEmpty(fileName)) {
                    fileName = URLDecoder.decode(fileName, SystemConstant.CHARSET_NAME);
                }
                Iterator<String> iter = multiRequest.getFileNames();
                int count = 0;
                while (iter.hasNext()) {
                    if (count > 0) {
                        throw new JkServerException("仅支持单个文件的上传,不支持多文件上传");
                    }
                    count++;
                    MultipartFile file = multiRequest.getFile(iter.next());
                    if (file != null) {
                        // 创建随机文件夹
                        File kwStoreDir = new File(fileStoreConfig.getStorageRoot(), examType.name());
                        kwStoreDir = new File(kwStoreDir, examCode);
                        kwStoreDir = new File(kwStoreDir, "kw");
                        if (!kwStoreDir.exists()) {
                            kwStoreDir.mkdirs();
                        }
                        String ext = getExtension(file.getOriginalFilename());
                        File saveFile = new File(kwStoreDir, file.getOriginalFilename());
                        System.out.println("path:" + saveFile.getAbsolutePath());
                        saveFile.createNewFile();
                        inputStream = file.getInputStream();
                        outputStream = new FileOutputStream(saveFile);
                        IOUtils.copy(inputStream, outputStream);
                        //检查文件的MD5是否匹配
                        String md5Value = DigestUtils.md5Hex(new FileInputStream(saveFile));
                        if (StringUtils.isNotEmpty(md5)) {
//                            md5Value = FileMD5Utils.encrypt(saveFile);
                            if (!md5Value.equals(md5)) {
                                throw JkServerException.FILE_MD5_NOT_MATCH;
                            }
                        }
//                        if (Objects.isNull(md5Value)) {
//                            md5Value = FileMD5Utils.encrypt(saveFile);
//                        }
                        //2020-12-19日加入上传到阿里云
                        if (fileStoreConfig.storageIsOss()) {
                            String dirName = fileStoreConfig.getStorageRoot() + saveFile.toString().replace(fileStoreConfig.getStorageRoot(), "").replaceAll("\\\\", "/");
                            fileStoreConfig.ossUpload(dirName, file.getInputStream(), md5Value, fileStoreConfig.getStorageRoot());
                            saveFile.delete();
                        }
                        String path = examType.name() + File.separator + examCode + File.separator + "kw";
                        String accessUri = path + File.separator + file.getOriginalFilename();

                        // 存储文件
                        Attachment attachment = new Attachment();
                        attachment.setId(SystemConstant.getDbUuid());
                        attachment.setExamCode(examCode);
                        attachment.setAccessUri(accessUri);
                        attachment.setPath(path);

                        attachment.setOriginalName(file.getOriginalFilename());
                        attachment.setName(file.getOriginalFilename());
                        attachment.setExt(ext);
                        attachment.setExamCode(examCode);
                        attachment.setSize(Double.valueOf(file.getSize()));
                        attachment.setTime(System.currentTimeMillis());

                        attachment.setMd5(md5Value);
                        attachment.setMoved(false);
//                        attachment = attachmentService.save(attachment);
                        attachmentService.saveOrUpdate(attachment);

//                        Query query = new Query();
//                        query.addCriteria(Criteria.where("examCode").is(examCode));
//                        KwFile kwFile = mongoTemplate.findOne(query, KwFile.class);
                        QueryWrapper<KwFile> kwFileQueryWrapper = new QueryWrapper<>();
                        kwFileQueryWrapper.lambda().eq(KwFile::getExamCode, examCode);
                        KwFile kwFile = kwService.getOne(kwFileQueryWrapper);
//                        kwFile.setPaperAnswerFile(attachment);
//                        mongoTemplate.save(kwFile);
                        kwFile.setPaperAnswerFileId(attachment.getId());
                        kwService.saveOrUpdate(kwFile);

                        results.add(attachment);
                        IOUtils.closeQuietly(outputStream);
                        IOUtils.closeQuietly(inputStream);

                        System.out.println("save file:" + saveFile.getAbsolutePath());
                    } else {
                        throw new JkServerException("文件实体为null导致上传失败,考试识别码:" + examCode);
                    }
                }
            } else {
                throw new JkServerException("上传文件失败,请求中没有检测到文件实体,考试识别码:" + examCode);
            }
        } finally {
            if (outputStream != null) {
                IOUtils.closeQuietly(outputStream);
            }
            if (inputStream != null) {
                IOUtils.closeQuietly(inputStream);
            }
        }
        return results;
    }

    /**
     * 获取文件的后缀
     */
    protected String getExtension(String fileName) {
        int k = fileName.lastIndexOf(".");
        String ext = "";
        if (k > 0) {
            ext = fileName.substring(k + 1);
        }
        return ext;
    }
}
