package com.qmth.teachcloud.task.config;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.google.gson.Gson;
import com.qmth.boot.redis.uid.RedisMachineService;
import com.qmth.distributed.print.business.templete.execute.AsyncCreatePdfTempleteService;
import com.qmth.teachcloud.common.bean.dto.MqDto;
import com.qmth.teachcloud.common.contant.SystemConstant;
import com.qmth.teachcloud.common.entity.SysUser;
import com.qmth.teachcloud.common.entity.TBTask;
import com.qmth.teachcloud.common.entity.TMMqMessage;
import com.qmth.teachcloud.common.service.TMMqMessageService;
import com.qmth.teachcloud.common.util.JacksonUtil;
import com.qmth.teachcloud.common.util.RedisUtil;
import com.qmth.teachcloud.common.util.ResultUtil;
import org.apache.commons.text.StringEscapeUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.data.redis.connection.Message;
import org.springframework.data.redis.connection.MessageListener;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
import java.time.Duration;
import java.util.*;
import java.util.concurrent.atomic.AtomicInteger;

/**
 * @Description: redis消息监听
 * @Param:
 * @return:
 * @Author: wangliang
 * @Date: 2021/7/9
 */
@Component
public class RedisMessageListener implements MessageListener {
    private final static Logger log = LoggerFactory.getLogger(RedisMessageListener.class);

    @Resource
    RedisUtil redisUtil;

    @Resource
    TMMqMessageService tmMqMessageService;

    @Resource
    AsyncCreatePdfTempleteService asyncCreatePdfTempleteService;

    @Resource
    RedisMachineService redisMachineService;

    @Override
    public void onMessage(Message message, byte[] bytes) {
        if (Objects.nonNull(redisUtil.get(SystemConstant.CURRENT_TASK_MACHINE_ID))) {
            Set<Integer> set = (Set<Integer>) redisUtil.getKeyPatterns(SystemConstant.TASK_MACHINE_ID_LIKE);
            if (Objects.nonNull(set) && set.size() > 1) {
                int currentMachineId = (int) redisUtil.get(SystemConstant.CURRENT_TASK_MACHINE_ID);
                if (currentMachineId == redisMachineService.getMachineId()) {
                    return;
                }
            }
        }
        MqDto mqDto = null;
        AtomicInteger integer = new AtomicInteger(0);
        try {
            //消息
            String body = StringEscapeUtils.unescapeJson(new String(message.getBody(), SystemConstant.CHARSET_NAME));
            if (Objects.nonNull(body)) {
                mqDto = JacksonUtil.readJson(body.substring(1, body.length() - 1), MqDto.class);
                for (; integer.get() < mqDto.getReconsume(); integer.incrementAndGet()) {
                    log.info("reconsume:{}", integer.get());
                    if (Objects.nonNull(mqDto.getAck()) && mqDto.getAck().intValue() != SystemConstant.STANDARD_ACK_TYPE
                            && Objects.nonNull(redisUtil.get(SystemConstant.MQ_TOPIC_BUFFER_LIST, mqDto.getId()))
                            && redisUtil.lock(SystemConstant.REDIS_LOCK_MQ_PREFIX + mqDto.getId(),
                            SystemConstant.REDIS_LOCK_MQ_TIME_OUT)) {
                        try {
                            //通道
                            String topic = new String(message.getChannel(), SystemConstant.CHARSET_NAME);
                            log.info("mqDto:{},topic:{}", JacksonUtil.parseJson(mqDto), JacksonUtil.parseJson(topic));
                            Map<String, Object> map = (Map<String, Object>) mqDto.getBody();
                            Map<String, Object> finalMap = new HashMap<>();
                            map.forEach((k, v) -> {
                                if (Objects.equals(k, SystemConstant.TASK)) {
                                    v = JSONObject.parseObject(JSON.toJSONString(v), TBTask.class);
                                } else if (Objects.equals(k, SystemConstant.USER)) {
                                    v = JSONObject.parseObject(JSON.toJSONString(v), SysUser.class);
                                }
                                Object finalV = v;
                                finalMap.computeIfAbsent(k, v1 -> finalV);
                            });
                            asyncCreatePdfTempleteService.createPdf(finalMap, null);
                            redisUtil.set(SystemConstant.CURRENT_TASK_MACHINE_ID, redisMachineService.getMachineId());
                            redisUtil.delete(SystemConstant.MQ_TOPIC_BUFFER_LIST, mqDto.getId());
                            mqDto.setAck(SystemConstant.STANDARD_ACK_TYPE);
                            break;
                        } finally {
                            if (Objects.nonNull(mqDto)) {
                                redisUtil.releaseLock(SystemConstant.REDIS_LOCK_MQ_PREFIX + mqDto.getId());
                            }
                        }
                    } else {
                        if (Objects.isNull(redisUtil.get(SystemConstant.MQ_TOPIC_BUFFER_LIST, mqDto.getId()))) {
                            break;
                        }
                        mqDto.setAck(SystemConstant.REDELIVERED_ACK_TYPE);
                        Thread.sleep(Duration.ofSeconds(SystemConstant.REDIS_MQ_MAX_RECONSUME).toMillis() * (integer.get() == 0 ? 1 : integer.get()));
                    }
                }
            }
        } catch (Exception e) {
            log.error(SystemConstant.LOG_ERROR, e);
            if (Objects.nonNull(mqDto)) {//存入库
                Gson gson = new Gson();
                mqDto.setAck(SystemConstant.POSION_ACK_TYPE);
                TMMqMessage tmMqMessage = gson.fromJson(gson.toJson(mqDto), TMMqMessage.class);
                tmMqMessage.setBody(JacksonUtil.parseJson(tmMqMessage.getBody()));
                tmMqMessageService.saveOrUpdate(tmMqMessage);
                redisUtil.releaseLock(SystemConstant.REDIS_LOCK_MQ_PREFIX + mqDto.getId());
            }
        }
    }
}
