/*
 * 文 件 名:  ErrorReportFrame
 * 版    权:  华设设计集团股份有限公司
 * 描    述:  错误报文帧
 * 修 改 人:  lvwenbin
 * 修改时间:  2025/12/25
 */
package com.ruoyi.ems.charging.model.req;

import com.ruoyi.ems.charging.model.BaseFrame;
import com.ruoyi.ems.charging.protocol.ProtocolConstants;
import com.ruoyi.ems.charging.utils.ByteUtils;
import io.netty.buffer.ByteBuf;
import lombok.Data;
import lombok.EqualsAndHashCode;

import java.util.ArrayList;
import java.util.List;

/**
 * 错误报文帧 (0x1B)
 * GBT-27930 充电桩与BMS充电错误报文
 * 用于上报充电过程中的通信超时等异常情况
 *
 * @author lvwenbin
 * @version [版本号, 2025/12/25]
 */
@Data
@EqualsAndHashCode(callSuper = true)
public class ErrorReportFrame extends BaseFrame {

    /**
     * 交易流水号 (BCD码 16字节)
     */
    private String transactionNo;

    /**
     * 桩编号 (BCD码 7字节)
     */
    private String pileCode;

    /**
     * 枪号 (BCD码 1字节)
     */
    private String gunNo;

    /**
     * 错误字节1 - BMS侧超时错误
     * Bit0-1: 接收SPN2560=0x00的充电机辨识报文超时
     * Bit2-3: 接收SPN2560=0xAA的充电机辨识报文超时
     * Bit4-7: 预留位
     */
    private int errorByte1;

    /**
     * 错误字节2 - BMS侧超时错误
     * Bit0-1: 接收充电机的时间同步和充电机最大输出能力报文超时
     * Bit2-3: 接收充电机完成充电准备报文超时
     * Bit4-7: 预留位
     */
    private int errorByte2;

    /**
     * 错误字节3 - BMS侧超时错误
     * Bit0-1: 接收充电机充电状态报文超时
     * Bit2-3: 接收充电机中止充电报文超时
     * Bit4-7: 预留位
     */
    private int errorByte3;

    /**
     * 错误字节4 - BMS侧超时错误
     * Bit0-1: 接收充电机充电统计报文超时
     * Bit2-7: BMS其他
     */
    private int errorByte4;

    /**
     * 错误字节5 - 充电机侧超时错误
     * Bit0-1: 接收BMS和车辆的辨识报文超时
     * Bit2-7: 预留位
     */
    private int errorByte5;

    /**
     * 错误字节6 - 充电机侧超时错误
     * Bit0-1: 接收电池充电参数报文超时
     * Bit2-3: 接收BMS完成充电准备报文超时
     * Bit4-7: 预留位
     */
    private int errorByte6;

    /**
     * 错误字节7 - 充电机侧超时错误
     * Bit0-1: 接收电池充电总状态报文超时
     * Bit2-3: 接收电池充电要求报文超时
     * Bit4-5: 接收BMS中止充电报文超时
     * Bit6-7: 预留位
     */
    private int errorByte7;

    /**
     * 错误字节8 - 充电机侧超时错误
     * Bit0-1: 接收BMS充电统计报文超时
     * Bit2-7: 充电机其他
     */
    private int errorByte8;

    @Override
    public byte getFrameType() {
        return ProtocolConstants.FRAME_TYPE_ERROR;
    }

    @Override
    protected void encodeBody(ByteBuf buf) {
        ByteUtils.writeBcd(buf, transactionNo, 16);
        ByteUtils.writeBcd(buf, pileCode, 7);
        ByteUtils.writeBcd(buf, gunNo, 1);
        buf.writeByte(errorByte1);
        buf.writeByte(errorByte2);
        buf.writeByte(errorByte3);
        buf.writeByte(errorByte4);
        buf.writeByte(errorByte5);
        buf.writeByte(errorByte6);
        buf.writeByte(errorByte7);
        buf.writeByte(errorByte8);
    }

    @Override
    protected void decodeBody(ByteBuf buf) {
        this.transactionNo = ByteUtils.readBcd(buf, 16);
        this.pileCode = ByteUtils.readBcd(buf, 7);
        this.gunNo = ByteUtils.readBcd(buf, 1);
        this.errorByte1 = buf.readByte() & 0xFF;
        this.errorByte2 = buf.readByte() & 0xFF;
        this.errorByte3 = buf.readByte() & 0xFF;
        this.errorByte4 = buf.readByte() & 0xFF;
        this.errorByte5 = buf.readByte() & 0xFF;
        this.errorByte6 = buf.readByte() & 0xFF;
        this.errorByte7 = buf.readByte() & 0xFF;
        this.errorByte8 = buf.readByte() & 0xFF;
    }

    /**
     * 获取完整枪号
     */
    public String getFullGunNo() {
        return pileCode + gunNo;
    }

    /**
     * 是否有错误
     */
    public boolean hasError() {
        return errorByte1 != 0 || errorByte2 != 0 || errorByte3 != 0 || errorByte4 != 0
            || errorByte5 != 0 || errorByte6 != 0 || errorByte7 != 0 || errorByte8 != 0;
    }

    /**
     * 获取错误描述列表
     * 对于能源管理平台，简化处理，只需要知道是否有通信异常
     */
    public List<String> getErrorDescriptions() {
        List<String> errors = new ArrayList<>();

        // BMS侧错误
        if (getBitValue(errorByte1, 0, 2) == 1) {
            errors.add("BMS:充电机辨识报文超时");
        }
        if (getBitValue(errorByte2, 0, 2) == 1) {
            errors.add("BMS:充电机时间同步报文超时");
        }
        if (getBitValue(errorByte2, 2, 2) == 1) {
            errors.add("BMS:充电机准备报文超时");
        }
        if (getBitValue(errorByte3, 0, 2) == 1) {
            errors.add("BMS:充电机状态报文超时");
        }
        if (getBitValue(errorByte3, 2, 2) == 1) {
            errors.add("BMS:充电机中止报文超时");
        }

        // 充电机侧错误
        if (getBitValue(errorByte5, 0, 2) == 1) {
            errors.add("充电机:BMS辨识报文超时");
        }
        if (getBitValue(errorByte6, 0, 2) == 1) {
            errors.add("充电机:电池参数报文超时");
        }
        if (getBitValue(errorByte6, 2, 2) == 1) {
            errors.add("充电机:BMS准备报文超时");
        }
        if (getBitValue(errorByte7, 0, 2) == 1) {
            errors.add("充电机:电池状态报文超时");
        }
        if (getBitValue(errorByte7, 2, 2) == 1) {
            errors.add("充电机:电池要求报文超时");
        }
        if (getBitValue(errorByte7, 4, 2) == 1) {
            errors.add("充电机:BMS中止报文超时");
        }

        return errors;
    }

    /**
     * 获取错误摘要（简化版，适合能源管理场景）
     */
    public String getErrorSummary() {
        if (!hasError()) {
            return "无错误";
        }
        List<String> errors = getErrorDescriptions();
        if (errors.isEmpty()) {
            return "通信异常";
        }
        return String.join("; ", errors);
    }

    /**
     * 从字节中提取指定位的值
     */
    private int getBitValue(int byteValue, int startBit, int bitCount) {
        int mask = (1 << bitCount) - 1;
        return (byteValue >> startBit) & mask;
    }

    @Override
    public String toString() {
        return String.format(
            "ErrorReportFrame[transNo=%s, pile=%s, gun=%s, hasError=%s, summary=%s]",
            transactionNo, pileCode, gunNo, hasError(), getErrorSummary());
    }
}
