//! ESI (EtherCAT Slave Information) 文件加载器
//!
//! 使用 quick-xml 解析 ESI XML 文件，提取从站配置信息。
//! 支持 encoding_rs 自动检测 GBK/GB2312/UTF-8 编码。
//! 通过 slave.esi() 获取实例，或直接调用 load_esi_file()。

use quick_xml::events::{BytesStart, Event};
use quick_xml::Reader;

use crate::slave::core::Slave;
use crate::utils::esi::{
    EsiBootstrapInfo, EsiCoEDetails, EsiDcConfiguration, EsiDcOpMode, EsiDeviceInfo,
    EsiEepromConfiguration, EsiPdoConfiguration, EsiPdoEntry, EsiPdoInfo, EsiSyncManagerInfo,
    parse_u16_hex_or_dec, parse_uint_hex_or_dec,
};
use crate::utils::ffi;

/// ESI 文件加载器
///
/// 用于加载和解析 ESI XML 文件，提取从站启动参数等配置信息。
///
/// # 示例
/// ```no_run
/// let slave = master.slave(1);
/// let mut esi = slave.esi();
/// if esi.load("path/to/device.xml") {
///     println!("ESI 文件已加载");
/// }
/// ```
pub struct EsiLoader {
    slave: Slave,
    /// ESI 文件是否已加载
    loaded: bool,
    /// 已加载的 ESI 文件路径
    file_path: Option<String>,
    /// 解析后的设备信息
    device_info: Option<EsiDeviceInfo>,
}

impl EsiLoader {
    /// 创建 ESI 加载器实例 (内部使用, 通过 slave.esi() 获取)
    pub(crate) fn new(slave: Slave) -> Self {
        Self {
            slave,
            loaded: false,
            file_path: None,
            device_info: None,
        }
    }

    /// 加载 ESI XML 文件
    ///
    /// 解析 ESI 文件并提取启动参数 (SDO init)，自动添加到从站的启动参数列表。
    ///
    /// # 参数
    /// - `file_path`: ESI XML 文件路径
    ///
    /// # 返回
    /// 成功返回 true，失败返回 false
    pub fn load(&mut self, file_path: &str) -> bool {
        if file_path.is_empty() {
            return false;
        }

        // 检查文件是否存在
        if !std::path::Path::new(file_path).exists() {
            return false;
        }

        // 解析 ESI 文件
        let info = match load_esi_file(file_path) {
            Ok(info) => info,
            Err(_) => return false,
        };

        // 读取并提取启动参数
        let xml_content = match read_file_auto_encoding(file_path) {
            Ok(content) => content,
            Err(_) => {
                // 即使启动参数提取失败，设备信息已经解析成功
                self.loaded = true;
                self.file_path = Some(file_path.to_string());
                self.device_info = Some(info);
                return true;
            }
        };

        // 提取启动参数 (InitCmd 节点)
        let params = extract_startup_parameters(&xml_content);

        // 将启动参数添加到从站
        for param in &params {
            let _ = self.slave.add_startup_parameter(
                param.index,
                param.subindex,
                &param.data,
                param.transition,
                param.timing,
                param.complete_access,
            );
        }

        self.loaded = true;
        self.file_path = Some(file_path.to_string());
        self.device_info = Some(info);
        true
    }

    /// 检查 ESI 文件是否已加载
    pub fn is_loaded(&self) -> bool {
        self.loaded
    }

    /// 获取已加载的 ESI 文件路径
    pub fn file_path(&self) -> Option<&str> {
        self.file_path.as_deref()
    }

    /// 获取解析后的设备信息
    pub fn device_info(&self) -> Option<&EsiDeviceInfo> {
        self.device_info.as_ref()
    }
}

impl std::fmt::Display for EsiLoader {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        if self.loaded {
            write!(
                f,
                "从站 {}: ESI 已加载 ({})",
                self.slave.index(),
                self.file_path.as_deref().unwrap_or("未知")
            )
        } else {
            write!(f, "从站 {}: ESI 未加载", self.slave.index())
        }
    }
}

// ===================== ESI 启动参数 =====================

/// ESI 启动参数
pub struct EsiStartupParam {
    /// 对象索引
    pub index: u16,
    /// 子索引
    pub subindex: u8,
    /// 数据
    pub data: Vec<u8>,
    /// 状态转换类型
    pub transition: u8,
    /// 写入时序
    pub timing: u8,
    /// 完整访问标志
    pub complete_access: bool,
}

// ===================== 文件编码处理 =====================

