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

import com.sundot.airport.common.utils.SecurityUtils;
import com.sundot.airport.exam.cache.ConcurrentLockHandler;
import com.sundot.airport.exam.common.CheckUtil;
import com.sundot.airport.exam.common.HttpResult;
import com.sundot.airport.exam.common.manager.TestPaperManager;
import com.sundot.airport.exam.common.model.result.QuesOptResult;
import com.sundot.airport.exam.common.model.result.TestPaperQuesResult;
import com.sundot.airport.exam.common.service.*;
import com.sundot.airport.exam.domain.*;
import com.sundot.airport.exam.enums.CloudSchoolBizExceptionEnum;
import com.sundot.airport.exam.logic.eighteen.model.params.ExamRecAddParam;
import com.sundot.airport.exam.logic.eighteen.model.result.ExamGetResult;
import com.sundot.airport.exam.logic.eighteen.model.result.ExamQuesOptResult;
import com.sundot.airport.exam.logic.eighteen.model.result.ExamQuestionResult;
import com.sundot.airport.exam.logic.eighteen.service.ExamOnlineService;
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.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Optional;
import java.util.stream.Collectors;

/**
 * <b>功能名：ExamOnlineServiceImpl</b><br>
 * <b>说明：</b> 在线测试业务处理类 <br>
 * <b>著作权：</b> Copyright (C) 2021 HUIFANEDU  CORPORATION<br>
 * <b>修改履历：</b><br>
 *
 * @author 2021-06-30 liangxiao
 */
@Service
public class ExamOnlineServiceImpl implements ExamOnlineService {

    private static final Logger log = LoggerFactory.getLogger(ExamOnlineServiceImpl.class);

    @Resource
    private ExamRecService examRecService;
    @Resource
    private ExamRecOptService examRecOptService;
//    @Resource
//    private ProdService prodService;
//    @Resource
//    private ProdCourseService prodCourseService;
    @Resource
    private ExamService examService;
    @Resource
    private TestPaperService testPaperService;
    @Resource
    private TestPaperManager testPaperManager;
    @Resource
    private ConcurrentLockHandler concurrentLockHandler;
//    @Resource
//    private BaseUserConsumer baseUserConsumer;

