package com.lingniu.ingest.protocol.gb32960.handler;

import com.lingniu.ingest.api.ProtocolId;
import com.lingniu.ingest.api.annotation.EventEmit;
import com.lingniu.ingest.api.annotation.MessageMapping;
import com.lingniu.ingest.api.annotation.ProtocolHandler;
import com.lingniu.ingest.api.annotation.RateLimited;
import com.lingniu.ingest.api.event.VehicleEvent;
import com.lingniu.ingest.protocol.gb32960.mapper.Gb32960EventMapper;
import com.lingniu.ingest.protocol.gb32960.model.Gb32960Message;

import java.util.List;

/**
 * GB/T 32960 协议 Handler：Dispatcher 路由到此的所有 0x01~0x07 命令都委托给
 * {@link Gb32960EventMapper} 转成 {@link VehicleEvent}。
 *
 * <p>这是 GB32960 协议在通用 Dispatcher 管线里的**唯一入口** Bean——移除将导致所有
 * GB32960 帧产出的事件丢失。构造器注入 {@link Gb32960EventMapper}，全部业务逻辑限制
 * 在纯函数里，不触碰数据库 / 不做 IO。产出的事件由 Dispatcher 统一投递到 Disruptor；
 * 下游 sink 再决定写 raw archive、TDengine 历史库或转发 Kafka。
 *
 * <p>当前 32960 专用 snapshot 查询不依赖 Realtime/Location 事件表，而是通过 raw archive URI
 * 回读原始 .bin 并即时解码合并，避免不同车辆或不同子包之间做大范围 join。
 */
@ProtocolHandler(protocol = ProtocolId.GB32960)
public class Gb32960RealtimeHandler {

    private final Gb32960EventMapper mapper;

    public Gb32960RealtimeHandler(Gb32960EventMapper mapper) {
        this.mapper = mapper;
    }

    /** 实时 + 补发上报。 */
    @MessageMapping(command = {0x02, 0x03}, desc = "实时/补发上报")
    @RateLimited(perVin = 50)
    @EventEmit({VehicleEvent.Realtime.class, VehicleEvent.Location.class})
    public List<VehicleEvent> onReport(Gb32960Message msg) {
        // 这里保留 Realtime/Location 事件供实时消费者使用；历史全字段查询走 raw archive 解码。
        return mapper.toEvents(msg);
    }

    /** 车辆登入 / 登出 / 心跳：统一映射为 session 事件。 */
    @MessageMapping(command = {0x01, 0x04, 0x07}, desc = "登入/登出/心跳")
    @EventEmit({VehicleEvent.Login.class, VehicleEvent.Logout.class, VehicleEvent.Heartbeat.class})
    public List<VehicleEvent> onSession(Gb32960Message msg) {
        return mapper.toEvents(msg);
    }

    /**
     * 平台登入 / 登出（0x05 / 0x06）：外部下级平台握手，产出
     * {@link VehicleEvent.Login} / {@link VehicleEvent.Logout}，
     * vin 字段形如 {@code platform:<username>}，metadata 带 {@code kind=platform}，
     * 下游消费者可据此区分车辆会话与平台会话。
     */
    @MessageMapping(command = {0x05, 0x06}, desc = "平台登入/登出")
    @EventEmit({VehicleEvent.Login.class, VehicleEvent.Logout.class})
    public List<VehicleEvent> onPlatform(Gb32960Message msg) {
        return mapper.toEvents(msg);
    }
}