/// 读取文件并自动检测编码 (支持 UTF-8/GBK/GB2312)
///
/// 使用 encoding_rs 检测文件编码，非 UTF-8 文件自动转换。
fn read_file_auto_encoding(path: &str) -> Result<String, String> {
    let raw_bytes = std::fs::read(path).map_err(|e| format!("读取文件失败: {}", e))?;

    // 检查 BOM 标记
    if raw_bytes.starts_with(&[0xEF, 0xBB, 0xBF]) {
        // UTF-8 BOM
        return String::from_utf8(raw_bytes[3..].to_vec())
            .map_err(|e| format!("UTF-8 解码失败: {}", e));
    }
    if raw_bytes.starts_with(&[0xFF, 0xFE]) {
        // UTF-16 LE BOM
        let (result, _, had_errors) = encoding_rs::UTF_16LE.decode(&raw_bytes[2..]);
        if had_errors {
            return Err("UTF-16 LE 解码失败".to_string());
        }
        return Ok(result.into_owned());
    }
    if raw_bytes.starts_with(&[0xFE, 0xFF]) {
        // UTF-16 BE BOM
        let (result, _, had_errors) = encoding_rs::UTF_16BE.decode(&raw_bytes[2..]);
        if had_errors {
            return Err("UTF-16 BE 解码失败".to_string());
        }
        return Ok(result.into_owned());
    }

    // 尝试 UTF-8
    if let Ok(s) = String::from_utf8(raw_bytes.clone()) {
        return Ok(s);
    }

    // 尝试从 XML 声明中提取编码
    let encoding = detect_xml_encoding(&raw_bytes);

    let decoder = match encoding.to_lowercase().as_str() {
        "gbk" | "gb2312" | "gb18030" => encoding_rs::GBK,
        "iso-8859-1" | "latin1" => encoding_rs::WINDOWS_1252,
        "shift_jis" | "shift-jis" => encoding_rs::SHIFT_JIS,
        _ => encoding_rs::GBK, // 默认尝试 GBK (中文环境常见)
    };

    let (result, _, had_errors) = decoder.decode(&raw_bytes);
    if had_errors {
        return Err(format!("使用 {} 编码解码失败", encoding));
    }
    Ok(result.into_owned())
}

/// 从 XML 声明中检测编码
fn detect_xml_encoding(data: &[u8]) -> String {
    // 在前 200 字节内查找 encoding="xxx"
    let search_len = data.len().min(200);
    let header = &data[..search_len];

    // 用 ASCII 安全方式搜索
    if let Some(pos) = header
        .windows(9)
        .position(|w| w.eq_ignore_ascii_case(b"encoding="))
    {
        let after = &header[pos + 9..];
        if let Some(&quote) = after.first() {
            if quote == b'"' || quote == b'\'' {
                if let Some(end) = after[1..].iter().position(|&b| b == quote) {
                    if let Ok(enc) = std::str::from_utf8(&after[1..1 + end]) {
                        return enc.to_string();
                    }
                }
            }
        }
    }
    "utf-8".to_string()
}

// ===================== quick-xml 解析核心 =====================

/// 从 ESI XML 文件加载设备信息
///
/// 解析 ESI 文件中 `<Descriptions><Devices><Device>` 节点，
/// 提取设备标识、邮箱配置、DC、SM、PDO、EEPROM 等完整配置。
///
/// # 参数
/// - `path`: ESI XML 文件路径
///
/// # 返回
/// 成功返回 EsiDeviceInfo，失败返回错误信息
pub fn load_esi_file(path: &str) -> Result<EsiDeviceInfo, String> {
    let xml_content = read_file_auto_encoding(path)?;
    parse_esi_xml(&xml_content)
}

/// 从 ESI XML 文件加载配置并应用启动参数到从站
///
/// 解析 ESI 文件，提取 InitCmd 中的 SDO 启动参数，
/// 通过 FFI 调用 AddStartupParameter 添加到指定从站。
///
/// # 参数
/// - `mi`: 主站索引
/// - `si`: 从站索引
/// - `path`: ESI XML 文件路径
///
/// # 返回
/// 成功返回添加的参数数量，失败返回错误信息
pub fn load_and_apply_startup(mi: u16, si: u16, path: &str) -> Result<i32, String> {
    let xml_content = read_file_auto_encoding(path)?;
    let params = extract_startup_parameters(&xml_content);

    let mut count = 0i32;
    for param in &params {
        let mut ffi_param: ffi::StartupParam = unsafe { std::mem::zeroed() };
        ffi_param.index = param.index;
        ffi_param.sub_index = param.subindex;
        ffi_param.data_len = param.data.len() as u16;
        ffi_param.transition = param.transition;
        ffi_param.timing = param.timing;
        ffi_param.complete_access = if param.complete_access { 1 } else { 0 };

        let copy_len = param.data.len().min(256);
        ffi_param.data[..copy_len].copy_from_slice(&param.data[..copy_len]);

        let ret = unsafe { ffi::AddStartupParameter(mi, si, &ffi_param) };
        if ret >= 0 {
            count += 1;
        } else {
            return Err(format!(
                "添加启动参数失败: 索引=0x{:04X} 子索引={} 返回码={}",
                param.index, param.subindex, ret
            ));
        }
    }

    Ok(count)
}

