package com.zksy.pressure.utils;

import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.SerializationFeature;
import com.zksy.pressure.domain.FirefightingPressure;
import lombok.extern.slf4j.Slf4j;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.math.BigDecimal;
import java.math.BigInteger;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.ArrayList;
import java.util.List;

@Slf4j
public class DataParser {
    private static Logger logger = LoggerFactory.getLogger(DataParser.class);

    public static FirefightingPressure parseMessage(String msgString) {
        DateTimeFormatter formatterSend = DateTimeFormatter.ofPattern("yyMMddHHmmss");
        DateTimeFormatter formatterObs = DateTimeFormatter.ofPattern("yyMMddHHmm");
        FirefightingPressure result = new FirefightingPressure();
        try {
            List<String> dataParts = new ArrayList<>();
            for (int i = 0; i < msgString.length(); i += 2) {
                int end = Math.min(i + 2, msgString.length());
                dataParts.add(msgString.substring(i, end));
            }

            // 固定头部字段
            getStringList(dataParts, 2); // 帧头7E7E
            result.setCentralStation(getStringList(dataParts, 1));
            result.setTelemeteringStation(getStringList(dataParts, 5));
            result.setPassword(getStringList(dataParts, 2));
            String functionCode = getStringList(dataParts, 1);
            result.setFunctionCode(functionCode);
            if("EF".equals(functionCode)){
                return result;
            }
            getStringList(dataParts, 3); // 长度+起始符
            result.setSerialNumber(getStringList(dataParts, 2));
            // 发报时间
            String sendTimeHex = getStringList(dataParts, 6);
            LocalDateTime sendTime = LocalDateTime.parse(sendTimeHex, formatterSend);
            result.setSendingTime(sendTime);

            getStringList(dataParts, 2); // F1F1
            getStringList(dataParts, 5); // 遥测站地址
            getStringList(dataParts, 1); // 48
            getStringList(dataParts, 2); // F0F0

            // 观测时间
            String obsTimeHex = getStringList(dataParts, 5);
            LocalDateTime obsTime = LocalDateTime.parse(obsTimeHex, formatterObs);
            result.setObservedTime(obsTime);

            // ========== TLV数据区解析 ==========
            while (dataParts.size() > 3) { // 保证能到达结束符03
                String tag1 = shiftFromList(dataParts);
                if ("03".equals(tag1)) break; // 报文结束符
                String tag2 = shiftFromList(dataParts);
                String tag = tag1 + tag2;

                // 长度字节
                String lenByteHex = shiftFromList(dataParts);
                int lenByte = Integer.parseInt(lenByteHex, 16);
                int dataLen = (lenByte >> 3) & 0x1F;
                int decimal = lenByte & 0x07;

                StringBuilder valueHex = new StringBuilder();
                for (int i = 0; i < dataLen; i++) {
                    valueHex.append(shiftFromList(dataParts));
                }

                // 解析具体数据
                switch (tag.toUpperCase()) {
                    case "FF01": // GPRS信号质量
                        result.setGprsSignal(parseValue(valueHex.toString(), decimal));
                        break;
                    case "FF03": // 主机电池电压
                        result.setHostVoltage(parseValue(valueHex.toString(), decimal));
                        break;
                    case "FF0E": // 经度
                        result.setLongitude(new BigDecimal(parseValue(valueHex.toString(), decimal)));
                        break;
                    case "FF0F": // 纬度
                        result.setLatitude(new BigDecimal(parseValue(valueHex.toString(), decimal)));
                        break;
                    case "581A": // 压力值（固定2字节，2位小数）
                        if (valueHex.length() == 0) {
                            valueHex.append(shiftFromList(dataParts));
                            valueHex.append(shiftFromList(dataParts));
                        }
                        result.setPressureValue(parseValue(valueHex.toString(), 2));
                        break;
                    case "4520": // 开关量（固定4字节）
                        if (valueHex.length() == 0) {
                            for (int i = 0; i < 4; i++) {
                                valueHex.append(shiftFromList(dataParts));
                            }
                        }
                        parseSwitchStatus(result, valueHex.toString());
                        break;
                    default:
                        logger.warn("未识别的Tag: {} 值: {}", tag, valueHex);
                        break;
                }
            }

            result.setCreateTime(LocalDateTime.now());

        } catch (Exception e) {
            logger.error("解析消息时出错", e);
        }
        return result;
    }

    /**
     * 把HEX转成数值，考虑小数位
     */
    private static Double parseValue(String hex, int decimal) {
        if (hex == null || hex.isEmpty()) return null;
        long value = Long.parseLong(hex, 16);
        return value / Math.pow(10, decimal);
    }

    /**
     * 解析开关量D31~D0
     */
    private static void parseSwitchStatus(FirefightingPressure result, String hex) {
        if (hex == null || hex.length() != 8) {
            logger.error("开关量格式错误，需要8位十六进制字符串，实际={}", hex);
            return;
        }

        // 1. 将8位十六进制字符串转成4字节的小端整数
        long status;
        try {
            // 先按大端解析成32位整数
            int intValue = Integer.parseUnsignedInt(hex, 16);
            // 再转换为小端字节序
            byte[] bytes = ByteBuffer.allocate(4)
                    .order(ByteOrder.BIG_ENDIAN)
                    .putInt(intValue)
                    .array();
            // 小端模式读取
            status = ByteBuffer.wrap(bytes)
                    .order(ByteOrder.LITTLE_ENDIAN)
                    .getInt() & 0xFFFFFFFFL;
        } catch (NumberFormatException e) {
            logger.error("开关量解析失败，hex={}", hex, e);
            return;
        }

        // 2. 解析各个开关状态
        result.setD0((int) (status & 1));
        result.setD1((int) ((status >> 1) & 1));
        result.setD2((int) ((status >> 2) & 1));
        result.setD3((int) ((status >> 3) & 1));
        result.setD4((int) ((status >> 4) & 1));
        result.setD5((int) ((status >> 5) & 1));
        result.setD6((int) ((status >> 6) & 1));
        result.setD7((int) ((status >> 7) & 1));
        result.setD8((int) ((status >> 8) & 1));
        result.setD9((int) ((status >> 9) & 1));
        result.setD10((int) ((status >> 10) & 1));
        result.setD11((int) ((status >> 11) & 1));
        result.setD12((int) ((status >> 12) & 1));
        result.setD13((int) ((status >> 13) & 1));
        result.setD14((int) ((status >> 14) & 1));
    }

    public static String shiftFromList(List<String> list) {
        if (list == null || list.isEmpty()) {
            return null;
        }
        return list.remove(0);
    }

    private static String getStringList(List<String> dataParts, Integer q) {
        StringBuilder res1 = new StringBuilder();
        for (int i = 0; i < q; i++) {
            res1.append(shiftFromList(dataParts));
        }
        return res1.toString();
    }

    public static void main(String[] args) throws Exception {
        // 样例报文
        String hexMsg = "7E7E0113021000071234E6003A020111250911163950F1F1130210000748F0F02509111638"
                + "FF01100031"
                + "FF03120370"
                + "FF0E2500000000"
                + "FF0F2500000000"
                + "581A000280"
                + "452002280000"
                + "039E83";

        FirefightingPressure pressure = DataParser.parseMessage(hexMsg);

        ObjectMapper mapper = new ObjectMapper();
        mapper.findAndRegisterModules();
        mapper.disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS); // 时间转ISO字符串
        String jsonResult = mapper.writerWithDefaultPrettyPrinter().writeValueAsString(pressure);

        System.out.println("解析结果：\n" + jsonResult);
    }
}
