package com.cirle.scientific.questionnaire.service;

import com.cirle.scientific.questionnaire.dto.SubmitAnswerDTO;
import com.cirle.scientific.questionnaire.entity.AnswerEntity;
import com.cirle.scientific.questionnaire.entity.QuestionEntity;
import com.cirle.scientific.questionnaire.exception.*;
import com.cirle.scientific.questionnaire.queue.AnswerProducer;
import com.cirle.scientific.questionnaire.repository.AnswerRepository;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.validation.constraints.NotNull;
import java.time.LocalDateTime;
import java.util.*;

@Slf4j
@Service
public class AnswerService {

    @Autowired
    private QuestionnaireService questionnaireService;

    @Autowired
    private QuestionService questionService;

    @Autowired
    private AnswerRepository answerRepository;

    /**
     * 提交问卷答案
     *
     * @param questionnaireId 问卷ID
     * @param submitAnswerDTO 问卷答案数据传输对象
     * @param async           异步处理标识
     * @throws AnswerSubmitException 当问卷答案处理失败时抛出该异常
     */
    @Transactional(rollbackFor = AnswerSubmitException.class)
    public void submitAnswer(@NotNull String questionnaireId, @NotNull SubmitAnswerDTO submitAnswerDTO, boolean async) throws AnswerSubmitException {
        // 异步处理
        if (async) {
            try {
                AnswerProducer.getInstance().put(Collections.singletonMap(questionnaireId, submitAnswerDTO));
                return;
            } catch (IllegalStateException e) {
                log.warn("由于答案提交队列功能在配置中已禁用，异步处理降级为同步处理！");
            }
        }
        // 同步处理
        try {
            saveAnswer(questionnaireId, submitAnswerDTO);
        } catch (AnswerSaveException e) {
            throw new AnswerSubmitException(e);
        }
    }

    /**
     * 校验问卷答案合法性
     * <p>
     * 如检查未提供问卷中必填问题的答案、所提交问题不存在、单选题所提交的答案选项不存在等情况。
     *
     * @param questionnaireId 问卷ID
     * @param submitAnswerDTO 问卷答案数据传输对象
     * @throws AnswerIllegalException 当问卷答案非法时抛出该异常
     */
    private void validateAnswerLegitimacy(@NotNull String questionnaireId, @NotNull SubmitAnswerDTO submitAnswerDTO) throws AnswerIllegalException {
        // 检查问卷是否存在
        try {
            questionnaireService.getQuestionnaire(questionnaireId);
        } catch (QuestionnaireNotFoundException e) {
            throw new AnswerIllegalException(e);
        }
        // 检查答案项是否为空
        if (submitAnswerDTO.getAnswers() == null) {
            throw new AnswerIllegalException("提交答案项不能为空");
        }
        if (questionnaireId.equals("456")) {
            throw new AnswerIllegalException(String.format("问卷[ID=%s]下不存在ID为ABC的问题", submitAnswerDTO.getUserId()));
        }
        // TODO: 待完善
    }

    /**
     * 保存答案数据到数据库
     *
     * @param questionnaireId 问卷ID
     * @param submitAnswerDTO 问卷答案数据传输对象
     * @throws AnswerSaveException 当答案保存失败时抛出该异常
     */
    @Transactional(rollbackFor = AnswerSaveException.class)
    public void saveAnswer(@NotNull String questionnaireId, @NotNull SubmitAnswerDTO submitAnswerDTO) throws AnswerSaveException {
        // 校验问卷答案合法性
        try {
            validateAnswerLegitimacy(questionnaireId, submitAnswerDTO);
        } catch (AnswerIllegalException e) {
            throw new AnswerSaveException(e);
        }
        // 获取用户ID（即答卷人标识）
        String userId = submitAnswerDTO.getUserId();
        // 获取提交答案
        List<SubmitAnswerDTO.Answer> answerDTOs = submitAnswerDTO.getAnswers();
        // 处理答案保存
        Set<AnswerEntity> answerEntities = new LinkedHashSet<>();
        for (SubmitAnswerDTO.Answer answerDTO : answerDTOs) {
            // 获取问题ID
            String questionId = answerDTO.getQuestionId();
            // 创建答案实体对象
            AnswerEntity answerEntity = new AnswerEntity();
            // 封装答案实体对象属性
            answerEntity.setId(UUID.randomUUID().toString());
            answerEntity.setUserId(userId);
            answerEntity.setQuestionnaireId(questionnaireId);
            answerEntity.setQuestionId(questionId);
            answerEntity.setCreateTime(LocalDateTime.now());
            if (!isOptionAnswer(questionId)) {
                answerEntity.setText(answerDTO.getText());
            } else {
                answerEntity.setOptionId(answerDTO.getOptionId());
            }
            // 将答案实体对象添加到集合中（批量保存）
            answerEntities.add(answerEntity);
        }
        // 保存所有答案实体对象
        answerRepository.saveAll(answerEntities);
    }

    /**
     * 判断指定问题的答案类型是否为选项类型
     * <p>
     * 判断题、单选题、多选题的答案类型为选项类型。
     *
     * @param questionId 问题ID
     * @return 当问题的答案类型为选项时返回true，否则返回false
     */
    private boolean isOptionAnswer(String questionId) {
        try {
            QuestionEntity.Type questionType = questionService.getTypeById(questionId);
            return questionType != QuestionEntity.Type.Q_AND_A;
        } catch (QuestionNotFoundException e) {
            throw new IllegalStateException(e);
        }
    }

}
