package com.ruoyi.web.service;

import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.ruoyi.common.core.domain.AjaxResult;
import com.ruoyi.common.core.redis.RedisCache;
import com.ruoyi.common.utils.StringUtils;
import com.ruoyi.ie.domain.Paperques;
import com.ruoyi.ie.domain.Questions;
import com.ruoyi.mxjb.domain.MxjbContants;
import com.ruoyi.mxjb.domain.MxjbPaperAnswers;
import com.ruoyi.mxjb.domain.MxjbWrongBook;
import com.ruoyi.mxjb.domain.MxjbWrongDetail;
import com.ruoyi.mxjb.mapper.MxjbWrongBookMapper;
import com.ruoyi.mxjb.mapper.MxjbWrongDetailMapper;
import com.ruoyi.mxjb.util.DataLocker;
import com.ruoyi.sy.domain.SyTestAnswers;
import com.ruoyi.sy.domain.SyTestQuestion;
import com.ruoyi.system.service.ISysUserService;
import com.ruoyi.web.domain.PaperDto;
import com.ruoyi.web.domain.QuestionDto;
import org.apache.commons.collections.MapUtils;
import org.apache.commons.collections4.CollectionUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.function.Function;
import java.util.stream.Collectors;

@Service
public class AdminExaminationService {
    private final MxjbWrongBookMapper wrongBookMapper;
    private final MxjbWrongDetailMapper wrongDetailMapper;
    private final ISysUserService sysUserService;
    private final CacheService cacheService;
    @Autowired
    private RedisCache redisCache;
    private DataLocker examineeDataLocker = new DataLocker();

    public AdminExaminationService(MxjbWrongBookMapper wrongBookMapper, MxjbWrongDetailMapper wrongDetailMapper, ISysUserService sysUserService, CacheService cacheService) {
        this.wrongBookMapper = wrongBookMapper;
        this.wrongDetailMapper = wrongDetailMapper;
        this.sysUserService = sysUserService;
        this.cacheService = cacheService;
    }

    public QuestionDto toQuestionDto(SyTestQuestion t, boolean fillParseAndAnswer, Map<Long, SyTestAnswers> questionAnswersMap) {
        QuestionDto dto = new QuestionDto();
        dto.setQuestionId(t.getQuestionId());
        dto.setSeq(t.getSeq());
        dto.setTypeId(cacheService.getQuestionType(t.getQtpye()));
        dto.setType(t.getQtpye());
        dto.setTitle(t.getTitle());
        dto.setScoreTotal(t.getScore());
        dto.setOptions(getOptions(t.getOptionA(), t.getOptionB(), t.getOptionC(), t.getOptionD(), t.getOptionE()));
        if (fillParseAndAnswer) {
            dto.setParse(t.getParse());
        }
        if (null != questionAnswersMap) {
            SyTestAnswers answers = questionAnswersMap.get(t.getQuestionId());
            if (null != answers) {
                dto.setDuration(answers.getDuration());
                setAnswerAttachemnts(dto, answers.getAnswer());
            } else {
                dto.setAnswer(StringUtils.EMPTY);
                dto.setAttachments(new ArrayList<>());
            }
        } else {
            dto.setAnswer(StringUtils.EMPTY);
            dto.setAttachments(new ArrayList<>());
        }

        dto.setSource(t.getQuesitonCateogry());
        return dto;
    }

