package com.ai.da.common.RabbitMQ;

import com.ai.da.common.config.exception.BusinessException;
import com.ai.da.common.utils.RedisUtil;
import com.ai.da.model.dto.GenerateThroughImageTextDTO;
import com.ai.da.model.vo.GenerateCollectionVO;
import com.ai.da.service.GenerateService;
import com.alibaba.fastjson.JSONObject;
import com.rabbitmq.client.Channel;
import lombok.extern.slf4j.Slf4j;
import org.springframework.amqp.core.Message;
import org.springframework.amqp.rabbit.annotation.RabbitHandler;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
import java.io.IOException;
import java.util.HashMap;
import java.util.Objects;


@Slf4j
@Component
public class GenerateConsumer {

    @Resource
    private GenerateService generateService;

    @Resource
    private RedisUtil redisUtil;

    @Value("${redis.key.orderForGenerate}")
    private String consumptionOrderKey;

    @Value("${redis.key.generateCancelSet}")
    private String cancelSetKey;

    @Value("${redis.key.generateExceptionMap}")
    private String exceptionMapKey;

    @Value("${redis.key.resultMap}")
    private String resultMapKey;

    public void generate(Message msg, Channel channel, String consumerName) {
        log.info("============start listening==========");
        long start = System.currentTimeMillis();

        GenerateThroughImageTextDTO generateThroughImageTextDTO = JSONObject.parseObject(msg.getBody(), GenerateThroughImageTextDTO.class);
        String uniqueId = generateThroughImageTextDTO.getUniqueId();
        log.info("From " + consumerName + " : " + uniqueId);

        try {
            // 2、判断当前消息是否在取消列表中
            Boolean isMember = redisUtil.isElementExistsInSet(cancelSetKey, uniqueId);
            if (isMember) {
                try {
                    // 2.1 手动确认该消息
                    channel.basicAck(msg.getMessageProperties().getDeliveryTag(), false);
                } catch (IOException ex) {
                    log.error("手动确认，不返回队列重新消费");
                }
                // 2.2 将该消息从取消列表中删除
//                redisUtil.removeFromSet(cancelSetKey, uniqueId);
            } else {
                /*try {
                    Thread.sleep(15000);
                } catch (InterruptedException e) {
                    throw new RuntimeException(e);
                }*/
                GenerateCollectionVO generateCollectionVO = generateService.generateThroughImageText(generateThroughImageTextDTO);
                // 将消息从redis排队队列中删除,需保证被消费的消息存储到db之后再从redis删除
                redisUtil.removeFromZSet(consumptionOrderKey, uniqueId);
                if (!Objects.isNull(generateCollectionVO)) {
                    HashMap<String, String> generateResult = new HashMap<>();
                    generateResult.put(uniqueId, JSONObject.toJSONString(generateCollectionVO));
                    // 将结果存在redis中 ,为空时不要存
                    redisUtil.addToMap(resultMapKey, generateResult);
                }

            }
        } catch (BusinessException e) {
            log.error(e.getMsg());
            // channel.basicNack() 为不确认deliveryTag对应的消息，第二个参数是否应用于多消息，第三个参数是否requeue
            try {
                // 第二个参数，是否批量确认消息，当传false时，只确认当前 deliveryTag对应的消息;当传true时，会确认当前及之前所有未确认的消息。
                channel.basicAck(msg.getMessageProperties().getDeliveryTag(), false);
                // 将消息从redis排队队列中删除,需保证被消费的消息存储到db之后再从redis删除
                redisUtil.removeFromZSet(consumptionOrderKey, uniqueId);
            } catch (IOException exception) {
                log.error("手动确认，取消返回队列，不再重新消费");
            }
            // 将入参和错误信息存入数据库
            String exceptionMessage = JSONObject.toJSONString(generateThroughImageTextDTO) +
                    " Exception message ： " + e.getMsg();
            HashMap<String, String> exceptionInfo = new HashMap<>();
            exceptionInfo.put(String.valueOf(uniqueId), exceptionMessage);
            // 存redis
            redisUtil.addToMap(exceptionMapKey, exceptionInfo);
        }
        long end = System.currentTimeMillis();

        log.info(" task_id： " + uniqueId + "----------" + consumerName + " 执行时长：" + (end - start) + "毫秒");
        log.info("=============end listening===========");
    }

    @RabbitListener(queues = MQConfig.GENERATE_QUEUE)
    @RabbitHandler
    public void generateConsumer1(Message msg, Channel channel) {
        generate(msg, channel, "consumer 1");
    }

    @RabbitListener(queues = MQConfig.GENERATE_QUEUE)
    @RabbitHandler
    public void generateConsumer2(Message msg, Channel channel) {
        generate(msg, channel, "consumer 2");
    }

    @RabbitListener(queues = MQConfig.GENERATE_QUEUE)
    @RabbitHandler
    public void generateConsumer3(Message msg, Channel channel) {
        generate(msg, channel, "consumer 3");
    }

    @RabbitListener(queues = MQConfig.GENERATE_QUEUE)
    @RabbitHandler
    public void generateConsumer4(Message msg, Channel channel) {
        generate(msg, channel, "consumer 4");
    }

    @RabbitListener(queues = MQConfig.GENERATE_QUEUE)
    @RabbitHandler
    public void generateConsumer5(Message msg, Channel channel) {
        generate(msg, channel, "consumer 5");
    }

    @RabbitListener(queues = MQConfig.GENERATE_QUEUE)
    @RabbitHandler
    public void generateConsumer6(Message msg, Channel channel) {
        generate(msg, channel, "consumer 6");
    }

    @RabbitListener(queues = MQConfig.GENERATE_QUEUE)
    @RabbitHandler
    public void generateConsumer7(Message msg, Channel channel) {
        generate(msg, channel, "consumer 7");
    }

    @RabbitListener(queues = MQConfig.GENERATE_QUEUE)
    @RabbitHandler
    public void generateConsumer8(Message msg, Channel channel) {
        generate(msg, channel, "consumer 8");
    }

    @RabbitListener(queues = MQConfig.GENERATE_QUEUE)
    @RabbitHandler
    public void generateConsumer9(Message msg, Channel channel) {
        generate(msg, channel, "consumer 9");
    }

}