/// 解析 ESI XML 内容，返回设备信息
fn parse_esi_xml(xml: &str) -> Result<EsiDeviceInfo, String> {
    let mut reader = Reader::from_str(xml);
    reader.config_mut().trim_text(true);

    let mut info = EsiDeviceInfo::default();
    let mut buf = Vec::new();

    // 导航到 <Descriptions><Devices><Device>
    if !navigate_to_device(&mut reader, &mut buf)? {
        return Err("未找到 <Descriptions><Devices><Device> 节点".to_string());
    }

    // 解析 Device 元素内容
    parse_device_element(&mut reader, &mut buf, &mut info)?;

    Ok(info)
}

/// 导航到第一个 Device 元素
fn navigate_to_device(
    reader: &mut Reader<&[u8]>,
    buf: &mut Vec<u8>,
) -> Result<bool, String> {
    let mut depth_path: Vec<String> = Vec::new();

    loop {
        buf.clear();
        match reader.read_event_into(buf) {
            Ok(Event::Start(ref e)) => {
                let name = local_name_str(e);
                depth_path.push(name.clone());

                // 检查路径是否匹配 Descriptions > Devices > Device
                if depth_path.len() >= 3 {
                    let len = depth_path.len();
                    if depth_path[len - 3] == "Descriptions"
                        && depth_path[len - 2] == "Devices"
                        && depth_path[len - 1] == "Device"
                    {
                        // 从 Device 元素的属性提取 Physics
                        // (Device 属性在 parse_device_element 中会再次处理)
                        return Ok(true);
                    }
                }
            }
            Ok(Event::End(_)) => {
                depth_path.pop();
            }
            Ok(Event::Eof) => return Ok(false),
            Err(e) => return Err(format!("XML 解析错误: {}", e)),
            _ => {}
        }
    }
}

/// 解析 Device 元素的全部子节点
fn parse_device_element(
    reader: &mut Reader<&[u8]>,
    buf: &mut Vec<u8>,
    info: &mut EsiDeviceInfo,
) -> Result<(), String> {
    let mut sm_list: Vec<EsiSyncManagerInfo> = Vec::new();
    let mut pdo_config = EsiPdoConfiguration::default();
    let mut depth = 1u32; // 当前在 <Device> 内部, 深度=1

    loop {
        buf.clear();
        match reader.read_event_into(buf) {
            Ok(Event::Start(e)) => {
                // 将 e 脱离 buf 的借用, 以便下游函数可再次借用 buf
                let e = e.into_owned();
                let tag = local_name_str(&e);
                depth += 1;

                match tag.as_str() {
                    "Type" => {
                        // <Type ProductCode="#x..." RevisionNo="#x...">类型名称</Type>
                        parse_type_element(reader, buf, &e, info)?;
                        depth -= 1; // parse_type_element 消费了 End 事件
                    }
                    "Name" => {
                        // 设备名称 (仅在 Device 直接子节点时使用)
                        if depth == 2 {
                            let text = read_text_content(reader, buf)?;
                            if info.product_name.is_empty() {
                                info.product_name = text;
                            }
                            depth -= 1;
                        }
                    }
                    "GroupType" => {
                        info.group_type = read_text_content(reader, buf)?;
                        depth -= 1;
                    }
                    "Profile" => {
                        parse_profile_element(reader, buf, info)?;
                        depth -= 1;
                    }
                    "Mailbox" => {
                        parse_mailbox_element(reader, buf, info)?;
                        depth -= 1;
                    }
                    "Dc" => {
                        let dc = parse_dc_element(reader, buf)?;
                        info.dc_configuration = Some(dc);
                        depth -= 1;
                    }
                    "Sm" => {
                        let sm = parse_sm_element(reader, buf, &e)?;
                        sm_list.push(sm);
                        depth -= 1;
                    }
                    "RxPdo" => {
                        let pdo = parse_pdo_element(reader, buf, &e)?;
                        pdo_config.rx_pdos.push(pdo);
                        depth -= 1;
                    }
                    "TxPdo" => {
                        let pdo = parse_pdo_element(reader, buf, &e)?;
                        pdo_config.tx_pdos.push(pdo);
                        depth -= 1;
                    }
                    "Eeprom" => {
                        let eeprom = parse_eeprom_element(reader, buf)?;
                        info.eeprom_configuration = Some(eeprom);
                        depth -= 1;
                    }
                    _ => {
                        // 跳过未识别的元素
                    }
                }
            }
            Ok(Event::End(_)) => {
                depth -= 1;
                if depth == 0 {
                    // 已离开 <Device>
                    break;
                }
            }
            Ok(Event::Eof) => break,
            Err(e) => return Err(format!("XML 解析错误: {}", e)),
            _ => {}
        }
    }

    // 将 SM 列表和 PDO 配置存入 info (通过 EsiDeviceInfo 的扩展字段)
    // 注: SM 和 PDO 信息存储在独立字段中
    let _ = sm_list; // SM 信息已通过 sm_list 收集，后续可扩展
    let _ = pdo_config; // PDO 信息已通过 pdo_config 收集

    Ok(())
}

