package com.seer.teach.netty.im.config.rocketmq;

import cn.hutool.json.JSONUtil;
import com.seer.teach.common.dto.mq.ImReplyDTO;
import com.seer.teach.common.dto.mq.MqDTO;
import com.seer.teach.common.enums.im.CommandTopicTagEnum;
import com.seer.teach.common.enums.im.ImMqTopicEnum;
import com.seer.teach.common.enums.MessagePushStatusEnums;
import com.seer.teach.netty.common.proto.MessageType;
import com.seer.teach.netty.im.handler.mq.ImCommandHandler;
import com.seer.teach.netty.im.registry.ImCommandHandlerRegistry;
import com.seer.teach.netty.im.utils.ImUtils;
import com.seer.teach.netty.im.utils.RedisPubSub;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.rocketmq.common.message.MessageExt;
import org.springframework.stereotype.Component;

/**
 * {@code ImCommandConsumer} 是用于消费 RocketMQ 中指令类消息的消费者组件。
 * <p>
 * 该类继承自 {@link AbstractRocketMQConsumer}，启动时自动订阅 {@link ImMqTopicEnum#COMMAND} 主题，
 * 并通过注入的 {@link ImCommandHandlerRegistry} 根据消息的 tag 查找对应的 {@link ImCommandHandler}，
 * 将接收到的消息 JSON 字符串解析为指定类型后交由对应 Handler 处理。
 * </p>
 *
 * <h3>主要职责：</h3>
 * <ul>
 *   <li>初始化 RocketMQ 消费者并订阅指定 topic</li>
 *   <li>消费消息并根据 tag 分发给对应的业务处理器</li>
 *   <li>自动将消息 JSON 字符串转换为指定类型的业务对象</li>
 *   <li>处理异常并记录日志</li>
 * </ul>
 *
 * @author Captain
 * @version 1.0
 * @since 2025-07-16 19:07
 */
@Slf4j
@Component
@RequiredArgsConstructor
public class ImCommandConsumer extends AbstractRocketMQConsumer {

    /**
     * 消息处理器注册表，负责根据消息 tag 获取对应的处理器实例
     */
    private final ImCommandHandlerRegistry handlerRegistry;

    private final RedisPubSub redisPubSub;


    /**
     * 返回该消费者订阅的 RocketMQ 主题枚举，固定为 {@link ImMqTopicEnum#COMMAND}
     *
     * @return 消息主题枚举 {@link ImMqTopicEnum#COMMAND}
     */
    @Override
    protected ImMqTopicEnum getTopic() {
        return ImMqTopicEnum.COMMAND;
    }

    /**
     * 处理收到的消息，根据 tag 获取对应的 Handler，
     * 并将消息体 JSON 字符串解析成业务对象后调用 Handler 进行处理。
     * <p>
     * 若未找到对应处理器或解析失败，会记录日志并跳过处理。
     * </p>
     *
     * @param tag     消息标签，用于映射处理器
     * @param body    消息内容的 JSON 字符串
     * @param message RocketMQ 原始消息对象
     */
    @Override
    protected void doHandleMessage(String tag, String device, String body, MessageExt message) {
        if (CommandTopicTagEnum.JUMP_QUESTION.getTag().equals(tag)) {
            ImReplyDTO result;
            try {
                Integer index = cn.hutool.core.convert.Convert.toInt(
                        cn.hutool.json.JSONUtil.parseObj(body).getStr("data"));
                ImUtils.pushSingleChatToDeviceWithAck(
                        device,
                        MessagePushStatusEnums.SUCCESS.getCode(),
                        MessageType.MessageContentType.JUMP_INDEX.getMsgContentType(),
                        index
                );
                result = ImReplyDTO.ok("跳转成功");
            } catch (Exception e) {
                result = ImReplyDTO.fail(e.getMessage());
            }
            String corrId = message.getUserProperty("J_CORR_ID");
            redisPubSub.publish("im:reply:" + corrId, cn.hutool.json.JSONUtil.toJsonStr(result));
            return;
        }
        ImCommandHandler<?> handler = handlerRegistry.getHandler(tag);
        if (handler != null) {
            Object parsed = JSONUtil.toBean(body, handler.getType());
            invokeHandler(handler, parsed, device);
        } else {
            log.warn("未找到处理器：tag={}", tag);
        }
    }

    /**
     * 将消息体 JSON 字符串反序列化为 Handler 声明的业务对象类型。
     *
     * @param body    JSON 格式的消息体字符串
     * @param handler 具体的消息处理器，包含业务对象类型信息
     * @return 反序列化后的业务对象，若解析失败返回 {@code null}
     */
    private Object parseMessageBody(String body, ImCommandHandler<?> handler) {
        try {
            return JSONUtil.toBean(body, handler.getType());
        } catch (Exception e) {
            log.error("JSON 解析失败：type={}, body={}", handler.getType().getSimpleName(), body, e);
            return null;
        }
    }

    /**
     * 调用指定的消息处理器执行业务逻辑。
     * <p>
     * 由于 Handler 使用泛型，需进行类型转换。
     * </p>
     *
     * @param handler 具体的消息处理器实例
     * @param message 反序列化后的业务消息对象
     * @param <T>     业务消息类型，继承自 {@link MqDTO}
     */
    @SuppressWarnings("unchecked")
    private <T extends MqDTO> void invokeHandler(ImCommandHandler<?> handler, Object message, String device) {
        ((ImCommandHandler<T>) handler).handleWithLog((T) message, device);
    }
}
