/*
 * 文 件 名:  FrameParser
 * 版    权:  华设设计集团股份有限公司
 * 描    述:  协议帧解析器
 * 修 改 人:  lvwenbin
 * 修改时间:  2025/12/25
 * 修改内容:  添加错误报文、交易记录、远程停机应答的解析支持
 */
package com.ruoyi.ems.charging.protocol;

import com.ruoyi.ems.charging.model.BaseFrame;
import com.ruoyi.ems.charging.model.req.ChargingEndFrame;
import com.ruoyi.ems.charging.model.req.ChargingHandshakeFrame;
import com.ruoyi.ems.charging.model.req.ErrorReportFrame;
import com.ruoyi.ems.charging.model.req.HeartbeatReqFrame;
import com.ruoyi.ems.charging.model.req.LoginReqFrame;
import com.ruoyi.ems.charging.model.req.RealtimeDataFrame;
import com.ruoyi.ems.charging.model.req.RemoteStopRespFrame;
import com.ruoyi.ems.charging.model.req.TransactionRecordFrame;
import com.ruoyi.ems.charging.model.req.WorkParamSetRespFrame;
import com.ruoyi.ems.charging.utils.CRC16Utils;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * 协议帧解析器
 * 负责解析充电桩上送的各类消息帧
 *
 * @author lvwenbin
 * @version [版本号, 2025/12/25]
 */
public class FrameParser {

    private static final Logger log = LoggerFactory.getLogger(FrameParser.class);

    /**
     * 解析帧数据
     *
     * @param data 原始字节数据
     * @return 解析后的帧对象，解析失败返回null
     */
    public static BaseFrame parse(byte[] data) {
        if (data == null || data.length < 6) {
            log.warn("数据长度不足，无法解析");
            return null;
        }

        ByteBuf buf = Unpooled.wrappedBuffer(data);
        try {
            return parse(buf);
        } finally {
            buf.release();
        }
    }

    /**
     * 解析帧数据
     *
     * @param buf ByteBuf
     * @return 解析后的帧对象，解析失败返回null
     */
    public static BaseFrame parse(ByteBuf buf) {
        if (buf.readableBytes() < 6) {
            log.warn("数据长度不足，无法解析");
            return null;
        }

        // 标记读取位置
        buf.markReaderIndex();

        // 读取并验证起始标志
        byte startFlag = buf.readByte();
        if (startFlag != ProtocolConstants.START_FLAG) {
            log.warn("起始标志错误: 0x{}", String.format("%02X", startFlag & 0xFF));
            buf.resetReaderIndex();
            return null;
        }

        // 读取数据长度
        int dataLength = buf.readByte() & 0xFF;

        // 检查数据完整性
        if (buf.readableBytes() < dataLength + 2) { // 数据域 + CRC
            log.warn("数据不完整，期望长度: {}, 实际可读: {}", dataLength + 2, buf.readableBytes());
            buf.resetReaderIndex();
            return null;
        }

        // 验证CRC
        int crcStartIndex = buf.readerIndex();
        byte[] crcData = new byte[dataLength];
        buf.getBytes(crcStartIndex, crcData);
        int calculatedCrc = CRC16Utils.calculateCRC(crcData);

        // 读取接收到的CRC
        int receivedCrc = buf.getShortLE(crcStartIndex + dataLength) & 0xFFFF;

        if (calculatedCrc != receivedCrc) {
            log.warn("CRC校验失败，计算值: 0x{}, 接收值: 0x{}",
                String.format("%04X", calculatedCrc),
                String.format("%04X", receivedCrc));
            buf.resetReaderIndex();
            return null;
        }

        // 读取序列号、加密标志、帧类型
        int sequenceNo = buf.readShortLE() & 0xFFFF;
        byte encryptFlag = buf.readByte();
        byte frameType = buf.readByte();

        // 根据帧类型创建对应的帧对象
        BaseFrame frame = createFrame(frameType);
        if (frame == null) {
            log.warn("未知的帧类型: 0x{}", String.format("%02X", frameType & 0xFF));
            buf.resetReaderIndex();
            return null;
        }

        // 重置读取位置到起始标志
        buf.resetReaderIndex();

        // 解码完整帧
        if (!frame.decode(buf)) {
            log.warn("帧解码失败: {}", frame.getClass().getSimpleName());
            return null;
        }

        log.debug("解析帧成功: {}", frame);
        return frame;
    }

