package ink.wgink.module.examine.service.question.impl;

import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import ink.wgink.common.base.DefaultBaseService;
import ink.wgink.exceptions.RemoveException;
import ink.wgink.exceptions.SearchException;
import ink.wgink.module.examine.dao.question.IQuestionDao;
import ink.wgink.module.examine.enums.question.QuestionChoiceTypeEnum;
import ink.wgink.module.examine.enums.question.QuestionTypeEnum;
import ink.wgink.module.examine.pojo.dtos.question.QuestionDTO;
import ink.wgink.module.examine.pojo.dtos.question.QuestionOptionsDTO;
import ink.wgink.module.examine.pojo.dtos.question.QuestionTypeQuestionDTO;
import ink.wgink.module.examine.pojo.pos.question.QuestionPO;
import ink.wgink.module.examine.pojo.vos.question.QuestionVO;
import ink.wgink.module.examine.service.question.IQuestionOptionsService;
import ink.wgink.module.examine.service.question.IQuestionService;
import ink.wgink.module.examine.service.question.IQuestionTypeQuestionService;
import ink.wgink.pojo.ListPage;
import ink.wgink.pojo.result.SuccessResultList;
import ink.wgink.util.ArrayListUtil;
import ink.wgink.util.UUIDUtil;
import ink.wgink.util.map.HashMapUtil;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.*;

/**
 * @ClassName: QuestionServiceImpl
 * @Description: 试题管理
 * @Author: WenG
 * @Date: 2020-09-09 21:00
 * @Version: 1.0
 **/
@Service
public class QuestionServiceImpl extends DefaultBaseService implements IQuestionService {

    @Autowired
    private IQuestionDao questionDao;
    @Autowired
    private IQuestionOptionsService questionOptionsService;
    @Autowired
    private IQuestionTypeQuestionService questionTypeQuestionService;

    @Override
    public void save(QuestionVO questionVO) throws Exception {
        saveQuestionInfo(null, questionVO);
    }

    @Override
    public void saveByToken(String token, QuestionVO questionVO) throws Exception {
        saveQuestionInfo(token, questionVO);
    }

    @Override
    public String saveReturnId(QuestionVO questionVO) throws Exception {
        return saveQuestionInfo(null, questionVO);
    }

    @Override
    public String saveByTokenReturnId(String token, QuestionVO questionVO) throws Exception {
        return saveQuestionInfo(token, questionVO);
    }

    /**
     * 新增试题管理
     *
     * @param token
     * @param questionVO
     * @throws Exception
     */
    private String saveQuestionInfo(String token, QuestionVO questionVO) throws Exception {
        String questionId = saveQuestionInfoReturnId(token, questionVO);
        boolean hasOption = StringUtils.equals(questionVO.getType(), QuestionTypeEnum.CHOICE.getValue())
                || StringUtils.equals(questionVO.getType(), QuestionTypeEnum.TURE_OR_FALSE.getValue());
        if (!hasOption) {
            return questionId;
        }
        // 删除原有试题类型
        questionOptionsService.save(questionId, questionVO.getOptions());
        // 新增试题类型
        questionTypeQuestionService.save(questionId, Arrays.asList(questionVO.getQuestionType().split(",")));
        return questionId;
    }

    /**
     * 新增试题管理
     *
     * @param token
     * @param questionVO
     * @return questionId
     * @throws Exception
     */
    private String saveQuestionInfoReturnId(String token, QuestionVO questionVO) throws Exception {
        questionVO.setSubject(questionVO.getSubject().replaceAll("\\s", ""));
        QuestionPO questionPO = getPO(questionVO.getSubject());
        if (questionPO != null) {
            throw new SearchException("题目已经存在");
        }
        String questionId = UUIDUtil.getUUID();
        Map<String, Object> params = HashMapUtil.beanToMap(questionVO);
        params.put("questionId", questionId);
        if (token != null) {
            setAppSaveInfo(token, params);
        } else {
            setSaveInfo(params);
        }
        questionDao.save(params);
        return questionId;
    }

    @Override
    public void remove(List<String> ids) throws RemoveException {
        removeQuestionInfo(null, ids);
    }

    @Override
    public void removeByToken(String token, List<String> ids) throws RemoveException {
        removeQuestionInfo(token, ids);
    }

    /**
     * 删除试题管理
     *
     * @param token
     * @param ids
     */
    private void removeQuestionInfo(String token, List<String> ids) {
        Map<String, Object> params = getHashMap(3);
        params.put("questionIds", ids);
        if (token != null) {
            setAppUpdateInfo(token, params);
        } else {
            setUpdateInfo(params);
        }
        questionDao.remove(params);
    }

    @Override
    public void delete(List<String> ids) throws RemoveException {
        Map<String, Object> params = getHashMap(3);
        params.put("questionIds", ids);
        questionDao.delete(params);
    }

    @Override
    public void update(String questionId, QuestionVO questionVO) throws Exception {
        updateInfo(null, questionId, questionVO);
    }

    @Override
    public void updateByToken(String token, String questionId, QuestionVO questionVO) throws Exception {
        updateInfo(token, questionId, questionVO);
    }

    /**
     * 修改试题管理
     *
     * @param token
     * @param questionId
     * @param questionVO
     */
    private void updateInfo(String token, String questionId, QuestionVO questionVO) throws Exception {
        Map<String, Object> params = HashMapUtil.beanToMap(questionVO);
        params.put("questionId", questionId);
        if (token != null) {
            setAppUpdateInfo(token, params);
        } else {
            setUpdateInfo(params);
        }
        questionDao.update(params);
        // 判断是否更新选项
        boolean hasOption = StringUtils.equals(questionVO.getType(), QuestionTypeEnum.CHOICE.getValue())
                || StringUtils.equals(questionVO.getType(), QuestionTypeEnum.TURE_OR_FALSE.getValue());
        if (!hasOption) {
            return;
        }
        // 删除原有试题类型
        questionOptionsService.save(questionId, questionVO.getOptions());
        // 新增试题类型
        questionTypeQuestionService.save(questionId, Arrays.asList(questionVO.getQuestionType().split(",")));
    }