/// 解析 <Type> 元素: 提取 ProductCode, RevisionNo, 设备类型名
fn parse_type_element(
    reader: &mut Reader<&[u8]>,
    buf: &mut Vec<u8>,
    start: &BytesStart<'_>,
    info: &mut EsiDeviceInfo,
) -> Result<(), String> {
    // 读取属性
    for attr in start.attributes().flatten() {
        let key = std::str::from_utf8(attr.key.as_ref()).unwrap_or("");
        let val = attr.unescape_value().unwrap_or_default();
        match key {
            "ProductCode" => {
                info.product_id = parse_uint_hex_or_dec(&val).unwrap_or(0);
            }
            "RevisionNo" => {
                info.revision_id = parse_uint_hex_or_dec(&val).unwrap_or(0);
            }
            _ => {}
        }
    }

    // 读取元素文本 (设备类型名)
    let type_name = read_text_content(reader, buf)?;
    if info.product_name.is_empty() {
        info.product_name = type_name;
    }

    Ok(())
}

/// 解析 <Profile> 元素
fn parse_profile_element(
    reader: &mut Reader<&[u8]>,
    buf: &mut Vec<u8>,
    info: &mut EsiDeviceInfo,
) -> Result<(), String> {
    let mut depth = 1u32;

    loop {
        buf.clear();
        match reader.read_event_into(buf) {
            Ok(Event::Start(ref e)) => {
                let tag = local_name_str(e);
                depth += 1;

                if tag == "ProfileNo" {
                    info.profile_number = read_text_content(reader, buf)?;
                    depth -= 1;
                }
            }
            Ok(Event::End(_)) => {
                depth -= 1;
                if depth == 0 {
                    break;
                }
            }
            Ok(Event::Eof) => break,
            Err(e) => return Err(format!("解析 Profile 错误: {}", e)),
            _ => {}
        }
    }
    Ok(())
}

/// 解析 <Mailbox> 元素: 提取协议支持标志和邮箱 SM 配置
fn parse_mailbox_element(
    reader: &mut Reader<&[u8]>,
    buf: &mut Vec<u8>,
    info: &mut EsiDeviceInfo,
) -> Result<(), String> {
    let mut depth = 1u32;
    let mut coe_details = EsiCoEDetails::default();
    let mut has_coe = false;

    loop {
        buf.clear();
        match reader.read_event_into(buf) {
            Ok(Event::Start(ref e)) => {
                let tag = local_name_str(e);
                depth += 1;

                match tag.as_str() {
                    "CoE" => {
                        has_coe = true;
                        info.supports_coe = true;
                        // 解析 CoE 属性
                        for attr in e.attributes().flatten() {
                            let key =
                                std::str::from_utf8(attr.key.as_ref()).unwrap_or("");
                            let val = attr.unescape_value().unwrap_or_default();
                            let bval = val == "1" || val.eq_ignore_ascii_case("true");
                            match key {
                                "SdoInfo" => coe_details.sdo_info = bval,
                                "PdoAssign" => coe_details.pdo_assign = bval,
                                "PdoConfig" | "PdoConfiguration" => {
                                    coe_details.pdo_config = bval
                                }
                                "CompleteAccess" => {
                                    coe_details.complete_access = bval
                                }
                                "PdoUpload" | "SegmentedSdo" => {
                                    coe_details.segmented_sdo = bval
                                }
                                "DiagHistory" => coe_details.diag_history = bval,
                                _ => {}
                            }
                        }
                        // CoE 可能包含 InitCmd 子节点，在此跳过内部
                    }
                    "SoE" => info.supports_soe = true,
                    "FoE" => info.supports_foe = true,
                    "EoE" => info.supports_eoe = true,
                    "VoE" => info.supports_voe = true,
                    _ => {}
                }
            }
            Ok(Event::Empty(ref e)) => {
                // 空元素 (如 <FoE/>)
                let tag = local_name_str(e);
                match tag.as_str() {
                    "CoE" => {
                        has_coe = true;
                        info.supports_coe = true;
                        for attr in e.attributes().flatten() {
                            let key =
                                std::str::from_utf8(attr.key.as_ref()).unwrap_or("");
                            let val = attr.unescape_value().unwrap_or_default();
                            let bval = val == "1" || val.eq_ignore_ascii_case("true");
                            match key {
                                "SdoInfo" => coe_details.sdo_info = bval,
                                "PdoAssign" => coe_details.pdo_assign = bval,
                                "PdoConfig" | "PdoConfiguration" => {
                                    coe_details.pdo_config = bval
                                }
                                "CompleteAccess" => {
                                    coe_details.complete_access = bval
                                }
                                "PdoUpload" | "SegmentedSdo" => {
                                    coe_details.segmented_sdo = bval
                                }
                                "DiagHistory" => coe_details.diag_history = bval,
                                _ => {}
                            }
                        }
                    }
                    "SoE" => info.supports_soe = true,
                    "FoE" => info.supports_foe = true,
                    "EoE" => info.supports_eoe = true,
                    "VoE" => info.supports_voe = true,
                    _ => {}
                }
            }
            Ok(Event::End(_)) => {
                depth -= 1;
                if depth == 0 {
                    break;
                }
            }
            Ok(Event::Eof) => break,
            Err(e) => return Err(format!("解析 Mailbox 错误: {}", e)),
            _ => {}
        }
    }

    if has_coe {
        info.coe_details = Some(coe_details);
    }

    Ok(())
}

