package cn.com.qmth.stmms.ms.quartz;

import cn.com.qmth.stmms.ms.commons.utils.RandomUtil;
import cn.com.qmth.stmms.ms.commons.utils.SqlUtil;
import cn.com.qmth.stmms.ms.core.cache.ParamCache;
import cn.com.qmth.stmms.ms.core.domain.*;
import cn.com.qmth.stmms.ms.core.domain.task.MarkTask;
import cn.com.qmth.stmms.ms.core.repository.MarkTaskJobRepo;
import cn.com.qmth.stmms.ms.core.repository.MarkTaskRepo;
import cn.com.qmth.stmms.ms.core.repository.PaperRepo;
import cn.com.qmth.stmms.ms.core.repository.WorkRepo;
import cn.com.qmth.stmms.ms.log.aop.MarkLogAop;
import cn.com.qmth.stmms.ms.marking.config.MarkingConfig;
import cn.com.qmth.stmms.ms.marking.service.MarkingService;
import com.alibaba.fastjson.JSONObject;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.scheduling.annotation.Async;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;

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

/**
 * @Description: quartz定时任务 task
 * @Param:
 * @return:
 * @Author: wangliang
 * @Date: 2020/1/16
 */
@Component
@Async
public class ScheduledTask implements InitializingBean {
    private static final org.slf4j.Logger LOGGER = LoggerFactory.getLogger(ScheduledTask.class);

    @Resource
    SqlUtil sqlUtil;

    @Resource
    RandomUtil randomUtil;

    @Resource
    PaperRepo paperRepo;

    @Resource
    MarkTaskRepo markTaskRepo;

    @Resource
    WorkRepo workRepo;

    @Resource
    MarkTaskJobRepo markTaskJobRepo;

    @Resource
    MarkLogAop markLogAop;

    @Resource
    MarkingService markingService;

    @Resource
    MarkingConfig markingConfig;

    boolean repairPaper = false, repairTask = false, markTaskJob = false;

    /**
     * 修复密号重复 30秒一次
     */
    @Scheduled(cron = "0/30 * * * * ?")
    public void repairRepeatSecretNumberTask() {
        if (Objects.nonNull(randomUtil.getRandomMap()) && randomUtil.getRandomMap().size() > 0) {
            List<Work> works = workRepo.findAllByActiveTrue();
            for (Work work : works) {
                if (Objects.nonNull(work)) {
                    if (!this.repairPaper) {
                        LOGGER.info("repairRepeatSecretNumberTask 修复试卷密号进来了");
                        repairRepeatPaper(work.getId());
                        LOGGER.info("repairRepeatSecretNumberTask 修复试卷密号结束了");
                    }
                    if (!this.repairTask) {
                        LOGGER.info("repairRepeatSecretNumberTask 修复任务密号进来了");
                        repairRepeatTask(work.getId());
                        LOGGER.info("repairRepeatSecretNumberTask 修复任务密号结束了");
                    }
                }
            }
        }
    }

    /**
     * 修复异步任务日志遗漏 1分钟一次
     */
    @Scheduled(cron = "0 0/1 * * * ?")
    public void markTaskJob() {
//        Work work = workRepo.findByActiveTrue();
        List<Work> works = workRepo.findAllByActiveTrue();
        for (Work work : works) {
            if (Objects.nonNull(work)) {
                if (!markTaskJob) {
                    LOGGER.info("markTaskJob 进来了");
                    repairMarkTaskJob(work);
                    LOGGER.info("markTaskJob 结束了");
                }
            }
        }
    }

