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

import cn.hutool.json.JSONUtil;
import com.seer.teach.common.dto.mq.MqDTO;
import com.seer.teach.common.enums.im.ImMqTopicEnum;
import com.seer.teach.netty.im.handler.mq.ImUserInfoHandler;
import com.seer.teach.netty.im.registry.ImUserInfoHandlerRegistry;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.rocketmq.common.message.MessageExt;
import org.springframework.stereotype.Component;

/**
 * {@code ImUserInfoConsumer} 是用于监听和消费 RocketMQ 中用户信息相关消息的消费者组件。
 * <p>
 * 该类继承自 {@link AbstractRocketMQConsumer}，绑定消息主题为 {@link ImMqTopicEnum#USER_INFO}。
 * 通过注入的 {@link ImUserInfoHandlerRegistry} 根据消息的 tag 查找对应的 {@link ImUserInfoHandler}，
 * 并将消息体反序列化后交由对应 Handler 处理。
 * </p>
 *
 * <h3>职责说明：</h3>
 * <ul>
 *     <li>初始化消费者，订阅用户信息相关 topic</li>
 *     <li>接收并解析消息 JSON 字符串</li>
 *     <li>根据消息 tag 分发给对应的业务处理器</li>
 *     <li>异常处理及日志记录</li>
 * </ul>
 *
 * @author Captain
 * @since 2025-07-15
 */
@Slf4j
@Component
@RequiredArgsConstructor
public class ImUserInfoConsumer extends AbstractRocketMQConsumer {

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

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

    /**
     * 处理收到的消息，先根据 tag 获取对应的消息处理器，
     * 然后将消息体反序列化为对应的类型，最后调用处理器执行具体业务逻辑。
     * <p>
     * 若未找到对应处理器或反序列化失败，则记录警告或错误日志。
     * </p>
     *
     * @param tag     消息标签，用于查找对应处理器
     * @param body    消息内容的 JSON 字符串
     * @param message RocketMQ 原始消息对象
     */
    @Override
    protected void doHandleMessage(String tag, String device, String body, MessageExt message) {
        ImUserInfoHandler<?> handler = handlerRegistry.getHandler(tag);
        if (handler == null) {
            log.warn("未找到对应处理器：tag={}", tag);
            return;
        }
        Object parsedObj = parseMessageBody(body, handler);
        if (parsedObj == null) return;
        invokeHandler(handler, parsedObj, device);
    }

    /**
     * 将消息体 JSON 字符串反序列化为 Handler 声明的业务对象类型。
     *
     * @param body    JSON 格式的消息体字符串
     * @param handler 具体的消息处理器，包含业务对象类型信息
     * @return 反序列化后的业务对象，若解析失败返回 {@code null}
     */
    private Object parseMessageBody(String body, ImUserInfoHandler<?> 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(ImUserInfoHandler<?> handler, Object message, String device) {
        ((ImUserInfoHandler<T>) handler).handleWithLog((T) message, device);
    }
}