    public QuestionDto toQuestionDto(Questions t, boolean fillParseAndAnswer, Map<Long, MxjbPaperAnswers> questionAnswersMap) {
        QuestionDto dto = new QuestionDto();
        dto.setQuestionId(t.getId());
        dto.setSeq(t.getSeq());
        dto.setTypeId(cacheService.getQuestionType(t.getQtpye()));
        dto.setType(t.getQtpye());
        dto.setTitle(StringUtils.isBlank(t.getTitle1()) ? t.getTitle() : t.getTitle1() + "<br />" + t.getTitle());
        dto.setKnowledgeId(t.getKnowledgeId());
        dto.setKnowledgeName(t.getKnowledges());
        dto.setScoreTotal(t.getScore());
        dto.setSubjectId(null != t.getSubjectId() ? t.getSubjectId().longValue() : null);
        dto.setCollect(t.isCollect());
        if (fillParseAndAnswer) {
            dto.setParse(t.getParse());
            dto.setAnswers(getAnswers(MxjbContants.QuestionTypeMultiChoose.equals(dto.getTypeId()), t.getAnswers(), t.getAnswer1(), t.getAnswer2()));
        } else {
            dto.setAnswers(Lists.newArrayList());
        }
        if (CollectionUtils.isNotEmpty(t.getSubquestions())) {
            List<QuestionDto> subQuestionList = Lists.newArrayList();
            List<String> subParseList = Lists.newArrayList();
            Long subScoreTotal = 0L;
            int questionNum = 0;
            List<String> subAnswers = Lists.newArrayList();
            for (Questions sq : t.getSubquestions()) {
                questionNum++;
                QuestionDto sqDto = toQuestionDto(sq, false, null);
                sqDto.setOptions(getOptions(sq.getOptionA(), sq.getOptionB(), sq.getOptionC(), sq.getOptionD(), sq.getOptionE()));
                subQuestionList.add(sqDto);
                if (StringUtils.isNotBlank(sq.getParse())) {
                    subParseList.add("第" + questionNum + "题: " + sq.getParse());
                }
                List<String> subAnswer = getAnswers(MxjbContants.QuestionTypeMultiChoose.equals(sqDto.getTypeId()), sq.getAnswers(), sq.getAnswer1(), sq.getAnswer2());
                subAnswers.add(subAnswer.get(0));
                subScoreTotal += sq.getScore();
                sqDto.setType(null);
            }
            dto.setScoreTotal(subScoreTotal);
            dto.setSubQuestions(subQuestionList);
            if (fillParseAndAnswer) {
                dto.setParse(StringUtils.join(subParseList, "<br/><br/>"));
                String subAnswer = StringUtils.join(subAnswers, ",");
                dto.setAnswers(Lists.newArrayList(subAnswer));
            }
        } else {
            dto.setOptions(getOptions(t.getOptionA(), t.getOptionB(), t.getOptionC(), t.getOptionD(), t.getOptionE()));
        }
        if (null != questionAnswersMap) {
            MxjbPaperAnswers answers = questionAnswersMap.get(t.getId());
            if (null != answers) {
                dto.setDuration(answers.getDuration());
                setAnswerAttachemnts(dto, answers.getAnswer());
                if (fillParseAndAnswer) {
                    dto.setScoreLevel(answers.getScoreLevel());
                    dto.setScore(answers.getScore());
                    dto.setScoreRate(answers.getScoreRate());
                }
            }
        }
        return dto;
    }

    public void setAnswerAttachemnts(QuestionDto dto, String answer) {
        if (StringUtils.isNotBlank(answer)) {
            String[] answerArray = StringUtils.splitByWholeSeparatorPreserveAllTokens(answer, "$@");
            if (answerArray.length > 0) {
                dto.setAnswer(answerArray[0]);
                if (answerArray.length > 1) {
                    List<String> attacheList = Lists.newArrayList();
                    for (int i = 1; i < answerArray.length; i++) {
                        if (StringUtils.isNotBlank(answerArray[i]) && !"null".equals(answerArray[i])) {
                            attacheList.add(answerArray[i]);
                        }
                    }
                    dto.setAttachments(attacheList);
                }
            }
        }
    }

    public List<String> getAnswers(boolean multiChose, String correct, String... answers) {
        if (StringUtils.isNotBlank(correct)) {
            String[] answerArray = StringUtils.split(correct, "$@");
            return this.getOptions(answerArray);
        }
        if (answers.length > 0 && multiChose) {
            answers[0] = correctAnswers(answers[0]);
        }
        return this.getOptions(answers);
    }

    private String correctAnswers(String answer) {
        return StringUtils.isNotBlank(answer) ? StringUtils.join(answer.replaceAll("\\||,|、| ", "").split(""), ",") : answer;
    }

    private List<String> getOptions(String... options) {
        List<String> optionList = Lists.newArrayList();
        for (String option : options) {
            if (StringUtils.isNotBlank(option)) {
                optionList.add(option);
            }
        }
        return optionList;
    }

    public void updateTempAnswerAndSave(PaperDto paperDto, Long examineeId, String examineeType) {
        String type = MxjbContants.getExamineeTypeKey(examineeType);
        String key = getExamineeAnswersKey(type, examineeId);
        Map<String, QuestionDto> questionDtoMap = redisCache.getCacheMap(key);
        if (MapUtils.isNotEmpty(questionDtoMap)) {
            Long lastQuestionId = questionDtoMap.get("0").getQuestionId();
            paperDto.getQuestions().forEach(t -> {
                QuestionDto dto = questionDtoMap.get(t.getQuestionId().toString());
                if (null != dto) {
                    t.setAnswer(dto.getAnswer());
                    t.setAttachments(dto.getAttachments());
                    t.setDuration(dto.getDuration());
                    t.setCurrent(t.getQuestionId().equals(lastQuestionId));
                }
            });
        } else if (CollectionUtils.isNotEmpty(paperDto.getQuestions())) {
            paperDto.getQuestions().get(0).setCurrent(true);
        }
    }