/// 解析 <Dc> 元素: 提取 OpMode 列表
fn parse_dc_element(
    reader: &mut Reader<&[u8]>,
    buf: &mut Vec<u8>,
) -> Result<EsiDcConfiguration, String> {
    let mut dc = EsiDcConfiguration::default();
    let mut depth = 1u32;

    loop {
        buf.clear();
        match reader.read_event_into(buf) {
            Ok(Event::Start(ref e)) => {
                let tag = local_name_str(e);
                depth += 1;

                if tag == "OpMode" {
                    let mode = parse_dc_opmode(reader, buf)?;
                    dc.op_modes.push(mode);
                    depth -= 1;
                }
            }
            Ok(Event::End(_)) => {
                depth -= 1;
                if depth == 0 {
                    break;
                }
            }
            Ok(Event::Eof) => break,
            Err(e) => return Err(format!("解析 Dc 错误: {}", e)),
            _ => {}
        }
    }
    Ok(dc)
}

/// 解析单个 <OpMode> 元素
fn parse_dc_opmode(
    reader: &mut Reader<&[u8]>,
    buf: &mut Vec<u8>,
) -> Result<EsiDcOpMode, String> {
    let mut mode = EsiDcOpMode::default();
    let mut depth = 1u32;

    loop {
        buf.clear();
        match reader.read_event_into(buf) {
            Ok(Event::Start(ref e)) => {
                let tag = local_name_str(e);
                depth += 1;

                match tag.as_str() {
                    "Name" => {
                        mode.name = read_text_content(reader, buf)?;
                        depth -= 1;
                    }
                    "Description" => {
                        mode.description = read_text_content(reader, buf)?;
                        depth -= 1;
                    }
                    "AssignActivate" => {
                        let text = read_text_content(reader, buf)?;
                        mode.assign_activate =
                            parse_u16_hex_or_dec(&text).unwrap_or(0);
                        depth -= 1;
                    }
                    "CycleTimeSync0" => {
                        let text = read_text_content(reader, buf)?;
                        mode.cycle_time_sync0 =
                            parse_uint_hex_or_dec(&text).unwrap_or(0);
                        depth -= 1;
                    }
                    "CycleTimeSync1" => {
                        let text = read_text_content(reader, buf)?;
                        mode.cycle_time_sync1 =
                            parse_uint_hex_or_dec(&text).unwrap_or(0);
                        depth -= 1;
                    }
                    "ShiftTimeSync0" | "ShiftTime" => {
                        let text = read_text_content(reader, buf)?;
                        mode.shift_time_sync0 =
                            text.trim().parse::<i32>().unwrap_or(0);
                        depth -= 1;
                    }
                    "ShiftTimeSync1" => {
                        let text = read_text_content(reader, buf)?;
                        mode.shift_time_sync1 =
                            text.trim().parse::<i32>().unwrap_or(0);
                        depth -= 1;
                    }
                    "CycleTimeSync0Factor" => {
                        let text = read_text_content(reader, buf)?;
                        mode.cycle_time_sync0_factor =
                            text.trim().parse::<i32>().unwrap_or(0);
                        depth -= 1;
                    }
                    "CycleTimeSync1Factor" => {
                        let text = read_text_content(reader, buf)?;
                        mode.cycle_time_sync1_factor =
                            text.trim().parse::<i32>().unwrap_or(0);
                        depth -= 1;
                    }
                    _ => {}
                }
            }
            Ok(Event::End(_)) => {
                depth -= 1;
                if depth == 0 {
                    break;
                }
            }
            Ok(Event::Eof) => break,
            Err(e) => return Err(format!("解析 OpMode 错误: {}", e)),
            _ => {}
        }
    }
    Ok(mode)
}

