package com.ruoyi.mill.protocol;

import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.nio.charset.StandardCharsets;
import java.util.Arrays;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;

/**
 * iXComPCS UDP 电文编解码器（第18章协议）
 *
 * 编码规则：
 *   字符型 → 固定长度，右侧以 0x20(空格) 填充，超长截断
 *   整型   → 4 字节，大端序 (BIG_ENDIAN)
 *   浮点型 → 4 字节 IEEE-754，小端序 (LITTLE_ENDIAN)
 *   长整型 → 8 字节，大端序
 */
public class TelegramCodec {

    private TelegramCodec() {}

    /** 将字段 Map 按字段定义顺序序列化为字节数组 */
    public static byte[] encode(List<FieldDef> schema, Map<String, Object> data) {
        int totalLen = calcTotalLength(schema);
        ByteBuffer buf = ByteBuffer.allocate(totalLen);

        for (FieldDef fd : schema) {
            Object val = data.getOrDefault(fd.getName(), defaultValue(fd));
            switch (fd.getType()) {
                case STRING: {
                    String s = val == null ? "" : val.toString();
                    byte[] bytes = s.getBytes(StandardCharsets.US_ASCII);
                    byte[] fixed = new byte[fd.getLength()];
                    Arrays.fill(fixed, (byte) 0x20);
                    System.arraycopy(bytes, 0, fixed, 0, Math.min(bytes.length, fixed.length));
                    buf.put(fixed);
                    break;
                }
                case INT: {
                    int i = val instanceof Number ? ((Number) val).intValue() : 0;
                    buf.order(ByteOrder.BIG_ENDIAN).putInt(i);
                    break;
                }
                case FLOAT: {
                    float f = val instanceof Number ? ((Number) val).floatValue() : 0f;
                    buf.order(ByteOrder.LITTLE_ENDIAN).putFloat(f);
                    break;
                }
                case LONG: {
                    long l = val instanceof Number ? ((Number) val).longValue() : 0L;
                    buf.order(ByteOrder.BIG_ENDIAN).putLong(l);
                    break;
                }
            }
        }
        return buf.array();
    }

    /** 将字节数组按字段定义顺序反序列化为字段 Map */
    public static Map<String, Object> decode(List<FieldDef> schema, byte[] raw) {
        ByteBuffer buf = ByteBuffer.wrap(raw);
        Map<String, Object> result = new LinkedHashMap<>();

        for (FieldDef fd : schema) {
            if (buf.remaining() < fd.getLength()) break;
            switch (fd.getType()) {
                case STRING: {
                    byte[] bytes = new byte[fd.getLength()];
                    buf.get(bytes);
                    String s = new String(bytes, StandardCharsets.US_ASCII).replaceAll("\\s+$", "");
                    result.put(fd.getName(), s);
                    break;
                }
                case INT: {
                    result.put(fd.getName(), buf.order(ByteOrder.BIG_ENDIAN).getInt());
                    break;
                }
                case FLOAT: {
                    result.put(fd.getName(), buf.order(ByteOrder.LITTLE_ENDIAN).getFloat());
                    break;
                }
                case LONG: {
                    result.put(fd.getName(), buf.order(ByteOrder.BIG_ENDIAN).getLong());
                    break;
                }
            }
        }
        return result;
    }

    private static int calcTotalLength(List<FieldDef> schema) {
        return schema.stream().mapToInt(FieldDef::getLength).sum();
    }

    private static Object defaultValue(FieldDef fd) {
        switch (fd.getType()) {
            case INT:   return 0;
            case FLOAT: return 0.0f;
            case LONG:  return 0L;
            default:    return "";
        }
    }
}
