package org.springblade.common.notify.rocketmq.consumer;

import com.alibaba.fastjson.JSONObject;
import com.aliyun.openservices.ons.api.PropertyKeyConst;
import lombok.extern.slf4j.Slf4j;
import org.apache.rocketmq.client.consumer.DefaultMQPushConsumer;
import org.apache.rocketmq.client.consumer.listener.ConsumeConcurrentlyStatus;
import org.apache.rocketmq.client.consumer.listener.MessageListenerConcurrently;
import org.apache.rocketmq.client.exception.MQClientException;
import org.apache.rocketmq.common.message.MessageExt;
import org.apache.rocketmq.common.protocol.heartbeat.MessageModel;
import org.springframework.util.CollectionUtils;

import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.List;
import java.util.Properties;

/**
 * @author Cai Yihua
 **/
@Slf4j
public class ApacheConsumerProxy implements ConsumerProxy {
    /**
     * 真实消费者对象
     */
    private DefaultMQPushConsumer consumer;

    @Override
    public void startup(Properties properties, MqMessageHandlerHolder mqMessageHandlerHolder) {
        // 实例化消费者
        consumer = new DefaultMQPushConsumer(mqMessageHandlerHolder.getConsumerId());
        // 设置NameServer的地址
        consumer.setNamesrvAddr(properties.getProperty(PropertyKeyConst.NAMESRV_ADDR));
        consumer.setMaxReconsumeTimes(mqMessageHandlerHolder.getMaxRetryTimes());
        consumer.setMessageModel(mqMessageHandlerHolder.isBroadcast() ? MessageModel.BROADCASTING : MessageModel.CLUSTERING);
        try {
            // 订阅一个或者多个Topic，以及Tag来过滤需要消费的消息
            consumer.subscribe(mqMessageHandlerHolder.getTopic(), mqMessageHandlerHolder.getTag());
            // 注册回调实现类来处理从broker拉取回来的消息
            consumer.registerMessageListener((MessageListenerConcurrently) (msgs, context) -> {
                if (CollectionUtils.isEmpty(msgs)) {
                    log.warn("The input message is NULL!!!");
                    return ConsumeConcurrentlyStatus.RECONSUME_LATER;
                }

                int reconsumeTimes = 0;
                try {
                    List<MqMessage> messages = new ArrayList<>();
                    for (MessageExt msg : msgs) {
                        reconsumeTimes = msg.getReconsumeTimes();
                        String messageBody = new String(msg.getBody(), StandardCharsets.UTF_8);

                        if (!msg.getTopic().equals(mqMessageHandlerHolder.getTopic()) || (!mqMessageHandlerHolder.getTag().equals("*") && !mqMessageHandlerHolder.getTag().contains(msg.getTags()))) {
                            log.warn(
                                    "The input message should not be handled by this handler. The message topic is {}, the message tag is {}; The handler topic is {}, the handler tag is {}.",
                                    msg.getTopic(), msg.getTags(), mqMessageHandlerHolder.getTopic(),
                                    mqMessageHandlerHolder.getTag());
                            continue;
                        }

                        MqMessage mqMessage = new MqMessage();
                        mqMessage.setConsumerId(mqMessageHandlerHolder.getConsumerId());
                        mqMessage.setTopic(msg.getTopic());
                        mqMessage.setTag(msg.getTags());
                        mqMessage.setMessageId(msg.getMsgId());
                        mqMessage.setMessageBody(messageBody);
                        mqMessage.setOriginMessage(JSONObject.toJSONString(msg));
                        messages.add(mqMessage);
                    }

                    boolean flag = mqMessageHandlerHolder.getMqMessageHandler().handle(messages);
                    log.info("ConsumerId:{}, Topic:{}, Tag:{}, the result of handling message:{}", mqMessageHandlerHolder.getConsumerId(), mqMessageHandlerHolder.getTopic(), mqMessageHandlerHolder.getTag(), flag);

                    // 如果成功，或者当重试次数超过某个阈值则返回成功.
                    if (flag || reconsumeTimes >= mqMessageHandlerHolder.getMaxRetryTimes()) {
                        return ConsumeConcurrentlyStatus.CONSUME_SUCCESS;
                    }

                    return ConsumeConcurrentlyStatus.RECONSUME_LATER;
                } catch (Exception e) {
                    log.error("consume message error.", e);
                    if (reconsumeTimes >= mqMessageHandlerHolder.getMaxRetryTimes()) {
                        return ConsumeConcurrentlyStatus.CONSUME_SUCCESS;
                    }
                    return ConsumeConcurrentlyStatus.RECONSUME_LATER;
                }
            });
            // 启动消费者实例
            consumer.start();
            log.info("Apache RocketMQ Consumer Started, Topic:{}, Tag:{}", mqMessageHandlerHolder.getTopic(),
                    mqMessageHandlerHolder.getTag());
        } catch (MQClientException e) {
            log.error("Apache RocketMq start failed:", e);
        }
    }

    @Override
    public void shutdown() {
        if (consumer != null) {
            consumer.shutdown();
            consumer = null;
        }
    }

    @Override
    public boolean isStarted() {
        return consumer != null;
    }
}
