package com.sundot.airport.exam.logic.eighteen.service.impl;

import cn.hutool.core.bean.BeanUtil;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.github.pagehelper.PageInfo;
import com.sundot.airport.common.utils.SecurityUtils;
import com.sundot.airport.exam.common.AbstractBaseExceptionEnum;
import com.sundot.airport.exam.common.CheckUtil;
import com.sundot.airport.exam.common.HttpResult;
import com.sundot.airport.exam.common.PageData;
import com.sundot.airport.exam.common.manager.ExamRecordManager;
import com.sundot.airport.exam.common.manager.GradeManager;
import com.sundot.airport.exam.common.model.BaseEntity;
import com.sundot.airport.exam.common.model.GradeResult;
import com.sundot.airport.exam.common.model.params.ExamRecPageParam;
import com.sundot.airport.exam.common.model.params.GetExamRecordParam;
import com.sundot.airport.exam.common.model.params.UserOption;
import com.sundot.airport.exam.common.model.result.ExamCountResult;
import com.sundot.airport.exam.common.model.result.GetExamRecordResult;
import com.sundot.airport.exam.common.model.result.sub.ExamRecordQuestion;
import com.sundot.airport.exam.common.service.ExamRecOptService;
import com.sundot.airport.exam.common.service.ExamRecService;
import com.sundot.airport.exam.common.service.ExamService;
import com.sundot.airport.exam.common.service.TestPaperService;
import com.sundot.airport.exam.domain.*;
import com.sundot.airport.exam.enums.CloudSchoolBizExceptionEnum;
import com.sundot.airport.exam.logic.eighteen.model.params.Get18ExamIntroParams;
import com.sundot.airport.exam.logic.eighteen.model.params.Get18ExamRecordListParams;
import com.sundot.airport.exam.logic.eighteen.model.params.Get18ExamRecordParams;
import com.sundot.airport.exam.logic.eighteen.model.params.SubmitExamParam;
import com.sundot.airport.exam.logic.eighteen.model.result.Get18ExamIntroResult;
import com.sundot.airport.exam.logic.eighteen.model.result.ItemIn18ExamRecordResult;
import com.sundot.airport.exam.logic.eighteen.model.result.SubmitExamResult;
import com.sundot.airport.exam.logic.eighteen.model.result.subresult.ItemIn18ExamRecordListResult;
import com.sundot.airport.exam.logic.eighteen.model.result.subresult.OptionIn18ExamRec;
import com.sundot.airport.exam.logic.eighteen.model.result.subresult.QuestionIn18ExamRec;
import com.sundot.airport.exam.logic.eighteen.service.EighteenService;
import com.sundot.airport.exam.mapper.DemoMapper;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.stream.Collectors;

/**
 * <b>功能名：</b>EighteenServiceImpl<br>
 * <b>说明：</b> 十八大实现类 <br>
 * <b>著作权：</b> Copyright (C) 2020 HUIFANEDU  CORPORATION<br>
 * <b>修改履历：
 *
 * @author 2021-06-04 huifan
 */
@Service
public class EighteenServiceImpl extends ServiceImpl<DemoMapper, BaseEntity> implements EighteenService {

    private static final Logger log = LoggerFactory.getLogger(EighteenServiceImpl.class);
    final int FINISH_RADIO = 100;
    @Resource
    private ExamRecService examRecService;
    @Resource
    private ExamService examService;
    @Resource
    private TestPaperService testPaperService;
    @Resource
    private ExamRecordManager examRecordManager;
    @Resource
    private GradeManager gradeManager;
    @Resource
    private ExamRecOptService examRecOptService;


    /**
     * <b>方法名: </b> getExamCountMap <br>
     * <b>说明: </b> 获取考试与考试次数的映射关系 <br>
     *
     * @param uid        String 用户ID
     * @param pcIds      List<String> 课程ID列表
     * @param clientType String 客户端类型
     * @return Map<String, Integer>
     * <b>修改履历: </b>
     * @author 2021/7/1 Mokou
     */
    private Map<String, Integer> getExamCountMap(String uid, List<String> pcIds, String clientType) {
        log.info(String.format("EighteenServiceImpl.getExamCountMap uid=%s clientType=%s pcIds=%s", uid, clientType, pcIds.toString()));
        Map<String, Integer> examCountMap = new HashMap<>((int) (pcIds.size() / 0.75) + 1);
        List<ExamCountResult> examCountList = examRecService.getCountExamRec(uid, pcIds, clientType);
        for (ExamCountResult countResult : examCountList) {
            examCountMap.put(countResult.getPcId(), countResult.getCount());
        }
        return examCountMap;
    }


