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

import cn.com.qmth.examcloud.api.commons.security.bean.User;
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.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.bean.dto.PaperDetailUnitExp;
import cn.com.qmth.examcloud.web.redis.RedisClient;
import org.apache.commons.collections.CollectionUtils;
import org.bson.types.ObjectId;
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 java.math.BigDecimal;
import java.util.ArrayList;
import java.util.List;
import java.util.Set;

import static cn.com.qmth.examcloud.core.questions.service.cache.Constants.CACHE_PREFIX_QUESTION;

/**
 * @author chenken
 * @date 2017年9月13日 上午11:29:56
 * @company QMTH
 * @description PaperDetailUnitServiceImpl.java
 */
@Service("paperDetailUnitService")
public class PaperDetailUnitServiceImpl implements PaperDetailUnitService {

    @Autowired
    PaperDetailUnitRepo paperDetailUnitRepo;

    @Autowired
    QuesService quesService;

    @Autowired
    PaperService paperService;

    @Autowired
    MongoTemplate mongoTemplate;

    @Autowired
    RedisTemplate<String, Object> redisTemplate;

    @Autowired
    RedisClient redisClient;

    /**
     * 根据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));
    }

    /**
     * 保存小题
     */
    public PaperDetailUnit savePaperDetailUnit(PaperDetailUnitExp updateUnit, User user) {
        PaperDetailUnit baseUnit = Model.of(paperDetailUnitRepo.findById(updateUnit.getId()));
        Question baseQuestion = baseUnit.getQuestion();
        Question updateQuestion = updateUnit.getQuestion();

        if (baseUnit.getQuestionType() == QuesStructType.NESTED_ANSWER_QUESTION) {
            if (updateQuestion.getId().equals(baseQuestion.getId())) {
                // 更新对象为套题本身
                quesService.saveQues(updateQuestion);
                baseUnit.setQuestion(updateQuestion);
            } else {
                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())) {
                        // 匹配到子题
                        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 = new BigDecimal(totalSum / totalDou);
                        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 {
            quesService.saveQues(updateQuestion);
            baseUnit.setQuestion(updateQuestion);
            baseUnit.setScore(updateUnit.getScore());
        }

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

        Paper paper = baseUnit.getPaper();
        paperService.formatPaper(paper, user);

        if (baseUnit.getQuestion() != null) {
            //清除缓存
            this.clearQuestionCache(baseUnit.getQuestion().getId());
        }

        return baseUnit;
    }

    /**
     * 删除小题
     *
     * @param id
     * @return
     */
    public void deletePaperDetailUnit(String id, User user) {
        PaperDetailUnit detailUnit = Model.of(paperDetailUnitRepo.findById(id));
        Paper paper = detailUnit.getPaper();
        paperDetailUnitRepo.deleteById(id);

        if (detailUnit.getQuestion() != null) {
            //清除缓存
            this.clearQuestionCache(detailUnit.getQuestion().getId());
        }

        paperService.formatPaper(paper, user);
    }

    /**
     * 根据大题查小题
     *
     * @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<PaperDetailUnit>();
        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(new Sort(new Order(Direction.ASC, "number")));
        query.with(new Sort(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<ObjectId>();
        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<ObjectId>();
        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();
			System.out.println("打印游标---------------"+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();
			System.out.println("打印游标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();
			System.out.println("打印游标3---------------"+object);
		}
		return null;
	}*/

    @Override
    public List<PaperDetailUnit> findByPaperIds(List<String> ids) {
        List<ObjectId> objectIds = new ArrayList<ObjectId>();
        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;
    }

    private void clearQuestionCache(String questionId) {
        //清理与当前试题相关的缓存
        final String patternKey = CACHE_PREFIX_QUESTION + "*" + questionId;
        Set<String> keys = redisTemplate.keys(patternKey);
        if (CollectionUtils.isNotEmpty(keys)) {
            redisTemplate.delete(keys);
        }
    }

}