    private QuestionPO getPO(Map<String, Object> params) {
        return questionDao.getPO(params);
    }

    public QuestionPO getPO(String subject) {
        Map<String, Object> params = getHashMap(2);
        params.put("subject", subject);
        return getPO(params);
    }

    @Override
    public QuestionDTO getById(String questionId) throws SearchException {
        Map<String, Object> params = super.getHashMap(1);
        params.put("questionId", questionId);
        QuestionDTO questionDTO = questionDao.get(params);
        boolean hasOption = StringUtils.equals(questionDTO.getType(), QuestionTypeEnum.CHOICE.getValue())
                || StringUtils.equals(questionDTO.getType(), QuestionTypeEnum.TURE_OR_FALSE.getValue());
        if (hasOption) {
            List<QuestionOptionsDTO> questionOptionsDTOs = questionOptionsService.listByQuestionId(questionId);
            questionDTO.setOptions(questionOptionsDTOs);
        }
        List<QuestionTypeQuestionDTO> questionTypeQuestionDTOS = questionTypeQuestionService.listByQuestionId(questionId);
        setQuestionTypeName(questionDTO, questionTypeQuestionDTOS);
        return questionDTO;
    }


    @Override
    public List<QuestionDTO> list(Map<String, Object> params) throws SearchException {
        List<QuestionDTO> questionDTOs = questionDao.list(params);
        if (!questionDTOs.isEmpty()) {
            List<String> questionIds = ArrayListUtil.listBeanStringIdValue(questionDTOs, "questionId", QuestionDTO.class);
            List<QuestionTypeQuestionDTO> questionTypeQuestionDTOS = questionTypeQuestionService.listByQuestionIds(questionIds);
            setQuestionTypeName(questionDTOs, questionTypeQuestionDTOS);
        }
        return questionDTOs;
    }

    @Override
    public List<QuestionDTO> listByIds(List<String> questionIds) {
        Map<String, Object> params = getHashMap(2);
        params.put("questionIds", questionIds);
        return list(params);
    }

    @Override
    public SuccessResultList<List<QuestionDTO>> listPage(ListPage page) throws SearchException {
        PageHelper.startPage(page.getPage(), page.getRows());
        List<QuestionDTO> questionDTOs = list(page.getParams());
        PageInfo<QuestionDTO> pageInfo = new PageInfo<>(questionDTOs);
        return new SuccessResultList<>(questionDTOs, pageInfo.getPageNum(), pageInfo.getTotal());
    }

    @Override
    public Integer count(Map<String, Object> params) throws SearchException {
        Integer count = questionDao.count(params);
        return count == null ? 0 : count;
    }

    @Override
    public List<String> listRandomIdByRandomCountAndTypeAndChoiceType(int randomCount, QuestionTypeEnum questionTypeEnum, QuestionChoiceTypeEnum questionChoiceTypeEnum) {
        Map<String, Object> params = getHashMap(4);
        params.put("type", questionTypeEnum.getValue());
        params.put("choiceType", questionChoiceTypeEnum == null ? null : questionChoiceTypeEnum.getValue());
        List<String> questionIds = questionDao.listIds(params);
        // 试题数小于随机总数，返回全部试题ID
        if (questionIds.size() <= randomCount) {
            return questionIds;
        }
        Random random = new Random(System.currentTimeMillis());
        Map<Integer, String> randomMap = new HashMap<>(randomCount * 2);
        while (randomMap.size() < randomCount) {
            int randomNumber = random.nextInt(questionIds.size());
            randomMap.put(randomNumber, questionIds.get(randomNumber));
        }
        List<String> randomQuestionIds = new ArrayList<>();
        for (Map.Entry<Integer, String> kv : randomMap.entrySet()) {
            randomQuestionIds.add(kv.getValue());
        }
        return randomQuestionIds;
    }

    private List<QuestionPO> listPOByIds(List<String> questionIds) {
        Map<String, Object> params = getHashMap(2);
        params.put("questionIds", questionIds);
        return questionDao.listPO(params);
    }

    /**
     * 设置试题类型名称
     *
     * @param questionDTOs
     * @param questionTypeQuestionDTOS
     */
    private void setQuestionTypeName(List<QuestionDTO> questionDTOs, List<QuestionTypeQuestionDTO> questionTypeQuestionDTOS) {
        questionDTOs.forEach(questionDTO -> {
            setQuestionTypeName(questionDTO, questionTypeQuestionDTOS);
        });
    }

    /**
     * 设置试题类型名称
     *
     * @param questionDTO
     * @param questionTypeQuestionDTOS
     */
    private void setQuestionTypeName(QuestionDTO questionDTO, List<QuestionTypeQuestionDTO> questionTypeQuestionDTOS) {
        String questionType = "";
        String questionTypeName = "";
        for (QuestionTypeQuestionDTO questionTypeQuestionDTO : questionTypeQuestionDTOS) {
            if (!StringUtils.equals(questionDTO.getQuestionId(), questionTypeQuestionDTO.getQuestionId())) {
                continue;
            }
            if (!StringUtils.isBlank(questionType)) {
                questionType += ",";
                questionTypeName += ",";
            }
            questionType += questionTypeQuestionDTO.getQuestionTypeId();
            questionTypeName += questionTypeQuestionDTO.getTypeSummary();
        }
        questionDTO.setQuestionType(questionType);
        questionDTO.setQuestionTypeName(questionTypeName);
    }

}