    @Override
    public HttpResult<Get18ExamIntroResult> getExamIntro(Get18ExamIntroParams param) {
        log.info(String.format("EighteenServiceImpl.getExamIntro param=%s", param.toString()));
        Optional<Exam> examOpt = examService.get(param.getId());
        CheckUtil.boolCheck(!examOpt.isPresent(), CloudSchoolBizExceptionEnum.EXAM_NOT_FOUND);

        Get18ExamIntroResult res = new Get18ExamIntroResult();
        // 考试基本信息
        BeanUtil.copyProperties(examOpt.get(), res);

        Optional<TestPaper> testPaperOpt = testPaperService.get(examOpt.get().getTpId());
        CheckUtil.boolCheck(!testPaperOpt.isPresent(), CloudSchoolBizExceptionEnum.TESTPAPER_NOT_FOUND);
        // 考试总分
        res.setTotalScore(testPaperOpt.get().getTpTotalScore());
        // 考试总题目数
        res.setQuestionCount(testPaperOpt.get().getTpQuesNum());

        return HttpResult.success(res);
    }

    @Override
    public HttpResult<PageData<ItemIn18ExamRecordListResult>> getExamRecordList(Get18ExamRecordListParams param) {
        log.info(String.format("EighteenServiceImpl.getExamRecordList param=%s", param.toString()));
        ExamRecPageParam pageParam = new ExamRecPageParam();
        BeanUtil.copyProperties(param, pageParam);

        pageParam.setUsrId(SecurityUtils.getUserId().toString());

        PageInfo<ExamRec> pageInfo = examRecService.pageList(pageParam);
        // 组装分页数据
        PageData<ItemIn18ExamRecordListResult> pageData = new PageData<>(pageInfo);
        pageData.setList(pageInfo
                .getList()
                .stream()
                .map(res -> new ItemIn18ExamRecordListResult() {
                    {
                        // 将查询结果转换为Result对象
                        BeanUtils.copyProperties(res, this);
                        Integer score = res.getErScore();
                        Integer certTh = res.getErExCertTh();
                        if (res.getErExEnableCert() && score != null && certTh != null && score >= certTh) {
                            this.setGetCert(true);
                        }
                    }
                })
                .collect(Collectors.toList()));
        return HttpResult.success(pageData);
    }

    @Override
    public HttpResult<ItemIn18ExamRecordResult> getExamRecord(Get18ExamRecordParams param) {
        log.info(String.format("EighteenServiceImpl.getExamRecord param=%s", param.toString()));
        GetExamRecordParam commonParam = new GetExamRecordParam();
        BeanUtil.copyProperties(param, commonParam);
        // 查询完整的测试记录、题目、用户答案
        GetExamRecordResult commonRes = examRecordManager.getExamRecord(commonParam);
        ItemIn18ExamRecordResult httpRes = new ItemIn18ExamRecordResult();
        BeanUtil.copyProperties(commonRes, httpRes);

//        if (commonRes.getErScore() != null && commonRes.getErExCertTh() != null && commonRes.getErScore() >= commonRes.getErExCertTh()) {
//            // 用户得分 与 证书门槛都有效时 返回入证书相关数据
//            CertDataIn18ExamRecordResult certData = new CertDataIn18ExamRecordResult();
//            BeanUtil.copyProperties(commonRes, certData);
//            // 发放时间 即考试记录更新时间
//            certData.setCertTime(commonRes.getUpdateTime());
//            httpRes.setCertData(certData);
//        }

        // 将common查询结果类转换为请求返回结果类
        List<ExamRecordQuestion> questionList = commonRes.getQuestion();
        httpRes.setQuestion(questionList.stream().map(ques -> new QuestionIn18ExamRec() {
            {
                BeanUtil.copyProperties(ques, this);
                this.setOption(ques.getOption().stream().map(opt -> new OptionIn18ExamRec() {
                    {
                        BeanUtil.copyProperties(opt, this);
                    }
                }).collect(Collectors.toList()));
                //  将选项中的回答正确情况提出至问题
                this.setEroCorrectStatus(examRecordManager.getCorrectStatusByOpts(ques.getOption()));
            }
        }).collect(Collectors.toList()));

        httpRes.setEnableReExam(true);
        // 1. 获取当前用户的信息
        //CacheUserInfo cacheUserInfo = ThreadContext.get();
        //checkEnableReExam(Objects.isNull(cacheUserInfo), CheckExceptionEnum.USER_ERROR, httpRes);
        if (!httpRes.getEnableReExam()) {
            return HttpResult.success(httpRes);
        }
        // 2. 检查产品课程
//        Optional<ProdCourse> prodCourseOpt = prodCourseService.get(httpRes.getPcId());
//        checkEnableReExam(!prodCourseOpt.isPresent(), CloudSchoolBizExceptionEnum.PROD_COURSE_NOT_FOUND, httpRes);
//        if (!httpRes.getEnableReExam()) {
//            return HttpResult.success(httpRes);
//        }
//
//        Optional<Prod> prodOpt = prodService.get(prodCourseOpt.get().getPrId());
//        checkEnableReExam(!prodOpt.isPresent(), CloudSchoolBizExceptionEnum.PROD_NOT_FOUND, httpRes);
//        if (!httpRes.getEnableReExam()) {
//            return HttpResult.success(httpRes);
//        }
        // 3. 检查考试信息
        Optional<Exam> examOpt = examService.get(httpRes.getErExId());
        checkEnableReExam(!examOpt.isPresent(), CloudSchoolBizExceptionEnum.EXAM_NOT_FOUND, httpRes);
        log.info(String.format("ExamOnlineServiceImpl.applyExam:param=%s,examCount=%d",
                param, examOpt.get().getExExamCount()));
        if (!httpRes.getEnableReExam()) {
            return HttpResult.success(httpRes);
        }
        // 4. 检查是否还有考试次数
        if (examOpt.get().getExExamCount() > 0) {
            // 统计某个课程用户的考试记录次数
            long examCount = examRecService.byPcIdUsrIdEnableCount(httpRes.getPcId(), SecurityUtils.getUserId().toString(), true);
            checkEnableReExam(examCount >= examOpt.get().getExExamCount(), CloudSchoolBizExceptionEnum.EXAM_COUNT_TO_UPPER_LIMIT, httpRes);
        }
        return HttpResult.success(httpRes);
    }

