package cn.com.qmth.examcloud.core.questions.service.impl;

import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.List;

import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.bson.types.ObjectId;
import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Sort;
import org.springframework.data.domain.Sort.Direction;
import org.springframework.data.domain.Sort.Order;
import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.data.mongodb.core.query.Criteria;
import org.springframework.data.mongodb.core.query.Query;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;

import cn.com.qmth.examcloud.api.commons.enums.AdminOperateType;
import cn.com.qmth.examcloud.api.commons.security.bean.User;
import cn.com.qmth.examcloud.commons.exception.StatusException;
import cn.com.qmth.examcloud.core.questions.base.Model;
import cn.com.qmth.examcloud.core.questions.base.enums.PaperType;
import cn.com.qmth.examcloud.core.questions.base.question.enums.QuesStructType;
import cn.com.qmth.examcloud.core.questions.dao.PaperDetailUnitRepo;
import cn.com.qmth.examcloud.core.questions.dao.PaperRepo;
import cn.com.qmth.examcloud.core.questions.dao.entity.Paper;
import cn.com.qmth.examcloud.core.questions.dao.entity.PaperDetail;
import cn.com.qmth.examcloud.core.questions.dao.entity.PaperDetailUnit;
import cn.com.qmth.examcloud.core.questions.dao.entity.Question;
import cn.com.qmth.examcloud.core.questions.service.PaperDetailUnitService;
import cn.com.qmth.examcloud.core.questions.service.PaperService;
import cn.com.qmth.examcloud.core.questions.service.QuesService;
import cn.com.qmth.examcloud.core.questions.service.RandomPaperQuestionService;
import cn.com.qmth.examcloud.core.questions.service.bean.dto.PaperDetailUnitDto;
import cn.com.qmth.examcloud.core.questions.service.bean.dto.PaperDetailUnitExp;
import cn.com.qmth.examcloud.core.questions.service.cache.BasePaperCache;
import cn.com.qmth.examcloud.core.questions.service.cache.ExtractConfigPaperCache;
import cn.com.qmth.examcloud.core.questions.service.cache.QuestionAnswerCache;
import cn.com.qmth.examcloud.core.questions.service.cache.QuestionCache;
import cn.com.qmth.examcloud.core.questions.service.util.PaperUtil;
import cn.com.qmth.examcloud.reports.commons.bean.AdminOperateReport;
import cn.com.qmth.examcloud.reports.commons.util.ReportsUtil;

/**
 * @author chenken
 * @date 2017年9月13日 上午11:29:56
 * @company QMTH
 */
@Service("paperDetailUnitService")
public class PaperDetailUnitServiceImpl implements PaperDetailUnitService {
    @Autowired
    PaperRepo paperRepo;
    @Autowired
    private ExtractConfigPaperCache extractConfigPaperCache;
    @Autowired
    private BasePaperCache basePaperCache;
    @Autowired
    private QuestionCache questionCache;
    @Autowired
    private QuestionAnswerCache questionAnswerCache;
    
    
    @Autowired
    PaperDetailUnitRepo paperDetailUnitRepo;

    @Autowired
    QuesService quesService;

    @Autowired
    PaperService paperService;

    @Autowired
    MongoTemplate mongoTemplate;

    @Autowired
    RedisTemplate<String, Object> redisTemplate;
    @Autowired
    private RandomPaperQuestionService randomPaperQuestionService;
    
    /**
     * 根据Id获得对应的试题对象
     *
     * @param id
     * @return
     */
    public Question getQuestionByPaperDetailUnitId(String id) {
        return Model.of(paperDetailUnitRepo.findById(id)).getQuestion();
    }

    /**
     * 按ID查询小题
     *
     * @param id
     * @return
     */
    public PaperDetailUnit findById(String id) {
        return Model.of(paperDetailUnitRepo.findById(id));
    }
    private void checkFillBlankQuestion(Question question) {
    	if(question.getQuestionType() == QuesStructType.FILL_BLANK_QUESTION) {
    		String body=question.getQuesBody();
    		Document bodyDoc = Jsoup.parse(body);
    		if(bodyDoc.body().childrenSize()==0) {
    			throw new StatusException("1000", "题干不能为空");
    		}
	        String bodyText=bodyDoc.body().html();
	        if(StringUtils.isBlank(bodyText)) {
	        	throw new StatusException("1001", "题干不能为空");
	        }
	        if(bodyText.indexOf("###")==-1) {
	        	throw new StatusException("1002", "题干不能没有空格(###)");
	        }
	        String answer=question.getQuesAnswer();
	        Document answerDoc = Jsoup.parse(answer);
	        if(answerDoc.body().childrenSize()!=0) {
		        String answerText=answerDoc.body().html();
		        if(StringUtils.isNotBlank(answerText)) {
		        	if(getSubStringCount(bodyText, "###")!=answerText.split("##").length) {
		        		throw new StatusException("1003", "题干空格(###)数量和答案数量不一致");
		        	}
		        }
	        }
    	}
    }
    private int getSubStringCount(String src,String find){
    	int o = 0;
    	int index=-1;
    	while((index=src.indexOf(find,index))>-1){
	    	++index;
	    	++o;
    	}
		return o;
	}
    
