package com.cirle.scientific.questionnaire.queue;

import com.cirle.scientific.questionnaire.dto.SubmitAnswerDTO;
import com.cirle.scientific.questionnaire.exception.AnswerSaveException;
import com.cirle.scientific.questionnaire.service.AnswerService;

import java.util.Map;
import java.util.concurrent.BlockingQueue;

/**
 * 答案队列消费者（单例）
 */
public class AnswerConsumer implements Runnable {

    private static AnswerConsumer answerConsumer;

    private final BlockingQueue<Map<String, SubmitAnswerDTO>> queue;

    private final AnswerService answerService;

    /**
     * 禁止外部实例化（单例）
     *
     * @param queue 队列对象
     */
    private AnswerConsumer(BlockingQueue<Map<String, SubmitAnswerDTO>> queue, AnswerService answerService) {
        this.queue = queue;
        this.answerService = answerService;
    }

    /**
     * 初始化答案队列消费者
     *
     * @param queue 队列对象
     */
    public static void init(BlockingQueue<Map<String, SubmitAnswerDTO>> queue, AnswerService answerService) {
        if (answerConsumer != null) {
            throw new IllegalStateException("该答案队列消费者已初始化");
        }
        answerConsumer = new AnswerConsumer(queue, answerService);
        new Thread(answerConsumer).start();
    }

    /**
     * 获取答案队列消费者实例（单例）
     *
     * @return 答案队列消费者对象
     */
    public static AnswerConsumer getInstance() {
        if (answerConsumer == null) throw new IllegalStateException("该答案队列消费者未初始化");
        return answerConsumer;
    }

    @Override
    public void run() {
        // 循环条件始终成立，该条件为骗过代码分析避免警告
        while (answerConsumer != null) process();
    }

    private void process() {
        takeAnswers().entrySet().forEach(this::submitAnswer);
    }

    private void submitAnswer(Map.Entry<String, SubmitAnswerDTO> entity) {
        try {
            answerService.saveAnswer(entity.getKey(), entity.getValue());
        } catch (AnswerSaveException e) {
            throw new IllegalStateException(e);
        }
    }

    private Map<String, SubmitAnswerDTO> takeAnswers() {
        try {
            return queue.take();
        } catch (InterruptedException e) {
            Thread.currentThread().interrupt();
            throw new IllegalStateException("从答案提交队列获取元素失败");
        }
    }

}