package com.ktg.common.utils.rocketmq;

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.springframework.beans.factory.DisposableBean;
import org.springframework.beans.factory.InitializingBean;

import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

/**
 * RocketMQ生产者管理器
 * 负责管理多个RocketMQ生产者实例
 * 实现InitializingBean在Spring初始化完成后自动初始化生产者
 * 实现DisposableBean在Spring销毁时自动关闭生产者
 */
public class RocketMQProducerManager implements InitializingBean, DisposableBean {
    // RocketMQ配置属性
    private final RocketMQProperties properties;

    // 生产者Map，key为生产者名称，value为生产者实例
    private final Map<String, DefaultMQProducer> producerMap = new ConcurrentHashMap<>();

    /**
     * 构造函数
     * @param properties RocketMQ配置属性
     */
    public RocketMQProducerManager(RocketMQProperties properties) {
        this.properties = properties;
    }

    /**
     * Spring Bean初始化完成后调用的方法
     * 初始化所有配置的生产者实例
     */
    @Override
    public void afterPropertiesSet() {
        // 遍历所有生产者配置
        properties.getProducers().forEach((name, config) -> {
            // 创建生产者实例
            DefaultMQProducer producer = new DefaultMQProducer(config.getGroup());

            // 设置NameServer地址
            producer.setNamesrvAddr(properties.getNamesrvAddr());

            // 设置生产者参数
            producer.setRetryTimesWhenSendFailed(config.getRetryTimesWhenSendFailed());
            producer.setSendMsgTimeout(config.getSendMsgTimeout());
            producer.setCompressMsgBodyOverHowmuch(config.getCompressMsgBodyOverHowmuch());

            // 设置实例名称（如果配置了）
            if (config.getInstanceName() != null) {
                producer.setInstanceName(config.getInstanceName());
            }

            try {
                // 启动生产者
                producer.start();
                // 将生产者加入Map
                producerMap.put(name, producer);
            } catch (MQClientException e) {
                throw new RuntimeException("Failed to start RocketMQ producer: " + name, e);
            }
        });
    }

    /**
     * Spring Bean销毁时调用的方法
     * 关闭所有生产者实例
     */
    @Override
    public void destroy() {
        producerMap.values().forEach(DefaultMQProducer::shutdown);
    }

    /**
     * 同步发送消息
     * @param producerName 生产者名称（配置中的key）
     * @param topic 消息Topic
     * @param tags 消息Tags
     * @param keys 消息Keys
     * @param body 消息体
     * @return 发送结果
     */
    public SendResult sendSync(String producerName, String topic, String tags, String keys, byte[] body) throws Exception {
        DefaultMQProducer producer = getProducer(producerName);
        Message msg = new Message(topic, tags, keys, body);
        return producer.send(msg);
    }

    /**
     * 异步发送消息
     * @param producerName 生产者名称
     * @param topic 消息Topic
     * @param tags 消息Tags
     * @param keys 消息Keys
     * @param body 消息体
     * @param sendCallback 异步回调接口
     */
    public void sendAsync(String producerName, String topic, String tags, String keys, byte[] body, SendCallback sendCallback) throws Exception {
        DefaultMQProducer producer = getProducer(producerName);
        Message msg = new Message(topic, tags, keys, body);
        producer.send(msg, sendCallback);
    }

    /**
     * 单向发送消息（不关心发送结果）
     * @param producerName 生产者名称
     * @param topic 消息Topic
     * @param tags 消息Tags
     * @param keys 消息Keys
     * @param body 消息体
     */
    public void sendOneway(String producerName, String topic, String tags, String keys, byte[] body) throws Exception {
        DefaultMQProducer producer = getProducer(producerName);
        Message msg = new Message(topic, tags, keys, body);
        producer.sendOneway(msg);
    }

    /**
     * 获取指定名称的生产者实例
     * @param name 生产者名称
     * @return 生产者实例
     */
    public DefaultMQProducer getProducer(String name) {
        DefaultMQProducer producer = producerMap.get(name);
        if (producer == null) {
            throw new IllegalArgumentException("RocketMQ producer not found: " + name);
        }
        return producer;
    }
}
