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

import com.alibaba.fastjson.JSONObject;
import com.aliyun.openservices.ons.api.PropertyKeyConst;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.apache.rocketmq.client.exception.MQClientException;
import org.apache.rocketmq.client.producer.DefaultMQProducer;
import org.apache.rocketmq.client.producer.SendCallback;
import org.apache.rocketmq.client.producer.SendResult;
import org.apache.rocketmq.common.message.Message;
import org.apache.rocketmq.remoting.common.RemotingHelper;

import java.util.Properties;
import java.util.UUID;

/**
 * @author Cai Yihua
 **/
@Slf4j
public class ApacheProducerProxy implements ProducerProxy {
    /**
     * 真实RocketMQ生产者对象
     */
    private DefaultMQProducer producer = null;
    /**
     * 缺省延迟时间级别列表
     */
    private static final String DEFAULT_DELAY_TIME = "1,5,10,30,60,120,180,240,300,360,420,480,540,600,1200,1800," +
            "3600,7200";

    @Override
    public void startup(Properties properties) {
        // 实例化消息生产者Producer
        //Instantiate with a producer group name.
        String producerGroupName = UUID.randomUUID().toString();
        producer = new DefaultMQProducer(producerGroupName);
        producer.setInstanceName(producerGroupName);
        // 设置NameServer的地址
        producer.setNamesrvAddr(properties.getProperty(PropertyKeyConst.NAMESRV_ADDR));
        log.info("Apache Producer started! Producer: {}, Group Name: {}", producer.toString(), producerGroupName);
        // 启动Producer实例
        try {
            producer.start();
        } catch (MQClientException e) {
            log.error("Apache RocketMq start failed:", e);
        }
    }

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

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

    @Override
    public SendMqMessageResult sendMessage(String topic, String tag, String messageBody, Properties userProperties, Long startDeliverTime) {
        try {
            // 创建消息，并指定Topic，Tag和消息体
            Message msg = new Message(topic,
                    tag,
                    messageBody.getBytes(RemotingHelper.DEFAULT_CHARSET)
            );
            if (startDeliverTime != null) {
                msg.setDelayTimeLevel(getDelayTimeLevel(userProperties, startDeliverTime));
            }
            // 发送消息到一个Broker
            SendResult sendResult = producer.send(msg);
            log.info("Send mq message success. Topic is: {}, tag is: {}, msgId is: {}. ", topic, tag, sendResult.getMsgId());
            SendMqMessageResult result = new SendMqMessageResult();
            result.setMessageId(sendResult.getMsgId());
            result.setOriginResult(JSONObject.toJSONString(sendResult));
            return result;
        } catch (Exception e) {
            log.error("Send mq message failed. Topic is: {}, tag is: {}, message body is: {} ", topic, tag, messageBody);
            log.error("Exception detailed info: ", e);
        }
        return null;
    }

    private int getDelayTimeLevel(Properties userProperties, Long startDeliverTime) {
        String delayTimeStr = null;
        if (userProperties !=  null) {
            delayTimeStr = userProperties.getProperty("delay_time_array");;
        }
        if (StringUtils.isEmpty(delayTimeStr)) {
            delayTimeStr = DEFAULT_DELAY_TIME;
        }
        String[] delayTimeArray = delayTimeStr.split(",");
        long delayTime = startDeliverTime - System.currentTimeMillis();
        long first = Integer.parseInt(delayTimeArray[0]) * 1000;
        long last = Integer.parseInt(delayTimeArray[delayTimeArray.length - 1]) * 1000;
        if (delayTime < first) {
            return 1;
        } else if (delayTime > last) {
            return delayTimeArray.length;
        }
        for (int i = 0; i < delayTimeArray.length; i++) {
            Integer start = Integer.parseInt(delayTimeArray[i]) * 1000;
            if (i < delayTimeArray.length - 1) {
                Integer end = Integer.parseInt(delayTimeArray[i + 1]) * 1000;
                if (delayTime >= start && delayTime < end) {
                    return i + 2;
                }
            }
        }
        return 15;
    }

    @Override
    public SendMqMessageResult sendAsyncMessage(String topic, String tag, String messageBody, Properties userProperties) {
        try {
            // 创建消息，并指定Topic，Tag和消息体
            Message msg = new Message(topic,
                    tag,
                    topic + "_" + tag + "_" + System.currentTimeMillis() / 1000,
                    messageBody.getBytes(RemotingHelper.DEFAULT_CHARSET));

            // SendCallback接收异步返回结果的回调
            SendMqMessageResult result = new SendMqMessageResult();
            producer.send(msg, new SendCallback() {
                @Override
                public void onSuccess(SendResult sendResult) {
                    // 消息发送成功
                    log.info("Send mq message success. Topic is: {}, tag is: {}, msgId is: {}. ", topic, tag, sendResult.getMsgId());
                    result.setMessageId(sendResult.getMsgId());
                    result.setOriginResult(JSONObject.toJSONString(sendResult));
                }

                @Override
                public void onException(Throwable e) {
                    // 消息发送失败，需要进行重试处理，可重新发送这条消息或持久化这条数据进行补偿处理
                    log.warn("send message failed. topic: {}", topic);
                    log.error("Exception detailed info: ", e);
                    sendMessage(topic, messageBody, tag, userProperties, null);
                }
            });
        } catch (Exception e) {
            log.error("Exception detailed info: ", e);
        }
        return null;
    }
}
