package com.seer.teach.teacher.mq;

import cn.hutool.json.JSONUtil;
import com.seer.teach.common.dto.mq.ImReplyDTO;
import com.seer.teach.common.dto.mq.StringDTO;
import com.seer.teach.common.dto.mq.im.KnowledgeDTO;
import com.seer.teach.common.enums.im.BusinessTopicTagEnum;
import com.seer.teach.common.enums.im.ImMqTopicEnum;
import com.seer.teach.common.enums.im.RedisChannelPushTopTagEnum;
import com.seer.teach.teacher.common.dto.TeachDTO;
import com.seer.teach.teacher.convert.MQConvert;
import com.seer.teach.teacher.service.impl.RedisPubSub;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.rocketmq.client.producer.DefaultMQProducer;
import org.apache.rocketmq.client.producer.SendResult;
import org.apache.rocketmq.common.message.Message;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;

import java.time.Duration;
import java.util.ArrayList;
import java.util.Collection;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;

/**
 * IM消息队列生产者类，用于向RocketMQ发送消息，并支持通过Redis实现请求-响应模式的消息通信。
 * 提供同步发送、异步发送以及带回复的消息发送功能。
 */
@Slf4j
@Component
@RequiredArgsConstructor
public class ImMqProducer {

    /**
     * RocketMQ NameServer 地址，默认值为 192.168.0.39:9876
     */
    @Value("${rocket-mq.namesrvAddr:192.168.0.39:9876}")
    private String namesrvAddr;

    /**
     * RocketMQ 生产者组名称，默认使用当前环境的 profile 名称（如 dev）
     */
    @Value("${rocket-mq.producerGroup:${spring.profiles.active:dev}}")
    private String producerGroup;

    /**
     * Redis发布订阅服务，用于处理需要等待响应的消息流程
     */
    private final RedisPubSub redisPubSub;

    /**
     * 异步消息发送线程池，最大线程数为40个，线程名为 rocketmq-message-async-sender，设置为守护线程
     */
    private static final ExecutorService ASYNC_EXECUTOR = Executors.newFixedThreadPool(40, r -> {
        Thread t = new Thread(r);
        t.setName("rocketmq-message-async-sender");
        t.setDaemon(true);
        return t;
    });

    /**
     * 向指定主题和标签发送消息
     *
     * @param topic       消息主题枚举
     * @param tag         消息标签
     * @param businessKey 业务键，用于标识消息内容
     * @param body        消息体内容
     */
    public void sendMsg(ImMqTopicEnum topic, String tag, String businessKey, String body) {
        try {
            // 获取RocketMQ生产者实例
            DefaultMQProducer producer = RocketMQProducerFactory.getProducer(topic.getTopic() + "-" + producerGroup, namesrvAddr);
            Collection<Message> messages = new ArrayList<>();
            // 构造消息对象
            Message msg = new Message(topic.getTopic() + "-" + producerGroup, tag, businessKey, body.getBytes());
            messages.add(msg);
            // 发送消息
            SendResult send = producer.send(messages);
        } catch (Exception e) {
            log.error(e.getMessage(), e);
        }
    }

    /**
     * 发送消息并通过Redis等待响应结果
     *
     * @param topic      消息主题枚举
     * @param tag        消息标签
     * @param key        消息键
     * @param body       消息体内容
     * @param timeoutMs  等待响应的超时时间（毫秒）
     * @return 响应结果 ImReplyDTO 对象，若失败或超时则返回 null
     */
    public ImReplyDTO sendMsgWithReplyViaRedis(ImMqTopicEnum topic, String tag, String key, String body, long timeoutMs) {
        String corrId = java.util.UUID.randomUUID().toString();
        String channel = "im:reply:" + corrId;
        try {
            // 异步等待Redis回复消息
            CompletableFuture<ImReplyDTO> wait = CompletableFuture.supplyAsync(() -> {
                try {
                    String payload = redisPubSub.await(channel, Duration.ofMillis(timeoutMs));
                    return cn.hutool.json.JSONUtil.toBean(payload, ImReplyDTO.class);
                } catch (Exception e) {
                    return null;
                }
            });

            // 发送MQ消息
            DefaultMQProducer p = RocketMQProducerFactory.getProducer(topic.getTopic() + "-" + producerGroup, namesrvAddr);
            Message msg = new Message(topic.getTopic() + "-" + producerGroup, tag, key, body.getBytes());
            msg.putUserProperty("J_CORR_ID", corrId);
            p.send(msg);

            // 等待并获取回复结果
            ImReplyDTO reply = wait.get(timeoutMs + 200L, TimeUnit.MILLISECONDS);
            return reply != null && reply.isSuccess() ? reply : null;
        } catch (Exception e) {
            log.error("Redis回包流程失败, key={}, corrId={}", key, corrId, e);
            return null;
        }
    }

    /**
     * 异步发送消息到指定主题和标签
     *
     * @param topic       消息主题枚举
     * @param tag         消息标签
     * @param businessKey 业务键，用于标识消息内容
     * @param body        消息体内容
     */
    public void sendMsgAsync(ImMqTopicEnum topic, String tag, String businessKey, String body) {
        ASYNC_EXECUTOR.submit(() -> {
            try {
                sendMsg(topic, tag, businessKey, body);
            } catch (Exception e) {
                log.error("异步发送消息失败，businessKey：{}，body：{}", businessKey, body, e);
            }
        });
    }

    /**
     * 发送音频通道名称到指定设备
     *
     * @param device      设备标识
     * @param channelName 音频通道名称
     */
    public void sendAudioChannelName(String device, String channelName) {
        sendMsgWithReplyViaRedis(
                ImMqTopicEnum.REDIS_CHANNEL_PUSH,
                RedisChannelPushTopTagEnum.PUSH_LLM_AUDIO.getTag(),
                device,
                JSONUtil.toJsonStr(new StringDTO(channelName)),
                3
        );
    }

    public void sendLessonKnowData(TeachDTO teachDTO,String device){
        KnowledgeDTO result = MQConvert.INSTANCE.toKnowDTO(teachDTO);
        sendMsg(ImMqTopicEnum.BUSINESS, BusinessTopicTagEnum.KNOW_DATA.getTag(), device, JSONUtil.toJsonStr(result));
    }

    public void sendClassOver(String device) {
        // TODO 发送 下课状态
    }
}
