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

import com.lingniu.ingest.protocol.jt808.codec.parser.HeartbeatBodyParser;
import com.lingniu.ingest.protocol.jt808.codec.parser.LocationBodyParser;
import com.lingniu.ingest.protocol.jt808.codec.parser.RegisterBodyParser;
import com.lingniu.ingest.protocol.jt808.model.Jt808Message;
import org.junit.jupiter.api.DynamicTest;
import org.junit.jupiter.api.TestFactory;

import java.io.IOException;
import java.net.URISyntaxException;
import java.nio.ByteBuffer;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.Collection;
import java.util.List;
import java.util.stream.Collectors;
import java.util.stream.Stream;

import static org.assertj.core.api.Assertions.assertThat;

/**
 * JT808 黄金样本集回放测试：遍历 {@code src/test/resources/samples/jt808/*.hex}。
 *
 * <p>样本文件格式：一行十六进制（完整 0x7e 包裹帧），脚本脱敏产出。
 * 测试会去掉首尾 0x7e，执行反转义后调用 {@link Jt808MessageDecoder}。
 */
class Jt808DecoderGoldenTest {

    private final Jt808MessageDecoder decoder = new Jt808MessageDecoder(
            new BodyParserRegistry(List.of(
                    new RegisterBodyParser(),
                    new LocationBodyParser(),
                    new HeartbeatBodyParser())));

    @TestFactory
    Collection<DynamicTest> replaySamples() throws URISyntaxException, IOException {
        var url = getClass().getClassLoader().getResource("samples/jt808");
        if (url == null) return List.of();
        Path dir = Paths.get(url.toURI());
        try (Stream<Path> s = Files.list(dir)) {
            return s.filter(p -> p.toString().endsWith(".hex"))
                    .sorted()
                    .map(this::toTest)
                    .collect(Collectors.toList());
        }
    }

    private DynamicTest toTest(Path sample) {
        return DynamicTest.dynamicTest(sample.getFileName().toString(), () -> {
            byte[] framed = readHex(sample);
            assertThat(framed[0]).as("must start with 0x7e").isEqualTo((byte) 0x7e);
            assertThat(framed[framed.length - 1]).as("must end with 0x7e").isEqualTo((byte) 0x7e);

            byte[] unescaped = Jt808Escape.unescape(framed, 1, framed.length - 2);
            Jt808Message msg = decoder.decode(ByteBuffer.wrap(unescaped));

            assertThat(msg.header().messageId()).isNotNegative();
            assertThat(msg.header().phone()).isNotEmpty();
        });
    }

    private static byte[] readHex(Path path) throws IOException {
        StringBuilder sb = new StringBuilder();
        for (String line : Files.readAllLines(path)) {
            String trimmed = line.trim();
            if (trimmed.isEmpty() || trimmed.startsWith("#")) continue;
            sb.append(trimmed);
        }
        String hex = sb.toString();
        int len = hex.length() / 2;
        byte[] out = new byte[len];
        for (int i = 0; i < len; i++) {
            out[i] = (byte) Integer.parseInt(hex.substring(i * 2, i * 2 + 2), 16);
        }
        return out;
    }
}
