package com.lingniu.ingest.protocol.jt808.codec.parser;

import com.lingniu.ingest.codec.BcdCodec;
import com.lingniu.ingest.protocol.jt808.codec.BodyParser;
import com.lingniu.ingest.protocol.jt808.model.Jt808Body;
import com.lingniu.ingest.protocol.jt808.model.Jt808Header;
import com.lingniu.ingest.protocol.jt808.model.Jt808MessageId;

import java.nio.ByteBuffer;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.util.LinkedHashMap;
import java.util.Map;

/**
 * 0x0200 位置信息汇报。
 *
 * <p>固定 28 字节 + 可选附加项。附加项按 JT/T 808 的 ID/长度/值 TLV 保留原始字节，
 * 由上层统计或导出服务按配置解释。
 * <pre>
 *   alarmFlag(4)
 *   statusFlag(4)
 *   latitude(4)   // 1/1000000 度
 *   longitude(4)  // 1/1000000 度
 *   altitudeM(2)
 *   speed(2)      // 1/10 km/h
 *   direction(2)
 *   time(6 BCD, YYMMDDHHMMSS)
 * </pre>
 */
public final class LocationBodyParser implements BodyParser {

    @Override
    public int messageId() {
        return Jt808MessageId.TERMINAL_LOCATION;
    }

    @Override
    public Jt808Body parse(Jt808Header header, ByteBuffer buf) {
        long alarmFlag = buf.getInt() & 0xFFFFFFFFL;
        long statusFlag = buf.getInt() & 0xFFFFFFFFL;
        long latRaw = buf.getInt() & 0xFFFFFFFFL;
        long lonRaw = buf.getInt() & 0xFFFFFFFFL;
        int altitudeM = buf.getShort();
        double speed = (buf.getShort() & 0xFFFF) * 0.1;
        int direction = buf.getShort() & 0xFFFF;

        byte[] timeBcd = new byte[6];
        buf.get(timeBcd);
        String ts = BcdCodec.decode(timeBcd);

        LocalDateTime ldt = LocalDateTime.of(
                2000 + Integer.parseInt(ts.substring(0, 2)),
                Integer.parseInt(ts.substring(2, 4)),
                Integer.parseInt(ts.substring(4, 6)),
                Integer.parseInt(ts.substring(6, 8)),
                Integer.parseInt(ts.substring(8, 10)),
                Integer.parseInt(ts.substring(10, 12)));

        Map<Integer, byte[]> extensions = parseExtensions(buf);

        return new Jt808Body.Location(
                alarmFlag, statusFlag,
                lonRaw / 1_000_000.0, latRaw / 1_000_000.0,
                altitudeM, speed, direction,
                ldt.atZone(ZoneId.of("Asia/Shanghai")).toInstant(),
                extensions);
    }

    private static Map<Integer, byte[]> parseExtensions(ByteBuffer buf) {
        if (!buf.hasRemaining()) {
            return Map.of();
        }
        Map<Integer, byte[]> out = new LinkedHashMap<>();
        while (buf.remaining() >= 2) {
            int id = buf.get() & 0xFF;
            int len = buf.get() & 0xFF;
            if (len > buf.remaining()) {
                byte[] truncated = new byte[buf.remaining()];
                buf.get(truncated);
                out.put(id, truncated);
                break;
            }
            byte[] value = new byte[len];
            buf.get(value);
            out.put(id, value);
        }
        if (buf.hasRemaining()) {
            byte[] tail = new byte[buf.remaining()];
            buf.get(tail);
            out.put(0xFFFF, tail);
        }
        return Map.copyOf(out);
    }
}