    @Override
    public boolean paperInUse(String questionId) {
    	 Query query = new Query();
         query.addCriteria(Criteria.where("question.$id").is(new ObjectId(questionId)));
         query.addCriteria(Criteria.where("paperType").is(PaperType.GENERATE.name()));
         List<PaperDetailUnitDto> units=this.mongoTemplate.find(query, PaperDetailUnitDto.class,"paperDetailUnit");
         if(CollectionUtils.isEmpty(units)) {
        	 return false;
         }
         for(PaperDetailUnitDto dto:units) {
        	 if(dto.getPaper().getInUse()!=null&&dto.getPaper().getInUse()==1) {
        		 return true;
        	 }
         }
         return false;
    }
    /**
     * 保存小题
     */
    public PaperDetailUnit savePaperDetailUnit(PaperDetailUnitExp updateUnit, User user) {
    	StringBuilder sb=new StringBuilder();
        PaperDetailUnit baseUnit = Model.of(paperDetailUnitRepo.findById(updateUnit.getId()));
        if(paperInUse(baseUnit.getQuestion().getId())) {
        	PaperUtil.checkUpdate(updateUnit, baseUnit,"试卷已调用,");
        }
        if(randomPaperQuestionService.existQuestion(baseUnit.getQuestion().getId())) {
        	PaperUtil.checkUpdateOption(updateUnit, baseUnit,"小题已被抽题模板使用,");
        }
        Question baseQuestion = baseUnit.getQuestion();
        Question updateQuestion = updateUnit.getQuestion();
        checkFillBlankQuestion(updateQuestion);
        if (baseUnit.getQuestionType() == QuesStructType.NESTED_ANSWER_QUESTION) {
            if (updateQuestion.getId().equals(baseQuestion.getId())) {
            	
            	if(!StringUtils.equals(baseQuestion.getQuesBody(), updateQuestion.getQuesBody())) {
            		sb.append(" 第"+baseUnit.getNumber()+"小题(套题)题干变动");
            	}
                // 更新对象为套题本身
                quesService.saveQues(updateQuestion);
                baseUnit.setQuestion(updateQuestion);
            } else {
            	if(updateQuestion.getQuesOptions()!=null&&updateQuestion.getQuesOptions().size()>26) {
            		throw new StatusException("选项数量不能超过26");
            	}
                List<Double> subScoreList = baseUnit.getSubScoreList();
                int size = baseQuestion.getSubQuestions().size();
                boolean match = false;

                // 判断更新的对象是哪个子题
                for (int index = 1; index <= size; index++) {
                    // 检查子题分数，确保没有错误数据
                    if (subScoreList.size() < index) {
                        subScoreList.add(0d);
                    }

                    Question sub = baseQuestion.getSubQuestions().get(index - 1);
                    if (updateQuestion.getId().equals(sub.getId())) {
                    	String changInfo=getQuestionChangeInfo(sub, updateQuestion);
                    	if(changInfo!=null) {
                    		sb.append("第"+baseUnit.getNumber()+"小题第"+index+"子题变动:"+changInfo);
                    	}
                        // 匹配到子题
                        subScoreList.set(index - 1, updateUnit.getScore());
                        baseQuestion.getSubQuestions().set(index - 1, updateQuestion);

                        //重新计算套题的难度，公开度
                        boolean publicity = false;
                        double totalSum = 0d;
                        double totalDou = 0d;
                        for (int i = 0; i < baseQuestion.getSubQuestions().size(); i++) {
                            Question subQuestion = baseQuestion.getSubQuestions().get(i);
                            //设置公开度
                            if (subQuestion.getPublicity()) {
                                publicity = true;
                            }

                            if (subQuestion.getDifficultyDegree() == null) {
                                subQuestion.setDifficultyDegree(0.5);
                            }

                            totalSum = subQuestion.getDifficultyDegree() * subScoreList.get(i) + totalSum;
                            totalDou = subScoreList.get(i) + totalDou;
                        }

                        BigDecimal b;
                        if (totalDou != 0d) {
                            b = BigDecimal.valueOf(totalSum / totalDou);
                        } else {
                            b = BigDecimal.valueOf(0d);
                        }

                        Double difficulty = b.setScale(2, BigDecimal.ROUND_HALF_UP).doubleValue();
                        baseQuestion.setDifficultyDegree(difficulty);
                        baseQuestion.setPublicity(publicity);
                        match = true;
                    }
                }

                if (match) {
                    quesService.saveQues(baseQuestion);
                    baseUnit.setQuestion(baseQuestion);
                }

                // 更新套题unit当前总分与子题分数
                baseUnit.setSubScoreList(subScoreList);
            }
        } else {
        	if(updateQuestion.getQuesOptions()!=null&&updateQuestion.getQuesOptions().size()>26) {
        		throw new StatusException("选项数量不能超过26");
        	}
        	String changInfo=getQuestionChangeInfo(baseQuestion, updateQuestion);
        	if(changInfo!=null) {
        		sb.append("第"+baseUnit.getNumber()+"小题变动:"+changInfo);
        	}
            quesService.saveQues(updateQuestion);
            baseUnit.setQuestion(updateQuestion);
            baseUnit.setScore(updateUnit.getScore());
        }

        // 同时要跟新小题里面的Question对象
        paperDetailUnitRepo.save(baseUnit);

        Paper paper = baseUnit.getPaper();
        Double total=paper.getTotalScore();
        Integer dc=paper.getPaperDetailCount();
        Integer uc=paper.getUnitCount();
        if(PaperType.GENERATE.equals(paper.getPaperType())) {
        	paper.setAuditStatus(false);
        }
        paperService.formatPaper(paper, user);

        String changInfo=PaperUtil.getPaperChangeInfo(total, dc, uc, paper);
    	if(changInfo!=null) {
    		sb.append(changInfo);
    	}
    	if(sb.length()!=0) {
    		StringBuilder paperInfo=new StringBuilder();
    		paperInfo.append(" 课程:"+paper.getCourse().getName()+"("+paper.getCourse().getCode()+")");
    		paperInfo.append(" 试卷名称:"+paper.getName());
    		sb.append(paperInfo);
    		if(PaperType.IMPORT.equals(paper.getPaperType())) {
    			ReportsUtil.report(new AdminOperateReport(user.getRootOrgId(), user.getUserId(), AdminOperateType.TYPE43.getDesc(),sb.toString()));
    		}else {
    			ReportsUtil.report(new AdminOperateReport(user.getRootOrgId(), user.getUserId(), AdminOperateType.TYPE44.getDesc(),sb.toString()));
    		}
    	}
        if (baseUnit.getQuestion() != null) {
            //清除缓存
            this.clearQuestionCache(baseUnit.getQuestion().getId());
        }

        return baseUnit;
    }
    
    
    
