package com.uas.search.jms;

import com.uas.search.constant.model.SPage;
import com.uas.search.model.ParsedQueueMessage;
import com.uas.search.schedule.TaskInformation;
import com.uas.search.schedule.Executable;
import com.uas.search.schedule.TaskService;
import com.uas.search.service.IndexService;
import com.uas.search.util.CollectionUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.List;

/**对数据库的消息队列进行实时监听
 *
 * @author sunyj
 * @since 2017/10/11 16:20
 */
@Service
public class JmsListener {

    /**
     * 第一次执行的延迟时间间隔为 3 秒，以防止日志交杂错乱，不好查看
     */
    private static final long INITIAL_DELAY = 3000;
    /**
     * 两次任务之间的等待时间间隔为 1 秒钟
     */
    private static final long INTERVAL = 1000;

    @Autowired
    private LuceneMessageDao luceneMessageDao;

    @Autowired
    private IndexService indexService;

    @Autowired
    private TaskService taskService;

    @Autowired
    private LuceneMessageService luceneMessageService;

    @Autowired
    private QueueMessageParser queueMessageParser;

    private TaskInformation taskInformation;

    private Logger logger = LoggerFactory.getLogger(getClass());

    /**
     * 开启实时更新索引
     *
     * @param interval
     *            每次接收到jms消息后等待的时间（秒）
     * @return 开启成功与否的提示信息
     */
    public void start(Long interval) {
        if(interval == null){
            interval = INTERVAL;
        }else{
            interval *= 1000;
        }
        if(interval <= 0){
            throw new IllegalArgumentException("interval 不合法：" + interval);
        }

        if (isRunning()) {
            throw new IllegalStateException("已存在运行的索引实时更新服务");
        }

        try {
            String title = "实时更新";
            Executable command = new Executable() {
                @Override
                public String execute() {
                    SPage<LuceneMessage> sPage = luceneMessageService.findAll(1, 100);
                    List<LuceneMessage> luceneMessages = sPage.getContent();
                    if (CollectionUtils.isEmpty(luceneMessages)) {
                        return "无消息";
                    }
                    for(LuceneMessage luceneMessage : luceneMessages){
                        try {
                            process(luceneMessage);
                        } catch (Throwable e) {
                            logger.error("", e);
                        }
                    }
                    // 如果消息不止一页，立即消费下一页
                    if(sPage.getTotalPage() > 1){
                        execute();
                    }
                    return "正常";
                }
            };
            taskInformation = new TaskInformation(title, command, INITIAL_DELAY, interval, TaskInformation.ScheduleType.FixedDelay);
            taskService.newTask(taskInformation);
            if (!taskService.isStopped()) {
                taskService.stop();
            }
            taskService.start();
        } catch (Throwable e) {
            if (taskInformation != null) {
                taskInformation = null;
            }
            throw new IllegalStateException("开启失败", e);
        }
    }

    /**
     * 关闭实时更新索引服务
     *
     * @return 关闭成功与否的提示信息
     */
    public void stop() {
        if (!isRunning()) {
            throw new IllegalStateException("索引实时更新服务未开启或已关闭");
        } else {
            taskService.remove(taskInformation.getCode());
            taskInformation = null;
            if (!taskService.isStopped()) {
                taskService.stop();
            }
            taskService.start();
        }
    }

    /**
     * @return 索引实时更新服务是否正在运行
     */
    public boolean isRunning() {
        return taskInformation != null && taskService.exist(taskInformation.getCode());
    }

    /**
     * 对得到的队列消息进行解析，之后根据解析出来的对象，对lucene索引进行添加、更新或删除操作
     *
     * @param luceneMessage 消息
     */
    private void process(LuceneMessage luceneMessage) {
        logger.info(luceneMessage.toString());
        Long id = luceneMessage.getId();
        luceneMessage.setRetryCount(luceneMessage.getRetryCount() + 1);
        luceneMessageDao.save(luceneMessage);
        ParsedQueueMessage parsedQueueMessage = queueMessageParser.parse(luceneMessage.getTableName(), luceneMessage.getDataId(), luceneMessage.getMethodType(), luceneMessage.getData());
        List<Object> maintainedObjects = indexService.maintainIndexes(parsedQueueMessage);
        logger.info("Maintained... " + maintainedObjects);
        luceneMessageDao.dequeueLuceneMessage(id);
    }
}