    /**
     * 修复异步任务日志遗漏
     *
     * @param work
     */
    public void repairMarkTaskJob(Work work) {
        try {
            List<MarkTaskJob> markTaskJobList = markTaskJobRepo.findAllByStatusIsFalseAndWorkId(work.getId());
            if (Objects.nonNull(markTaskJobList) && markTaskJobList.size() > 0) {
                long startTime = System.currentTimeMillis();
                this.markTaskJob = true;
                for (MarkTaskJob m : markTaskJobList) {
                    long createTime = m.getCreateTime().getTime();
                    if ((startTime - createTime) / 1000 > 60) {
                        JSONObject jsonObject = JSONObject.parseObject(m.getDataObject());
                        String type = String.valueOf(jsonObject.get("type"));
                        Long paperId = Long.parseLong(String.valueOf(jsonObject.get("paperId")));
                        Paper paper = paperRepo.findOne(paperId);
                        List<MarkTask> markTaskList = markTaskRepo.findByWorkIdAndStageAndPaperId(work.getId(), MarkStage.LEVEL, paperId);
                        if (Objects.nonNull(markTaskList) && markTaskList.size() > 0) {
                            if (Objects.equals("levelsLog", type)) {
                                markingService.levelsLog(markTaskList, paper, m);//档位差日志记录
                            } else if (Objects.equals("autoCallback", type)) {
                                ParamSetting paramSetting = ParamCache.paramMap.get(work.getId());
                                Integer deviationParam = paramSetting == null ? 3 : paramSetting.getDeviation();
                                Integer deviation = jsonObject.get("deviation") == null ? deviationParam.intValue() : Integer.parseInt(String.valueOf(jsonObject.get("deviation")));
                                markLogAop.autoCallback(markTaskList, deviation, paper, m, work.getName());//自动打回记录
                            }
                        }
                    }
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
            throw new RuntimeException(e);
        } finally {
            this.markTaskJob = false;
        }
    }

    /**
     * 修复试卷密号
     *
     * @param workId
     */
    @Transactional
    public void repairRepeatPaper(Long workId) {
        try {
            String sql = "select * from (select p.random_seq, count(p.random_seq) as seq from paper p where p.work_id = ? group by p.random_seq) temp where temp.seq > 1 LIMIT 500";
            List list = sqlUtil.execSqlForMapNative(sql, workId);
            Set papers = new HashSet();
            if (Objects.nonNull(list) && list.size() > 0) {
                this.repairPaper = true;
                for (int i = 0; i < list.size(); i++) {
                    Map map = (Map) list.get(i);
                    Long randomSeq = Long.parseLong(String.valueOf(map.get("random_seq")));
                    List<Paper> paperList = paperRepo.findByRandomSeq(randomSeq);
                    paperList.remove(0);//删除一条
                    for (Paper paper : paperList) {
                        Long randomNew = this.getRandomPaper(paper.getWorkId(), paper.getExamNumber());
                        String secretNumberNew = paper.getSubject().ordinal() + paper.getAreaCode() + randomNew;
                        paper.setRandomSeq(randomNew);
                        paper.setSecretNumber(secretNumberNew);
                        papers.add(paper);
                    }
                }
            }
            if (Objects.nonNull(papers) && papers.size() > 0) {
                LOGGER.info("需要修改的paper数为:{}", papers.size());
                paperRepo.save(papers);
            }
        } catch (Exception e) {
            e.printStackTrace();
            throw new RuntimeException(e);
        } finally {
            this.repairPaper = false;
        }
    }

    /**
     * 修复任务密号
     *
     * @param workId
     */
    @Transactional
    public void repairRepeatTask(Long workId) {
        try {
            String sql = "select * from (select mt.random_seq_new, count(mt.random_seq_new) as seq from mark_task mt where mt.work_id = ? group by mt.random_seq_new) temp where temp.seq > 1 LIMIT 500";
            List list = sqlUtil.execSqlForMapNative(sql, workId);
            Set tasks = new HashSet();
            if (Objects.nonNull(list) && list.size() > 0) {
                this.repairTask = true;
                for (int i = 0; i < list.size(); i++) {
                    Map map = (Map) list.get(i);
                    Long randomSeq = Long.parseLong(String.valueOf(map.get("random_seq_new")));
                    List<MarkTask> markTaskList = markTaskRepo.findByRandomSeqNew(randomSeq);
                    markTaskList.remove(0);//删除一条
                    for (MarkTask markTask : markTaskList) {
                        Long randomNew = this.getRandomTask(markTask.getMarkerId(), markTask.getPaper().getId(), markTask.getWorkId(), markTask.getPaper().getExamNumber());
                        String secretNumberNew = markTask.getMarkerId() + markTask.getSubject().ordinal() + markTask.getPaper().getAreaCode() + randomNew;
                        markTask.setRandomSeqNew(randomNew);
                        markTask.setSecretNumber(secretNumberNew);
                        tasks.add(markTask);
                    }
                }
            }
            if (Objects.nonNull(tasks) && tasks.size() > 0) {
                LOGGER.info("需要修改的task数为:{}", tasks.size());
                markTaskRepo.save(tasks);
            }
        } catch (Exception e) {
            e.printStackTrace();
            throw new RuntimeException(e);
        } finally {
            this.repairTask = false;
        }
    }

    /**
     * 修复试卷随机号
     *
     * @param workId
     * @param examNumber
     * @return
     */
    private Long getRandomPaper(Long workId, String examNumber) {
        int count = 0, result = 0;
        Long random = 0L;
        while (true) {
            random = randomUtil.getRandomMap().get(workId).get(new Random().nextInt(randomUtil.getRandomMap().get(workId).size()));
            result = paperRepo.countByWorkIdAndExamNumberAndRandomSeq(workId, examNumber, random);
            if (result == 0 && Long.parseLong(examNumber) != random) {
                break;
            } else {
                count++;
            }
            if (count > 1000) {
                randomUtil.getRandom(workId, true);
                getRandomPaper(workId, examNumber);
            }
        }
        return random;
    }

    /**
     * 修复任务随机号
     *
     * @param markerId
     * @param paperId
     * @param workId
     * @param examNumber
     * @return
     */
    private Long getRandomTask(Long markerId, Long paperId, Long workId, String examNumber) {
        int count = 0, result = 0;
        Long random = 0L;
        while (true) {
            random = randomUtil.getRandomMap().get(workId).get(new Random().nextInt(randomUtil.getRandomMap().get(workId).size()));
            result = markTaskRepo.countByMarkerIdAndPaperIdAndWorkIdAndRandomSeqNew(markerId, paperId, workId, random);
            if (result == 0 && Long.parseLong(examNumber) != random) {
                break;
            } else {
                count++;
            }
            if (count > 1000) {
                randomUtil.getRandom(workId, true);
                getRandomTask(markerId, paperId, workId, examNumber);
            }
        }
        return random;
    }

    @Override
    public void afterPropertiesSet() {
        this.repairRepeatSecretNumberTask();
        this.markTaskJob();
    }
}