    @Override
    @Transactional(rollbackFor = Exception.class)
    public HttpResult<ExamGetResult> applyExam(String token, ExamRecAddParam param) {
        // 3. 检查考试信息
        Optional<Exam> examOpt = examService.get(param.getId());
        CheckUtil.boolCheck(!examOpt.isPresent(), CloudSchoolBizExceptionEnum.EXAM_NOT_FOUND);

        log.info(String.format("ExamOnlineServiceImpl.applyExam:token=%s,param=%s,examCount=%d",
                token, param, examOpt.get().getExExamCount()));
        // 4. 检查是否还有考试次数
        if (examOpt.get().getExExamCount() > 0) {
            // 统计某个课程用户的考试记录次数
            long examCount = examRecService.byPcIdUsrIdEnableCount(param.getPcId(), SecurityUtils.getUserId().toString(), true);
            CheckUtil.boolCheck(examCount >= examOpt.get().getExExamCount(), CloudSchoolBizExceptionEnum.EXAM_COUNT_TO_UPPER_LIMIT);
        }

        String lockKey = buildLockKey(param.getPcId(), examOpt.get().getExId(), SecurityUtils.getUserId().toString());

        try {
            // 5. 获取锁
            boolean lock = concurrentLockHandler.tryLock(lockKey, "" + System.currentTimeMillis());
            CheckUtil.boolCheck(!lock, CloudSchoolBizExceptionEnum.EXAM_SERVICE_BUSY);

            // 6. 根据考试信息查询 试卷、试题等信息
            Optional<TestPaper> testPaperOpt = testPaperService.get(examOpt.get().getTpId());
            CheckUtil.boolCheck(!testPaperOpt.isPresent(), CloudSchoolBizExceptionEnum.TEST_PAPER_NOT_FOUND);

            // 根据试卷业务id列表查询关联的题目信息（包含题干、计分规则、选项）
            List<TestPaperQuesResult> quesList = testPaperManager
                    .byTpIdsFindAndBuildResult(Collections.singletonList(testPaperOpt.get().getTpId()))
                    .getOrDefault(testPaperOpt.get().getTpId(), Collections.emptyList());
            CheckUtil.listEmpty(quesList, CloudSchoolBizExceptionEnum.QUES_NOT_FOUND);

            // 7. 创建考试记录
            ExamRec examRec = beanCopyExamRec(param,
                    examOpt.get(), testPaperOpt.get());
            // 保存考试记录
            examRecService.insert(examRec);

            ArrayList<ExamRecOpt> batchInsertTemp = new ArrayList<>();

            // 8. 创建问题选项快照，并返回题目信息列表
            List<ExamQuestionResult> quesResList = quesList
                    .stream()
                    .map(ques -> {
                        // 选项结果列表
                        List<ExamQuesOptResult> optsResList = ques.getOption()
                                .stream()
                                .map(opt -> {
                                    // 复制题目信息到问题选项快照
                                    ExamRecOpt examRecOpt = beanCopyExamRecOpt(examRec, ques, opt);
                                    // 保存考试记录-题目信息
                                    batchInsertTemp.add(examRecOpt);

                                    // 拷贝选项信息
                                    ExamQuesOptResult optResult = new ExamQuesOptResult();
                                    BeanUtils.copyProperties(opt, optResult);
                                    return optResult;
                                })
                                .collect(Collectors.toList());

                        // 拷贝题目信息
                        ExamQuestionResult quesResult = new ExamQuestionResult();
                        BeanUtils.copyProperties(ques, quesResult);
                        // 设置题目选项
                        quesResult.setOptions(optsResList);
                        return quesResult;
                    })
                    .collect(Collectors.toList());
            // 批量插入数据
            examRecOptService.insertList(batchInsertTemp);

            // 拷贝考试信息
            ExamGetResult examGetResult = new ExamGetResult();
            BeanUtils.copyProperties(examOpt.get(), examGetResult);
            examGetResult.setQuestion(quesResList);
            examGetResult.setErId(examRec.getErId());
            return HttpResult.success(examGetResult);
        } catch (Exception e) {
            log.error(String.format("applyExam:获取考试信息异常:param=%s,userId=%s", param, SecurityUtils.getUserId()), e);
            return HttpResult.error(CloudSchoolBizExceptionEnum.EXAM_SERVICE_BUSY);
        } finally {
            concurrentLockHandler.releaseLock(lockKey);
        }
    }

    /**
     * <b>方法名: </b> beanCopyExamRec <br>
     * <b>说明: </b> 创建考试记录 <br>
     *
     * @param param         com.sundot.airport.logic.eighteen.model.params.ExamRecAddParam 在线测试用户获取考试基本信息和试题请求参数
//     * @param cacheUserInfo com.huifanedu.kernel.redis.entity.CacheUserInfo 缓存用户信息
//     * @param userInfo      com.sundot.airport.consumer.model.result.DirKgInfoResult 园长个人信息
//     * @param prodCourse    com.sundot.airport.exam.domain.ProdCourse 课程类
//     * @param prod          com.sundot.airport.exam.domain.Prod 产品库表
     * @param exam          com.sundot.airport.exam.domain.Exam 考试管理表
     * @param testPaper     com.sundot.airport.exam.domain.TestPaper 试卷表
     * @return com.sundot.airport.exam.domain.ExamRec 考试记录表类<br>
     * <b>修改履历: </b>
     * @author 2021/7/13 liangxiao
     */
    private ExamRec beanCopyExamRec(ExamRecAddParam param,
                                     Exam exam, TestPaper testPaper) {
        ExamRec examRec = new ExamRec();
        // 开始答题，但未交卷状态
        examRec.setEnableStatus(false);
        // 其它
        examRec.setErClientType(param.getClientType());
//        examRec.setPrId(prod.getPrId());
//        examRec.setPcId(prodCourse.getPcId());
        // 考试信息
        examRec.setErExId(exam.getExId());
        examRec.setErExName(exam.getExName());
        examRec.setErExBgImg(exam.getExBgImg());
        examRec.setErExDetailImg(exam.getExDetailImg());
        examRec.setErExExamTime(exam.getExExamTime());
        examRec.setErExExamCount(exam.getExExamCount());
        examRec.setErExEnableAns(exam.getExEnableAns());
        examRec.setErExEnableCert(exam.getExEnableCert());
        examRec.setErExCertTh(exam.getExCertTh());
        examRec.setErExCertName(exam.getExCertName());
        examRec.setErExCertBgImg(exam.getExCertBgImg());
        examRec.setErExCertQrCode(exam.getExCertQrCode());
        examRec.setErExCertShareRemark(exam.getExCertShareRemark());
        examRec.setErCrContent(null);
        // 试卷
        examRec.setErTpId(testPaper.getTpId());
        examRec.setErTpcName(null);
        examRec.setErTpName(testPaper.getTpName());
        examRec.setErTpQuesNum(testPaper.getTpQuesNum());
        examRec.setErTpTotalScore(testPaper.getTpTotalScore());
        // token获取的用户信息
        examRec.setUsrId(String.valueOf(SecurityUtils.getUserId()));
        examRec.setErUsrName(SecurityUtils.getUsername());
        // 院长用户信息
//        examRec.setErHeadImg(userInfo.getHeadImg());
//        examRec.setErKiId(userInfo.getKiId());
//        examRec.setErKiName(userInfo.getKiName());
//        examRec.setErKiNumber(userInfo.getKiNumber());
//        examRec.setErWzId(userInfo.getWzId());
//        examRec.setErWzName(userInfo.getWzName());
//        examRec.setErKiProvince(userInfo.getKiProvince());
//        examRec.setErKiProvinceCode(userInfo.getKiProvinceCode());
//        examRec.setErKiCity(userInfo.getKiCity());
//        examRec.setErKiCityCode(userInfo.getKiCityCode());
//        examRec.setErKiCounty(userInfo.getKiCounty());
//        examRec.setErKiCountyCode(userInfo.getKiCountyCode());
        return examRec;
    }