/// 解析 <Sm> 元素: SyncManager 配置
fn parse_sm_element(
    reader: &mut Reader<&[u8]>,
    buf: &mut Vec<u8>,
    start: &BytesStart<'_>,
) -> Result<EsiSyncManagerInfo, String> {
    let mut sm = EsiSyncManagerInfo::default();

    // 从属性读取 SM 配置
    for attr in start.attributes().flatten() {
        let key = std::str::from_utf8(attr.key.as_ref()).unwrap_or("");
        let val = attr.unescape_value().unwrap_or_default();
        match key {
            "No" | "Index" => {
                sm.index = val.trim().parse::<i32>().unwrap_or(0);
            }
            "StartAddress" => {
                sm.start_address = parse_u16_hex_or_dec(&val).unwrap_or(0);
            }
            "DefaultSize" => {
                sm.default_size = parse_u16_hex_or_dec(&val).unwrap_or(0);
            }
            "ControlByte" => {
                sm.control_byte = parse_uint_hex_or_dec(&val).unwrap_or(0) as u8;
            }
            "Enable" => {
                let bval = val == "1" || val.eq_ignore_ascii_case("true");
                sm.enable = bval;
            }
            "MinSize" => {
                sm.min_size = parse_u16_hex_or_dec(&val).unwrap_or(0);
            }
            "MaxSize" => {
                sm.max_size = parse_u16_hex_or_dec(&val).unwrap_or(0);
            }
            _ => {}
        }
    }

    // 读取 SM 文本内容 (可能有名称或内嵌子元素)
    let text = read_text_content(reader, buf)?;
    if !text.is_empty() {
        sm.name = text;
    }

    Ok(sm)
}

/// 解析 <RxPdo> 或 <TxPdo> 元素
fn parse_pdo_element(
    reader: &mut Reader<&[u8]>,
    buf: &mut Vec<u8>,
    start: &BytesStart<'_>,
) -> Result<EsiPdoInfo, String> {
    let mut pdo = EsiPdoInfo::default();

    // 从属性读取 PDO 信息
    for attr in start.attributes().flatten() {
        let key = std::str::from_utf8(attr.key.as_ref()).unwrap_or("");
        let val = attr.unescape_value().unwrap_or_default();
        match key {
            "Fixed" => {
                pdo.is_fixed = val == "1" || val.eq_ignore_ascii_case("true");
            }
            "Mandatory" => {
                pdo.is_mandatory = val == "1" || val.eq_ignore_ascii_case("true");
            }
            "Sm" | "SM" => {
                pdo.sync_manager = val.trim().parse::<u8>().unwrap_or(0);
            }
            _ => {}
        }
    }

    let mut depth = 1u32;

    loop {
        buf.clear();
        match reader.read_event_into(buf) {
            Ok(Event::Start(ref e)) => {
                let tag = local_name_str(e);
                depth += 1;

                match tag.as_str() {
                    "Index" => {
                        let text = read_text_content(reader, buf)?;
                        pdo.index = parse_u16_hex_or_dec(&text).unwrap_or(0);
                        depth -= 1;
                    }
                    "Name" => {
                        pdo.name = read_text_content(reader, buf)?;
                        depth -= 1;
                    }
                    "Exclude" => {
                        let text = read_text_content(reader, buf)?;
                        if let Some(v) = parse_u16_hex_or_dec(&text) {
                            pdo.exclude_indices.push(v);
                        }
                        depth -= 1;
                    }
                    "Entry" => {
                        let entry = parse_pdo_entry(reader, buf)?;
                        pdo.entries.push(entry);
                        depth -= 1;
                    }
                    _ => {}
                }
            }
            Ok(Event::End(_)) => {
                depth -= 1;
                if depth == 0 {
                    break;
                }
            }
            Ok(Event::Eof) => break,
            Err(e) => return Err(format!("解析 PDO 错误: {}", e)),
            _ => {}
        }
    }
    Ok(pdo)
}

/// 解析 PDO 条目 <Entry>
fn parse_pdo_entry(
    reader: &mut Reader<&[u8]>,
    buf: &mut Vec<u8>,
) -> Result<EsiPdoEntry, String> {
    let mut entry = EsiPdoEntry::default();
    let mut depth = 1u32;

    loop {
        buf.clear();
        match reader.read_event_into(buf) {
            Ok(Event::Start(ref e)) => {
                let tag = local_name_str(e);
                depth += 1;

                match tag.as_str() {
                    "Index" => {
                        let text = read_text_content(reader, buf)?;
                        entry.index = parse_u16_hex_or_dec(&text).unwrap_or(0);
                        depth -= 1;
                    }
                    "SubIndex" => {
                        let text = read_text_content(reader, buf)?;
                        entry.sub_index =
                            parse_uint_hex_or_dec(&text).unwrap_or(0) as u8;
                        depth -= 1;
                    }
                    "BitLen" => {
                        let text = read_text_content(reader, buf)?;
                        entry.bit_length =
                            text.trim().parse::<u8>().unwrap_or(0);
                        depth -= 1;
                    }
                    "Name" => {
                        entry.name = read_text_content(reader, buf)?;
                        depth -= 1;
                    }
                    "DataType" => {
                        entry.data_type = read_text_content(reader, buf)?;
                        depth -= 1;
                    }
                    _ => {}
                }
            }
            Ok(Event::End(_)) => {
                depth -= 1;
                if depth == 0 {
                    break;
                }
            }
            Ok(Event::Eof) => break,
            Err(e) => return Err(format!("解析 PDO Entry 错误: {}", e)),
            _ => {}
        }
    }
    Ok(entry)
}