    private String getQuestionChangeInfo(Question old,Question now) {
    	StringBuilder sb=new StringBuilder();
    	if(old.getScore().doubleValue() !=now.getScore().doubleValue()) {
    		sb.append(" 分数变动("+old.getScore()+"变为"+now.getScore()+")");
    	}
    	if(!StringUtils.equals(old.getQuesBody(), now.getQuesBody())) {
    		sb.append(" 题干变动");
    	}
    	if(optionChange(old, now)) {
    		sb.append(" 选项变动");
    	}
    	if(!StringUtils.equals(old.getQuesAnswer(), now.getQuesAnswer())) {
    		sb.append(" 答案变动");
    	}
    	if(sb.length()==0) {
    		return null;
    	}
    	return sb.toString();
    }
    
    private boolean optionChange(Question old,Question now) {
    	if(now.getQuesOptions()==null) {
    		return false;
    	}
    	if(old.getQuesOptions().size()!=now.getQuesOptions().size()) {
    		return true;
    	}
    	for(int i=0;i<now.getQuesOptions().size();i++) {
    		if(!StringUtils.equals(old.getQuesOptions().get(i).getOptionBody(), now.getQuesOptions().get(i).getOptionBody())) {
    			return true;
        	}
    	}
    	return false;
    }
    /**
     * 删除小题
     *
     * @param id
     * @return
     */
    public void deletePaperDetailUnit(String id, User user) {
    	String changInfo=null;
        PaperDetailUnit detailUnit = Model.of(paperDetailUnitRepo.findById(id));
        Paper paper = detailUnit.getPaper();
        if(paper.getInUse()!=null&&paper.getInUse()==1) {
			throw new StatusException("500", "试卷已调用");
		}
        paperDetailUnitRepo.deleteById(id);

        if (detailUnit.getQuestion() != null) {
            //清除缓存
            this.clearQuestionCache(detailUnit.getQuestion().getId());
        }
        Double total=paper.getTotalScore();
        Integer dc=paper.getPaperDetailCount();
        Integer uc=paper.getUnitCount();
        paper.setAuditStatus(false);
        paperService.formatPaper(paper, user);
        changInfo=PaperUtil.getPaperChangeInfo(total, dc, uc, paper);
        if(detailUnit!=null) {
        	StringBuilder sb=new StringBuilder();
			sb.append("课程:"+detailUnit.getPaper().getCourse().getName()+"("+detailUnit.getPaper().getCourse().getCode()+")");
			sb.append(" 试卷名称:"+detailUnit.getPaper().getName()); 
			sb.append(" 第"+detailUnit.getNumber()+"小题 ");
			sb.append(changInfo);
        	ReportsUtil.report(new AdminOperateReport(user.getRootOrgId(), user.getUserId(), AdminOperateType.TYPE45.getDesc(),sb.toString()));
        }
    }