    /**
     * <b>方法名: </b> beanCopyExamRecOpt <br>
     * <b>说明: </b> 复制题目信息到问题选项快照 <br>
     *
     * @param examRec com.sundot.airport.exam.domain.ExamRec 考试记录表类
     * @param ques    com.sundot.airport.exam.common.model.result.TestPaperQuesResult 试卷题目计分表封装结果
     * @param opt     com.sundot.airport.exam.common.model.result.QuesOptResult 题目选项表封装结果
     * @return com.sundot.airport.exam.domain.ExamRecOpt 测试记录选项表实体类 <br>
     * <b>修改履历: </b>
     * @author 2021/7/13 liangxiao
     */
    private ExamRecOpt beanCopyExamRecOpt(ExamRec examRec, TestPaperQuesResult ques, QuesOptResult opt) {
        // 创建问题选项快照
        ExamRecOpt examRecOpt = new ExamRecOpt();
        examRecOpt.setErId(examRec.getErId());
        // 答题内容
        examRecOpt.setEroConnNo(null);
        // 题干信息
        examRecOpt.setEroQuId(ques.getQuId());
        examRecOpt.setEroTpqSort(ques.getSort());
        examRecOpt.setEroQuType(ques.getQuType());
        examRecOpt.setEroQcName(ques.getQcName());
        examRecOpt.setEroQuContent(ques.getQuContent());
        // 计分信息
        examRecOpt.setEroTpqTotalScore(ques.getTpqTotalScore());
        examRecOpt.setEroTpqCompType(ques.getTpqCompType());
        examRecOpt.setEroTpqLeftScore(ques.getTpqLeftScore());
        examRecOpt.setEroTpqRightScore(ques.getTpqRightScore());
        // 选项信息
        examRecOpt.setEroSort(opt.getSort());
        examRecOpt.setEroQoCorrect(opt.getQoCorrect());
        examRecOpt.setEroQoOptionType(opt.getQoOptionType());
        examRecOpt.setEroQoOption(opt.getQoOption());
        examRecOpt.setEroQoConnSort(opt.getQoConnSort());
        examRecOpt.setEroQoConnOptType(opt.getQoConnOptType());
        examRecOpt.setEroQoConnOpt(opt.getQoConnOpt());
        return examRecOpt;
    }

    /**
     * <b>方法名: </b> buildLockKey <br>
     * <b>说明: </b> 构建考试记录的rediskey <br>
     *
     * @param pcId  java.lang.String 产品课程id
     * @param exId  java.lang.String 考试id
     * @param usrId java.lang.String 用户id
     * @return java.lang.String<br>
     * <b>修改履历: </b>
     * @author 2021/7/5 liangxiao
     */
    private String buildLockKey(String pcId, String exId, String usrId) {
        return String.format("%s:%s:%s", pcId, exId, usrId);
    }
}
