package com.huangzj.comm.crosslink;

import com.huangzj.base.frame.NettyBufUtil;
import com.huangzj.cmd.gen.CmdRpcEnvelope;
import io.netty.buffer.ByteBuf;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.SimpleChannelInboundHandler;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;

/**
 * 区服进程内：跨服经长连接发回的入站帧处理。
 *
 * <p>跨服回包目的地是 <strong>区服</strong>（本进程），不是游戏客户端。客户端只连 {@link
 * com.huangzj.server.net.ClientTcpServer}；经跨服的逻辑由区服命令里 {@link CrossTcpClient#roundTrip} 等对跨服发包，
 * 回包仍回到本 Handler，再按 {@link CmdRpcEnvelope#getLinkSeq()} 唤醒区服侧等待线程。
 *
 * <p>命名说明：相对「游戏客户端」而言这里是 <strong>Server（区服）</strong> 侧；TCP 上区服对跨服仍是主动建连方，故
 * 建连类仍叫 {@link CrossTcpClient}。
 */
@Slf4j
@RequiredArgsConstructor
public class CrossServerInboundHandler extends SimpleChannelInboundHandler<ByteBuf> {

    private final CrossTcpClient client;

    /** 一帧一 CmdRpcEnvelope，按 link_seq 配对区服内 pending 的 roundTrip/注册/心跳。 */
    @Override
    protected void channelRead0(ChannelHandlerContext ctx, ByteBuf msg) throws Exception {
        byte[] raw = NettyBufUtil.readReadableBytes(msg);
        CmdRpcEnvelope env = CmdRpcEnvelope.parseFrom(raw);
        client.dispatchInbound(env);
    }

    /**
     * 对端正常 FIN：未完成的 roundTrip/注册/心跳必须以异常结束，否则 {@link
     * java.util.concurrent.CompletableFuture#get} 会一直挂起。
     */
    @Override
    public void channelInactive(ChannelHandlerContext ctx) {
        log.warn("Cross inbound channel inactive remote={}", ctx.channel().remoteAddress());
        client.failAllPending(new java.io.IOException("cross inactive"));
    }

    /** 半包、PB 损坏、对端 RST 等：先失败所有 pending，再关 channel 防止重复读脏数据。 */
    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {
        log.error("Cross inbound error remote={}", ctx.channel().remoteAddress(), cause);
        client.failAllPending(cause);
        ctx.close();
    }
}