    /**
     * 根据大题查小题
     *
     * @param paperDetail
     * @return
     */
    public List<PaperDetailUnit> getUnitsByPaperDetail(PaperDetail paperDetail) {
        return paperDetailUnitRepo.findByPaperDetailOrderByNumber(paperDetail);
    }

    /**
     * 根据大题集合删除小题
     *
     * @param paperDetails
     */
    public void deleteUnitsByPaperDetails(List<PaperDetail> paperDetails) {
        List<PaperDetailUnit> units = new ArrayList<>();
        for (PaperDetail pd : paperDetails) {
            units.addAll(getUnitsByPaperDetail(pd));
        }
        paperDetailUnitRepo.deleteAll(units);
    }

    public List<PaperDetailUnit> findByQuestionAndPaperTypes(Question question, List<PaperType> paperTypes) {
        Query query = new Query();
        query.addCriteria(Criteria.where("paperType").in(paperTypes));
        query.addCriteria(Criteria.where("question").is(question));
        return this.mongoTemplate.find(query, PaperDetailUnit.class);
    }

    /**
     * 查询大题下的小题
     * 按number升序或降序排列，取第一个
     *
     * @return
     */
    public PaperDetailUnit findTopOrderByNumber(PaperDetail paperDetail, String orderType) {
        if ("ASC".equals(orderType)) {
            return paperDetailUnitRepo.findTopByPaperDetailOrderByNumberAsc(paperDetail);
        } else if ("DESC".equals(orderType)) {
            return paperDetailUnitRepo.findTopByPaperDetailOrderByNumberDesc(paperDetail);
        }
        return null;
    }

    /**
     * 按试卷 查询 小题，并将小题按number，createTime排序
     *
     * @param paper
     * @return
     */
    public List<PaperDetailUnit> findByPaperAndSort(Paper paper) {
        Query query = new Query();
        query.addCriteria(Criteria.where("paper").is(paper));
        query.with(Sort.by(new Order(Direction.ASC, "number")));
        query.with(Sort.by(new Order(Direction.ASC, "createTime")));
        return this.mongoTemplate.find(query, PaperDetailUnit.class);
    }


    public List<PaperDetailUnit> findByQuestionsAndPaperTypeOnline(List<String> ids, PaperType paperType) {
        Query query = new Query();
        query.addCriteria(Criteria.where("question.id").in(ids));
        query.addCriteria(Criteria.where("paperType").is(paperType));
        List<PaperDetailUnit> paperDetailUnits = this.mongoTemplate.find(query, PaperDetailUnit.class);
        return paperDetailUnits;
    }

    @Override
    public List<PaperDetailUnit> findByQuestionsAndPaperType(List<String> ids, PaperType paperType) {
        List<ObjectId> objectIds = new ArrayList<>();
        for (String id : ids) {
            objectIds.add(new ObjectId(id));
        }
        Query query = new Query();
        query.addCriteria(Criteria.where("question.$id").in(objectIds));
        query.addCriteria(Criteria.where("paperType").is(paperType));
        List<PaperDetailUnit> paperDetailUnits = this.mongoTemplate.find(query, PaperDetailUnit.class);
        return paperDetailUnits;
    }