    /**
     * 根据帧类型创建对应的帧对象
     *
     * @param frameType 帧类型
     * @return 帧对象
     */
    private static BaseFrame createFrame(byte frameType) {
        switch (frameType) {
            // ==================== 充电桩发起的帧(奇数) ====================
            
            // 登录认证 (0x01)
            case ProtocolConstants.FRAME_TYPE_LOGIN_REQ:
                return new LoginReqFrame();
            
            // 心跳请求 (0x03)
            case ProtocolConstants.FRAME_TYPE_HEARTBEAT_REQ:
                return new HeartbeatReqFrame();
            
            // 实时监测数据 (0x13)
            case ProtocolConstants.FRAME_TYPE_REALTIME_DATA:
                return new RealtimeDataFrame();
            
            // 充电握手 (0x15)
            case ProtocolConstants.FRAME_TYPE_CHARGING_HANDSHAKE:
                return new ChargingHandshakeFrame();
            
            // 充电结束 (0x19)
            case ProtocolConstants.FRAME_TYPE_CHARGING_END:
                return new ChargingEndFrame();
            
            // 错误报文 (0x1B) - 新增
            case ProtocolConstants.FRAME_TYPE_ERROR:
                return new ErrorReportFrame();
            
            // 远程停机命令回复 (0x35) - 新增
            case ProtocolConstants.FRAME_TYPE_REMOTE_STOP_RESP:
                return new RemoteStopRespFrame();
            
            // 交易记录 (0x3B) - 新增
            case ProtocolConstants.FRAME_TYPE_TRANSACTION:
                return new TransactionRecordFrame();
            
            // 工作参数设置应答 (0x51)
            case ProtocolConstants.FRAME_TYPE_WORK_PARAM_SET_RESP:
                return new WorkParamSetRespFrame();
            
            default:
                // 对于未实现的帧类型，使用通用帧处理
                return new GenericFrame(frameType);
        }
    }

    /**
     * 从ByteBuf中查找帧起始位置
     *
     * @param buf ByteBuf
     * @return 起始位置索引，未找到返回-1
     */
    public static int findFrameStart(ByteBuf buf) {
        int readerIndex = buf.readerIndex();
        while (buf.readableBytes() > 0) {
            byte b = buf.readByte();
            if (b == ProtocolConstants.START_FLAG) {
                int startIndex = buf.readerIndex() - 1;
                buf.readerIndex(readerIndex);
                return startIndex - readerIndex;
            }
        }
        buf.readerIndex(readerIndex);
        return -1;
    }

    /**
     * 获取完整帧长度
     *
     * @param buf ByteBuf
     * @return 帧长度，数据不完整返回-1
     */
    public static int getFrameLength(ByteBuf buf) {
        if (buf.readableBytes() < 2) {
            return -1;
        }
        buf.markReaderIndex();
        buf.skipBytes(1); // 跳过起始标志
        int dataLength = buf.readByte() & 0xFF;
        buf.resetReaderIndex();

        // 完整帧长度 = 起始标志(1) + 数据长度(1) + 数据域(dataLength) + CRC(2)
        return 1 + 1 + dataLength + 2;
    }

    /**
     * 通用帧 - 用于处理未实现的帧类型
     */
    private static class GenericFrame extends BaseFrame {
        private byte type;
        private byte[] bodyData;

        public GenericFrame(byte type) {
            this.type = type;
        }

        @Override
        public byte getFrameType() {
            return type;
        }

        @Override
        protected void encodeBody(ByteBuf buf) {
            if (bodyData != null) {
                buf.writeBytes(bodyData);
            }
        }

        @Override
        protected void decodeBody(ByteBuf buf) {
            if (buf.readableBytes() > 0) {
                bodyData = new byte[buf.readableBytes()];
                buf.readBytes(bodyData);
            }
        }

        @Override
        public String toString() {
            return String.format("GenericFrame[type=0x%02X, bodyLen=%d]",
                type & 0xFF, bodyData != null ? bodyData.length : 0);
        }
    }
}
