package com.huangzj.base.cmd;

import com.huangzj.cmd.gen.CmdRpcEnvelope;
import com.google.protobuf.Message;
import io.netty.channel.ChannelHandlerContext;
import lombok.extern.slf4j.Slf4j;

/**
 * Netty 入站：先解析CmdRpcEnvelope，再按 {@link ProtoRegistry} 取 {@link ProtoInfo} 做 CTS 解码与 STC Builder 创建（网络层职责），
 * 最后交给 {@link CmdRpcDispatch}。
 */
@Slf4j
public final class CmdRpcChannelDispatch {

    private CmdRpcChannelDispatch() {
    }

    /**
     * @param linkSource   当前链路（客户端 TCP / 跨服 TCP），与注册表 {@link ProtoInfo#source()} 一致
     * @param protoRegistry PB 元数据表，在应用启动时完成注册
     */
    public static CmdRpcEnvelope dispatch(
            byte[] raw,
            GameCommandLookup lookup,
            ChannelHandlerContext ctx,
            CrossRpcInvoker crossRpc,
            CommandSource linkSource,
            ProtoRegistry protoRegistry)
            throws Exception {
        CmdRpcEnvelope in = CmdRpcEnvelope.parseFrom(raw);
        // 同一套 service/method，在 Client_TCP 与 CROSS_TCP 可对应不同 ProtoInfo（来源隔离）
        ProtoInfo protoInfo = protoRegistry.resolve(linkSource, in.getServiceId(), in.getMethodId());
        if (log.isDebugEnabled()) {
            log.debug(
                    "CmdRpc inbound source={} remote={} service={} method={} protoInfo={}",
                    linkSource,
                    ctx.channel().remoteAddress(),
                    in.getServiceId(),
                    in.getMethodId(),
                    protoInfo != null);
        }
        Message decoded = null;
        Message.Builder responseBuilder = null;
        if (protoInfo != null) {
            // 强类型命令：网络层负责 bytes→CTS、预创建 STC Builder，命令里只填字段
            decoded = ProtoCommandReflect.parser(protoInfo.ctsClass()).parseFrom(in.getPayload());
            responseBuilder = ProtoCommandReflect.builderSupplier(protoInfo.stcClass()).get();
        }
        // protoInfo==null 时（如纯中继）由具体 GameCommand 自行解析 payload / 组包
        CommandContext cctx =
                new CommandContext(ctx, crossRpc, in.getCrossRet(), protoInfo, decoded, responseBuilder);
        return CmdRpcDispatch.dispatchEnvelope(in, lookup, cctx);
    }
}