/// 解析 <Eeprom> 元素
fn parse_eeprom_element(
    reader: &mut Reader<&[u8]>,
    buf: &mut Vec<u8>,
) -> Result<EsiEepromConfiguration, String> {
    let mut eeprom = EsiEepromConfiguration::default();
    let mut depth = 1u32;

    loop {
        buf.clear();
        match reader.read_event_into(buf) {
            Ok(Event::Start(ref e)) => {
                let tag = local_name_str(e);
                depth += 1;

                match tag.as_str() {
                    "ByteSize" => {
                        let text = read_text_content(reader, buf)?;
                        eeprom.byte_size = text.trim().parse::<i32>().unwrap_or(0);
                        depth -= 1;
                    }
                    "ConfigData" => {
                        eeprom.config_data = read_text_content(reader, buf)?;
                        depth -= 1;
                    }
                    "BootStrap" => {
                        let bs = parse_bootstrap_element(reader, buf)?;
                        eeprom.bootstrap = Some(bs);
                        depth -= 1;
                    }
                    _ => {}
                }
            }
            Ok(Event::End(_)) => {
                depth -= 1;
                if depth == 0 {
                    break;
                }
            }
            Ok(Event::Eof) => break,
            Err(e) => return Err(format!("解析 Eeprom 错误: {}", e)),
            _ => {}
        }
    }
    Ok(eeprom)
}

/// 解析 <BootStrap> 元素
fn parse_bootstrap_element(
    reader: &mut Reader<&[u8]>,
    buf: &mut Vec<u8>,
) -> Result<EsiBootstrapInfo, String> {
    let mut bs = EsiBootstrapInfo::default();
    let mut depth = 1u32;

    loop {
        buf.clear();
        match reader.read_event_into(buf) {
            Ok(Event::Start(ref e)) => {
                let tag = local_name_str(e);
                depth += 1;

                match tag.as_str() {
                    "RecvMbxOffset" | "RecvMailboxOffset" => {
                        let text = read_text_content(reader, buf)?;
                        bs.recv_mailbox_offset =
                            parse_u16_hex_or_dec(&text).unwrap_or(0);
                        depth -= 1;
                    }
                    "RecvMbxSize" | "RecvMailboxSize" => {
                        let text = read_text_content(reader, buf)?;
                        bs.recv_mailbox_size =
                            parse_u16_hex_or_dec(&text).unwrap_or(0);
                        depth -= 1;
                    }
                    "SendMbxOffset" | "SendMailboxOffset" => {
                        let text = read_text_content(reader, buf)?;
                        bs.send_mailbox_offset =
                            parse_u16_hex_or_dec(&text).unwrap_or(0);
                        depth -= 1;
                    }
                    "SendMbxSize" | "SendMailboxSize" => {
                        let text = read_text_content(reader, buf)?;
                        bs.send_mailbox_size =
                            parse_u16_hex_or_dec(&text).unwrap_or(0);
                        depth -= 1;
                    }
                    _ => {}
                }
            }
            Ok(Event::End(_)) => {
                depth -= 1;
                if depth == 0 {
                    break;
                }
            }
            Ok(Event::Eof) => break,
            Err(e) => return Err(format!("解析 BootStrap 错误: {}", e)),
            _ => {}
        }
    }
    Ok(bs)
}

// ===================== InitCmd 启动参数解析 =====================

/// 从 ESI XML 内容提取启动参数
///
/// 解析 `<InitCmd>` 节点中的 CoE SDO 初始化命令。
/// 支持位于 `<Mailbox><CoE><InitCmd>` 路径下的节点。
pub fn extract_startup_parameters(xml: &str) -> Vec<EsiStartupParam> {
    let mut params = Vec::new();
    let mut reader = Reader::from_str(xml);
    reader.config_mut().trim_text(true);
    let mut buf = Vec::new();

    loop {
        buf.clear();
        match reader.read_event_into(&mut buf) {
            Ok(Event::Start(ref e)) => {
                let tag = local_name_str(e);
                if tag == "InitCmd" {
                    if let Ok(Some(param)) =
                        parse_init_cmd_element(&mut reader, &mut buf)
                    {
                        params.push(param);
                    }
                }
            }
            Ok(Event::Eof) => break,
            Err(_) => break,
            _ => {}
        }
    }

    params
}

