/*
 * 文 件 名:  ChargingPileDecoder
 * 版    权:  华设设计集团股份有限公司
 * 描    述:  充电桩协议解码器
 * 修 改 人:  lvwenbin
 * 修改时间:  2025/12/22
 */
package com.ruoyi.ems.charging.core;

import com.ruoyi.ems.charging.model.BaseFrame;
import com.ruoyi.ems.charging.protocol.FrameParser;
import com.ruoyi.ems.charging.protocol.ProtocolConstants;
import com.ruoyi.ems.charging.utils.ByteUtils;
import io.netty.buffer.ByteBuf;
import io.netty.channel.ChannelHandlerContext;
import io.netty.handler.codec.ByteToMessageDecoder;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.List;

/**
 * 充电桩协议解码器
 * 负责从TCP流中提取完整的协议帧并解码
 *
 * @author lvwenbin
 * @version [版本号, 2025/12/22]
 */
public class ChargingPileDecoder extends ByteToMessageDecoder {

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

    /**
     * 最小帧长度: 起始标志(1) + 数据长度(1) + 序列号(2) + 加密标志(1) + 帧类型(1) + CRC(2) = 8
     */
    private static final int MIN_FRAME_LENGTH = 8;

    /**
     * 最大帧长度: 起始标志(1) + 数据长度(1) + 数据域(200) + CRC(2) = 204
     */
    private static final int MAX_FRAME_LENGTH = 204;

    @Override
    protected void decode(ChannelHandlerContext ctx, ByteBuf in, List<Object> out) throws Exception {
        // 循环处理，直到没有完整帧可读
        while (in.readableBytes() >= MIN_FRAME_LENGTH) {
            // 标记当前位置
            in.markReaderIndex();

            // 查找起始标志
            int startIndex = findStartFlag(in);
            if (startIndex < 0) {
                // 没有找到起始标志，丢弃所有数据
                log.debug("未找到起始标志，丢弃{}字节数据", in.readableBytes());
                in.skipBytes(in.readableBytes());
                return;
            }

            // 跳过起始标志之前的数据
            if (startIndex > 0) {
                log.debug("丢弃起始标志之前的{}字节数据", startIndex);
                in.skipBytes(startIndex);
            }

            // 检查剩余数据是否足够读取帧头
            if (in.readableBytes() < 2) {
                return;
            }

            // 读取起始标志和数据长度
            in.markReaderIndex();
            byte startFlag = in.readByte();
            int dataLength = in.readByte() & 0xFF;

            // 验证数据长度
            if (dataLength > ProtocolConstants.MAX_DATA_LENGTH) {
                log.warn("数据长度超限: {}, 最大允许: {}", dataLength, ProtocolConstants.MAX_DATA_LENGTH);
                // 跳过这个错误的起始标志，继续查找下一个
                in.resetReaderIndex();
                in.skipBytes(1);
                continue;
            }

            // 计算完整帧长度
            int frameLength = 1 + 1 + dataLength + 2; // 起始标志 + 数据长度 + 数据域 + CRC

            // 检查数据是否足够
            in.resetReaderIndex();
            if (in.readableBytes() < frameLength) {
                // 数据不完整，等待更多数据
                log.debug("数据不完整，期望长度: {}, 实际可读: {}", frameLength, in.readableBytes());
                return;
            }

            // 读取完整帧数据
            byte[] frameData = new byte[frameLength];
            in.readBytes(frameData);

            // 调试日志
            if (log.isDebugEnabled()) {
                log.debug("收到原始数据[{}字节]: {}", frameData.length, ByteUtils.bytesToHex(frameData));
            }

            // 解析帧
            BaseFrame frame = FrameParser.parse(frameData);
            if (frame != null) {
                out.add(frame);
                log.debug("解码成功: {}", frame);
            }
            else {
                log.warn("帧解析失败，丢弃数据: {}", ByteUtils.bytesToHex(frameData));
            }
        }
    }

    /**
     * 查找起始标志位置
     *
     * @param buf ByteBuf
     * @return 起始标志相对于当前读取位置的偏移量，未找到返回-1
     */
    private int findStartFlag(ByteBuf buf) {
        int readerIndex = buf.readerIndex();
        int readableBytes = buf.readableBytes();

        for (int i = 0; i < readableBytes; i++) {
            if (buf.getByte(readerIndex + i) == ProtocolConstants.START_FLAG) {
                return i;
            }
        }
        return -1;
    }

    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
        log.error("解码器异常: {}", cause.getMessage(), cause);
        ctx.close();
    }
}