    @Override
    public List<PaperDetailUnit> findByDDQuestionsAndPaperType(List<String> ids, PaperType paperType, List<Question> questionList) {
        List<ObjectId> objectIds = new ArrayList<>();
        for (String id : ids) {
            objectIds.add(new ObjectId(id));
        }
        Query query = new Query();
        query.addCriteria(Criteria.where("question.$id").in(objectIds));
        query.addCriteria(Criteria.where("paperType").is("IMPORT"));
        List<PaperDetailUnit> paperDetailUnits = mongoTemplate.find(query, PaperDetailUnit.class);
        return paperDetailUnits;
    }

	/*@Override
	public List<PaperDetailUnit> testFind(List<String> ids,PaperType paperType, List<Question> questionList) {
		//第一种查询，quesion.id  id
		DBObject query1 = new BasicDBObject();
		BasicDBList values = new BasicDBList();
		for(String id:ids){
			values.add(id);
		}
		query1.put("quesion.id", new BasicDBObject("$in", values));
		DBCursor dbCursor = mongoTemplate.getCollection("paperDetailUnit").find(query1);
		while (dbCursor.hasNext()){
			DBObject object=dbCursor.next();
			log.debug("打印游标---------------"+object);
		}

		//第二种查询，quesion.$id  id
		//DBObject query2 = new BasicDBObject();
		BasicDBList values2 = new BasicDBList();
		for(String id:ids){
			values2.add(id);
		}
		query1.put("quesion.$id", new BasicDBObject("$in", values2));
		DBCursor dbCursor2 = mongoTemplate.getCollection("paperDetailUnit").find(query1);
		while (dbCursor2.hasNext()){
			DBObject object=dbCursor2.next();
			log.debug("打印游标2---------------"+object);
		}

		//第三种查询，quesion.$id  ObjectId
		//DBObject query3 = new BasicDBObject();
		BasicDBList values3 = new BasicDBList();
		for(String id:ids){
			values3.add(new ObjectId(id));
		}
		query1.put("quesion.$id", new BasicDBObject("$in", values3));
		DBCursor dbCursor3 = mongoTemplate.getCollection("paperDetailUnit").find(query1);
		while (dbCursor3.hasNext()){
			DBObject object=dbCursor3.next();
			log.debug("打印游标3---------------"+object);
		}
		return null;
	}*/

    @Override
    public List<PaperDetailUnit> findByPaperIds(List<String> ids) {
        List<ObjectId> objectIds = new ArrayList<>();
        for (String id : ids) {
            objectIds.add(new ObjectId(id));
        }
        Query query = new Query();
        query.addCriteria(Criteria.where("paper.$id").in(objectIds));
        List<PaperDetailUnit> paperDetailUnits = mongoTemplate.find(query, PaperDetailUnit.class);
        return paperDetailUnits;
    }

    @Override
    public void clearQuestionCache(String questionId) {
        //清理与当前试题相关的缓存
//        final String patternKey = CACHE_KEY_QUESTION + "*" + questionId;
//        Set<String> keys = redisTemplate.keys(patternKey);
//        if (CollectionUtils.isNotEmpty(keys)) {
//            redisTemplate.delete(keys);
//        }
        questionCache.remove(questionId);
        questionAnswerCache.remove(questionId);
        //根据questionId清空相关联的paper缓存
        List<PaperDetailUnit> list=findByQuestionId(questionId);
        if(list!=null&&list.size()>0) {
        	for(PaperDetailUnit pd:list) {
//        		String paperKey = CACHE_KEY_PAPER + "*" + pd.getPaper().getId();
//                Set<String> paperKeys = redisTemplate.keys(paperKey);
//                if (CollectionUtils.isNotEmpty(paperKeys)) {
//                    redisTemplate.delete(paperKeys);
//                }
        	    extractConfigPaperCache.remove(pd.getPaper().getId());
        	    basePaperCache.remove(pd.getPaper().getId());
        	}
        }
    }
    
    private List<PaperDetailUnit> findByQuestionId(String questionId) {
        Query query = new Query();
        query.addCriteria(Criteria.where("question.id").is(questionId));
        List<PaperDetailUnit> paperDetailUnits = this.mongoTemplate.find(query, PaperDetailUnit.class);
        return paperDetailUnits;
    }

}