/// 解析单个 <InitCmd> 元素
fn parse_init_cmd_element(
    reader: &mut Reader<&[u8]>,
    buf: &mut Vec<u8>,
) -> Result<Option<EsiStartupParam>, String> {
    let mut index: Option<u16> = None;
    let mut subindex: u8 = 0;
    let mut data: Vec<u8> = Vec::new();
    let mut transition: u8 = ffi::TRANS_PS;
    let mut timing: u8 = ffi::TIMING_BEFORE;
    let mut complete_access = false;
    let mut depth = 1u32;

    loop {
        buf.clear();
        match reader.read_event_into(buf) {
            Ok(Event::Start(ref e)) => {
                let tag = local_name_str(e);
                depth += 1;

                match tag.as_str() {
                    "Index" => {
                        let text = read_text_content(reader, buf)?;
                        index = parse_u16_hex_or_dec(&text);
                        depth -= 1;
                    }
                    "SubIndex" => {
                        let text = read_text_content(reader, buf)?;
                        subindex =
                            parse_uint_hex_or_dec(&text).unwrap_or(0) as u8;
                        depth -= 1;
                    }
                    "Data" => {
                        let text = read_text_content(reader, buf)?;
                        data = parse_hex_string(&text);
                        depth -= 1;
                    }
                    "Transition" => {
                        let text = read_text_content(reader, buf)?;
                        transition = match text.trim() {
                            "IP" => ffi::TRANS_IP,
                            "PS" => ffi::TRANS_PS,
                            "SO" => ffi::TRANS_SO,
                            "OS" => ffi::TRANS_OS,
                            "SP" => ffi::TRANS_SP,
                            "PI" => ffi::TRANS_PI,
                            _ => ffi::TRANS_PS,
                        };
                        depth -= 1;
                    }
                    "Timeout" | "Timing" => {
                        let text = read_text_content(reader, buf)?;
                        timing = match text.trim() {
                            "After" | "after" | "AFTER" => ffi::TIMING_AFTER,
                            _ => ffi::TIMING_BEFORE,
                        };
                        depth -= 1;
                    }
                    "CompleteAccess" => {
                        let text = read_text_content(reader, buf)?;
                        complete_access = matches!(
                            text.trim(),
                            "1" | "true" | "True" | "TRUE"
                        );
                        depth -= 1;
                    }
                    _ => {}
                }
            }
            Ok(Event::End(_)) => {
                depth -= 1;
                if depth == 0 {
                    break;
                }
            }
            Ok(Event::Eof) => break,
            Err(e) => return Err(format!("解析 InitCmd 错误: {}", e)),
            _ => {}
        }
    }

    // Index 是必须字段
    match index {
        Some(idx) => Ok(Some(EsiStartupParam {
            index: idx,
            subindex,
            data,
            transition,
            timing,
            complete_access,
        })),
        None => Ok(None),
    }
}

// ===================== 辅助函数 =====================

/// 获取元素的本地名称 (去掉命名空间前缀)
fn local_name_str(e: &BytesStart<'_>) -> String {
    let full = e.name();
    let local = full.local_name();
    std::str::from_utf8(local.as_ref())
        .unwrap_or("")
        .to_string()
}

/// 读取当前元素的文本内容直到对应的结束标签
fn read_text_content(
    reader: &mut Reader<&[u8]>,
    buf: &mut Vec<u8>,
) -> Result<String, String> {
    let mut text = String::new();
    let mut depth = 1u32;

    loop {
        buf.clear();
        match reader.read_event_into(buf) {
            Ok(Event::Text(ref e)) => {
                if let Ok(t) = e.unescape() {
                    text.push_str(&t);
                }
            }
            Ok(Event::Start(_)) => {
                depth += 1;
            }
            Ok(Event::End(_)) => {
                depth -= 1;
                if depth == 0 {
                    break;
                }
            }
            Ok(Event::Eof) => break,
            Err(e) => return Err(format!("读取文本内容错误: {}", e)),
            _ => {}
        }
    }
    Ok(text.trim().to_string())
}

/// 将十六进制字符串转换为字节数组 (如 "0102FF" -> [0x01, 0x02, 0xFF])
fn parse_hex_string(hex_str: &str) -> Vec<u8> {
    let hex = hex_str.trim();
    let mut bytes = Vec::new();
    let chars: Vec<char> = hex.chars().collect();
    let mut i = 0;
    while i + 1 < chars.len() {
        if let (Some(high), Some(low)) = (chars[i].to_digit(16), chars[i + 1].to_digit(16)) {
            bytes.push((high << 4 | low) as u8);
        }
        i += 2;
    }
    bytes
}