    private void checkEnableReExam(Boolean flag, AbstractBaseExceptionEnum exceptionEnum, ItemIn18ExamRecordResult httpRes) {
        if (flag && httpRes.getEnableReExam()) {
            httpRes.setEnableReExam(false);
            httpRes.setReExamMsg(exceptionEnum.getMessage());
        }
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public HttpResult<SubmitExamResult> submitExam(SubmitExamParam param) {
        log.info(String.format("EighteenServiceImpl.submitExam param=%s", param.toString()));
        String clientType = param.getClientType();
        String exId = param.getExId();
        String erId = param.getErId();
        Integer erExamTime = param.getErExamTime();

        List<UserOption> options = param.getOptions().stream().map(item -> new UserOption() {
            {
                BeanUtil.copyProperties(item, this);
            }
        }).collect(Collectors.toList());

        // 判卷结果
        GradeResult gradeRes = gradeManager.grade(erId, options);
        // 用户得分
        int userScore = gradeRes.getUserScore();
        // 用户答对题目数
        int correctCount = gradeRes.getCorrectCount();
        // 用户部分答对题目数
        int partCorrectCount = gradeRes.getPartCorrectCount();
        // 用户答错题目数
        int incorrectCount = gradeRes.getIncorrectCount();
        // 用户未作答题目数
        int notFilledCount = gradeRes.getNotFilledCount();
        // 题目总数
        int questionCount = gradeRes.getQuestionCount();
        // 需要更新的用户答案快照
        List<ExamRecOpt> userOptionRecList = gradeRes.getExamRecOptList();

        // 1 用erId查所属课程是否有属于系统 属于则记录考试情况
        // 1.1 查询考试快照
        Optional<ExamRec> examRec = examRecService.get(erId);
        CheckUtil.boolCheck(!examRec.isPresent(), CloudSchoolBizExceptionEnum.EXAMREC_NOT_FOUND);

//        // 1.2 通过考试快照查询考试所属课程
//        Optional<ProdCourse> prodCourseOpt = prodCourseService.get(examRec.get().getPcId());
//        CheckUtil.boolCheck(!prodCourseOpt.isPresent(), CloudSchoolBizExceptionEnum.PROD_COURSE_NOT_FOUND);
//
//        // 1.3 有父级课程则认为属于系统 需要记录系统考试情况
//        if (prodCourseOpt.get().getPcParentId() != null && prodCourseOpt.get().getPcParentId().length() > 0) {
//            updateUserCourseStatus(prodCourseOpt.get().getPcParentId(), clientType, userScore, examRec.get());
//        }

        // 2 更新用户考试快照数据
        // 得分
        examRec.get().setErScore(userScore);
        // 正确题目数
        examRec.get().setErBingoCount(correctCount);
        // 正确率 小数四舍五入
        examRec.get().setErCorrect(Math.round(correctCount * 100F / questionCount));
        // 部分答对题目数
        examRec.get().setErPartBingoCount(partCorrectCount);
        // 答错题目数
        examRec.get().setErIncorrectCount(incorrectCount);
        // 未作答题目数
        examRec.get().setErNotFilledCount(notFilledCount);
        // 考试用时
        examRec.get().setErExamTime(erExamTime);
        // 查询并保存评语
        // Optional<CertRating> certRatingOpt = certRatingService.byExIdAndScoreFindList(exId, userScore);
        // certRatingOpt.ifPresent(certRating -> examRec.get().setErCrContent(certRating.getCrContent()));
        // 启用本条快照
        examRec.get().setEnableStatus(true);
        examRecService.update(examRec.get());

        // 3 更新考试管理表中的参考人数
        updateExamPeopleNum(exId);

        // 4 更新用户选项快照
        if (userOptionRecList.size() > 0) {
            userOptionRecList.forEach(orl -> examRecOptService.updateEroConnNo(orl));
        }

        SubmitExamResult httpRes = new SubmitExamResult();
        httpRes.setErId(examRec.get().getErId());
        return HttpResult.success(httpRes);
    }

    /**
     * <b>方法名: </b> updateExamPeopleNum <br>
     * <b>说明: </b> 更新考试管理表中的参考人数 <br>
     *
     * @param exId String 考试ID
     *             <b>修改履历: </b>
     * @author 2021/7/9 Mokou
     */
    private void updateExamPeopleNum(String exId) {
        log.info(String.format("EighteenServiceImpl.updateExamPeopleNum exId=%s", exId));
        long enableUserExamCount = examRecService.countExamNumEnable(SecurityUtils.getUserId().toString(), exId);
        if (enableUserExamCount == 1) {
            // 用户第一次参加该考试, 参考人数+1
            Optional<Exam> examOpt = examService.get(exId);
            CheckUtil.boolCheck(!examOpt.isPresent(), CloudSchoolBizExceptionEnum.EXAM_NOT_FOUND);
            examOpt.get().setExPeople(examOpt.get().getExPeople() + 1);
            examService.update(examOpt.get());
        }
    }

    /**
     * <b>方法名: </b> updateUserCourseStatus <br>
     * <b>说明: </b> 更新用户学习系统考试状态 <br>
     *
     * @param parentId   String 考试所属一级课程ID
     * @param clientType String 客户端类型
     * @param totalScore Integer 用户得分
     * @param examRec    ExamRec 考试记录快照
     *                   <b>修改履历: </b>
     * @author 2021/7/8 Mokou
     */
    private void updateUserCourseStatus(String parentId, String clientType, int totalScore, ExamRec examRec) {
//        log.info(String.format(
//                "EighteenServiceImpl.updateUserCourseStatus parentId=%s clientType=%s totalScore=%d examRec=%s",
//                parentId, clientType, totalScore, examRec.toString())
//        );
//        String uid = SecurityContextHolder.getUserId().toString();
//        Optional<UserCourseStatus> userCourseStatusOpt = userCourseStatusService.getByPcId(parentId, uid, clientType);
//        if (userCourseStatusOpt.isPresent()) {
//            // 更新考试次数
//            userCourseStatusOpt.get().setUcsExamNum(userCourseStatusOpt.get().getUcsExamNum() + 1);
//            // 更新最高得分 规则
//            // 一、 分数高最优先
//            // 二、 同分数优先取及格;
//            // 三、 未开启证书按照不及格处理
//
//            // 原最高分
//            Integer oldMaxScore = userCourseStatusOpt.get().getUcsExamMaxScore();
//            oldMaxScore = oldMaxScore == null ? 0 : oldMaxScore;
//
//            if (oldMaxScore < totalScore) {
//                // 新的分数高 优先取高 同时更新及格分数线
//                userCourseStatusOpt.get().setUcsExamMaxScore(totalScore);
//                userCourseStatusOpt.get().setExCertTh(examRec.getErExCertTh());
//            } else if (oldMaxScore == totalScore) {
//                // 同分数 优先取及格 未开启证书按照不及格处理
//                // 代码逻辑 同分数时 保留最低的及格分数线
//                Integer oldCertTh = userCourseStatusOpt.get().getExCertTh();
//                Integer newCertTh = ExamConstant.DISABLE_CERT_TH;
//                if (examRec.getErExEnableCert()) {
//                    newCertTh = examRec.getErExCertTh();
//                }
//                if (newCertTh < oldCertTh) {
//                    userCourseStatusOpt.get().setExCertTh(newCertTh);
//                }
//            }
//            userCourseStatusService.update(userCourseStatusOpt.get());
        //  } else {
        // 无考试记录 初始化一条
//            UserCourseStatus newStatus = new UserCourseStatus();
//            newStatus.setUcsExamNum(1);
//            newStatus.setUcsExamMaxScore(totalScore);
//            newStatus.setUcsClientType(clientType);
//            newStatus.setUsrId(uid);
//            newStatus.setPcId(parentId);
//            if (examRec.getErExEnableCert()) {
//                newStatus.setExCertTh(examRec.getErExCertTh());
//            } else {
//                newStatus.setExCertTh(ExamConstant.DISABLE_CERT_TH);
//            }
//            userCourseStatusService.insert(newStatus);
        //  }
    }
}
