package com.seer.teach.teacher.mq;

import cn.hutool.json.JSONUtil;
import com.seer.teach.common.dto.mq.ImReplyDTO;
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.common.message.MessageExt;
import org.apache.rocketmq.remoting.protocol.heartbeat.MessageModel;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;

import java.net.InetAddress;
import java.nio.charset.StandardCharsets;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;

/**
 *
 * <p>
 *
 * </p >
 *
 * @author Captain
 * @since 2025-09-06 16:13
 */
@Slf4j
@Component
public class ImReplyConsumer  implements InitializingBean {

    @Value("${rocket-mq.namesrvAddr:192.168.0.39:9876}")
    private String namesrvAddr;

    @Value("${rocket-mq.producerGroup:${spring.profiles.active:dev}}")
    private String producerGroup;

    /**
     * 本实例唯一ID，用于路由回包
     */
    private String replyInstanceId;

    /**
     * replyConsumer
     */
    private DefaultMQPushConsumer replyConsumer;

    /**
     * correlationId -> Future
     */
    private final ConcurrentMap<String, CompletableFuture<ImReplyDTO>> pending = new ConcurrentHashMap<>();

    @Override
    public void afterPropertiesSet()  {
        String replyGroup = sanitizeForRocketMQ(producerGroup + "_reply_" + replyInstanceId);

        replyConsumer = new DefaultMQPushConsumer(replyGroup);
        replyConsumer.setNamesrvAddr(namesrvAddr);
        replyConsumer.setMessageModel(MessageModel.CLUSTERING);

        try {
            this.replyInstanceId = sanitizeForRocketMQ(producerGroup + "_" + InetAddress.getLocalHost().getHostAddress());
            // 订阅所有 topic 下的 RSP 消息
            replyConsumer.subscribe("*", "RSP");

            replyConsumer.registerMessageListener((MessageListenerConcurrently) (msgs, ctx) -> {
                for (MessageExt m : msgs) {
                    String corrId = m.getUserProperty("correlationId");
                    String toInstance = m.getUserProperty("replyInstanceId");

                    // 打印收到的所有 RSP
                    log.info("[RSP-RECV] topic={} tag={} corrId={} msgReplyInstanceId={} myInstanceId={}",
                            m.getTopic(),
                            m.getTags(),
                            corrId,
                            toInstance,
                            this.replyInstanceId);

                    if (!this.replyInstanceId.equals(toInstance)) {
                        log.warn("[RSP-DROP] replyInstanceId 不匹配, corrId={} msgReplyInstanceId={} myInstanceId={}",
                                corrId, toInstance, this.replyInstanceId);
                        continue;
                    }

                    CompletableFuture<ImReplyDTO> f = pending.remove(corrId);
                    if (f != null) {
                        try {
                            ImReplyDTO dto = JSONUtil.toBean(new String(m.getBody(), StandardCharsets.UTF_8), ImReplyDTO.class);
                            f.complete(dto);
                            log.info("[RSP-OK] corrId={} result={}", corrId, JSONUtil.toJsonStr(dto));
                        } catch (Exception e) {
                            log.error("[RSP-ERR] corrId={} 解析失败", corrId, e);
                            f.completeExceptionally(e);
                        }
                    } else {
                        log.warn("[RSP-ORPHAN] 收到孤儿回包 corrId={} 没有匹配的 pending", corrId);
                    }
                }
                return ConsumeConcurrentlyStatus.CONSUME_SUCCESS;
            });

            replyConsumer.start();
            log.info("[IM-RPC] ReplyConsumer 启动成功 group={} instanceId={} subscribe=(*,RSP)", replyGroup, replyInstanceId);
        } catch (Exception e) {
            log.error("[IM-RPC] ReplyConsumer 启动失败", e);
        }

    }

    public void registerPending(String corrId, CompletableFuture<ImReplyDTO> future) {
        pending.put(corrId, future);
    }

    public String getReplyInstanceId() {
        return replyInstanceId;
    }

    private static String sanitizeForRocketMQ(String s) {
        return s.replaceAll("[^%|a-zA-Z0-9_-]", "_");
    }
}