    public AjaxResult saveQuestion(PaperDto paperDto) {
        AjaxResult ajaxResult;
        DataLocker.SemaphoreDataLocker semaphoreDataLocker = null;
        try {
            semaphoreDataLocker = examineeDataLocker.getSemaphore(paperDto.getExamineeId());
            semaphoreDataLocker.acquire();
            ajaxResult = saveQuestionWithLocker(paperDto);
            semaphoreDataLocker.release();
        } catch (InterruptedException e) {
            throw new RuntimeException("计算中断", e);
        } finally {
            examineeDataLocker.freeSemaphore(semaphoreDataLocker);
        }
        return ajaxResult;
    }
    public AjaxResult saveQuestionWithLocker(PaperDto paperDto) {
        String type = MxjbContants.getExamineeTypeKey(paperDto.getExamineeType());
        String key = getExamineeAnswersKey(type, paperDto.getExamineeId());
        Map<String, QuestionDto> questionDtoMap = redisCache.getCacheMap(key);
        if (null == questionDtoMap) {
            questionDtoMap = Maps.newHashMap();
        }
        QuestionDto posDto = questionDtoMap.get("0");
        if (null == posDto) {
            posDto = new QuestionDto();
            questionDtoMap.put("0", posDto);
        }
        for (QuestionDto questionDto : paperDto.getQuestions()) {
            QuestionDto cacheDto = new QuestionDto();
            cacheDto.setQuestionId(questionDto.getQuestionId());
            cacheDto.setDuration(questionDto.getDuration());
            cacheDto.setAnswer(questionDto.getAnswer());
            cacheDto.setAttachments(questionDto.getAttachments());
            questionDtoMap.put(cacheDto.getQuestionId().toString(), cacheDto);
            posDto.setQuestionId(cacheDto.getQuestionId());
        }
        redisCache.setCacheMap(key, questionDtoMap);
        return AjaxResult.success("");
    }


    public void  calculateWrongAnswers(PaperDto standPaper, List<MxjbPaperAnswers> answersList, Long examineeId, String customerCode, String source) {
        Map<Long, QuestionDto> questionMap = standPaper.getQuestions().stream().collect(Collectors.toMap(QuestionDto::getQuestionId, Function.identity()));
        if (CollectionUtils.isEmpty(answersList)){
            return;
        }
        answersList.forEach(t -> {
            if (MxjbContants.InvalidScoreLevelSet.contains(t.getScoreLevel())) {
                MxjbWrongBook wrongBookCond = new MxjbWrongBook();
                wrongBookCond.setCustomerCode(customerCode);
                wrongBookCond.setQuestionId(t.getQuestionId());
                QuestionDto standard = questionMap.get(t.getQuestionId());
                if(null==standard){
                    standard = new QuestionDto();
                }
                List<MxjbWrongBook> wrongBookList = wrongBookMapper.selectMxjbWrongBookList(wrongBookCond);
                if (CollectionUtils.isNotEmpty(wrongBookList)) {
                    MxjbWrongBook wrongBook = wrongBookList.get(0);
                    if (null == wrongBook.getWrongCount()) {
                        wrongBook.setWrongCount(0L);
                    }
                    if (null == wrongBook.getTotalCount()) {
                        wrongBook.setTotalCount(0L);
                    }
                    wrongBookCond.setWrongId(wrongBook.getWrongId());
                    wrongBookCond.setCustomerCode(null);
                    wrongBookCond.setQuestionId(null);
                    wrongBookCond.setWrongCount(wrongBook.getWrongCount() + 1);
                    wrongBookCond.setTotalCount(wrongBook.getTotalCount() + 1);
                } else {
                    List<String> answerList = standard.getAnswers();
                    if (CollectionUtils.isNotEmpty(answerList)) {
                        wrongBookCond.setAnswer1(answerList.get(0));
                        if (answerList.size() > 1) {
                            wrongBookCond.setAnswer2(answerList.get(1));
                        }
                    }
                    wrongBookCond.setSubjectId(standard.getSubjectId());
                    wrongBookCond.setRightCount(0L);
                    wrongBookCond.setWrongCount(1L);
                    wrongBookCond.setTotalCount(1L);
                    wrongBookCond.setScoreTotal(standard.getScoreTotal());
                }
                wrongBookCond.setKnownledgeId(standard.getKnowledgeId());
                wrongBookCond.setKnownledgeName(standard.getKnowledgeName());
                wrongBookCond.setPaperType(standPaper.getPaperType());
                wrongBookCond.setPaperId(standPaper.getPaperId());
                wrongBookCond.setScore(t.getScore());
                wrongBookCond.setSource(source);
                wrongBookCond.setDuration(standard.getDuration());
                wrongBookCond.setComment(standard.getComment());
                wrongBookCond.setAnswers(t.getAnswer());
                wrongBookCond.setState(MxjbContants.QuestionScoreWrong);
                if(null == wrongBookCond.getWrongId()) {
                    wrongBookMapper.insertMxjbWrongBook(wrongBookCond);
                } else {
                    wrongBookMapper.updateMxjbWrongBook(wrongBookCond);
                }
                MxjbWrongDetail wrongDetail = new MxjbWrongDetail();
                wrongDetail.setWrongId(wrongBookCond.getWrongId());
                wrongDetail.setCreatedTime(new Date());
                wrongDetail.setSource(wrongBookCond.getSource() + ":" + examineeId);
                wrongDetail.setState(0);
                wrongDetail.setExamineeId(examineeId);
                wrongDetail.setPaperId(standPaper.getPaperId());
                wrongDetailMapper.insertMxjbWrongDetail(wrongDetail);
            }
        });
    }

    public String getExamineeAnswersKey(String type, Long examineeId) {
        return type + "EA::" + examineeId;
    }

}
