//! XML 配置文件解析工具
//!
//! 对应 C# Utils/Xml.cs
//! 提供 ENI/DENI 配置文件的加载和保存功能。
//! 使用 quick-xml 进行 XML 解析和生成。

use std::collections::HashMap;
use std::io::BufRead;
use quick_xml::events::Event;
use quick_xml::reader::Reader;
// quick_xml::writer::Writer 及 BytesStart/BytesEnd/BytesText/BytesDecl 在
// save_xml_configuration 移除后已不再使用, 保留 load 路径所需的 Event 即可。

/// ENI 标准命名空间
pub const ENI_NAMESPACE: &str = "";

/// DENI 扩展命名空间
pub const DENI_NAMESPACE: &str = "http://www.darra.com/ethercat/deni";

/// DENI 命名空间前缀
const DENI_PREFIX: &str = "deni";

/// ESI 命名空间
pub const ESI_NAMESPACE: &str = "http://www.ethercat.org/esi";

/// 解析 u32，支持 "0x" 或 "#" 前缀的十六进制
///
/// 对应 C# TryParseUIntHexOrDec
pub fn parse_uint_hex_or_dec(s: &str) -> Option<u32> {
    let s = s.trim();
    if s.is_empty() {
        return None;
    }

    // 十六进制前缀
    if let Some(hex) = s.strip_prefix("0x").or_else(|| s.strip_prefix("0X")) {
        return u32::from_str_radix(hex, 16).ok();
    }
    if let Some(hex) = s.strip_prefix("#x").or_else(|| s.strip_prefix("#X")) {
        return u32::from_str_radix(hex, 16).ok();
    }
    if let Some(hex) = s.strip_prefix('#') {
        return u32::from_str_radix(hex, 16).ok();
    }

    // 尝试十进制
    if let Ok(val) = s.parse::<u32>() {
        return Some(val);
    }

    // 尝试纯十六进制字符串
    if s.chars().all(|c| c.is_ascii_hexdigit()) && s.chars().any(|c| c.is_ascii_alphabetic()) {
        return u32::from_str_radix(s, 16).ok();
    }

    None
}

/// 解析 u16
pub fn parse_u16_hex_or_dec(s: &str) -> Option<u16> {
    parse_uint_hex_or_dec(s).map(|v| v as u16)
}

/// 解析 u8
pub fn parse_u8_hex_or_dec(s: &str) -> Option<u8> {
    parse_uint_hex_or_dec(s).and_then(|v| {
        if v <= 255 { Some(v as u8) } else { None }
    })
}

/// 解析 i32，支持十六进制
pub fn parse_i32_hex_or_dec(s: &str) -> Option<i32> {
    let s = s.trim();
    if s.is_empty() {
        return None;
    }

    // 负数
    if let Some(rest) = s.strip_prefix('-') {
        return parse_uint_hex_or_dec(rest).map(|v| -(v as i32));
    }

    parse_uint_hex_or_dec(s).map(|v| v as i32)
}

/// 将字节数组格式化为十六进制字符串
pub fn bytes_to_hex_string(bytes: &[u8]) -> String {
    bytes.iter().map(|b| format!("{:02x}", b)).collect()
}

/// 从十六进制字符串解析字节数组
pub fn hex_string_to_bytes(hex: &str) -> Option<Vec<u8>> {
    let hex = hex.trim();
    let hex = hex.strip_prefix("0x").or_else(|| hex.strip_prefix("0X")).unwrap_or(hex);

    if hex.len() % 2 != 0 {
        return None;
    }

    let mut bytes = Vec::with_capacity(hex.len() / 2);
    for i in (0..hex.len()).step_by(2) {
        let byte_str = &hex[i..i + 2];
        match u8::from_str_radix(byte_str, 16) {
            Ok(b) => bytes.push(b),
            Err(_) => return None,
        }
    }

    Some(bytes)
}

/// 解析布尔值字符串 ("true"/"1"/"yes" -> true)
fn parse_bool_str(s: &str) -> bool {
    let s = s.trim().to_lowercase();
    matches!(s.as_str(), "true" | "1" | "yes")
}

// ===================== QoS 配置 (对应 C# QoS) =====================

/// QoS 配置
///
/// EtherCAT 帧优先级和 VLAN 配置
#[derive(Debug, Clone, Default)]
pub struct QosConfiguration {
    /// VLAN ID (802.1Q, 0=不使用)
    pub vlan_id: u16,
    /// VLAN 优先级 (0-7)
    pub vlan_priority: u8,
    /// 是否启用高优先级帧发送
    pub frame_high_priority: bool,
    /// 是否启用 DSCP (仅 UDP)
    pub enable_dscp: bool,
    /// DSCP 值 (默认 EF=46)
    pub dscp_value: u8,
}

/// Startup SDO 配置 (对应 C# StartupParameter)
#[derive(Debug, Clone, Default)]
pub struct StartupSdoConfig {
    /// CoE 对象索引
    pub index: u16,
    /// CoE 子索引
    pub sub_index: u8,
    /// 数据 (十六进制字节)
    pub data: Vec<u8>,
    /// 状态转换标识 ("PS"=PreOp->SafeOp, "SP"=SafeOp->PreOp, "SO"=SafeOp->Op 等)
    pub transition: String,
    /// 描述/注释
    pub comment: String,
    /// 是否使用完整访问 (Complete Access)
    pub complete_access: bool,
    /// 超时时间 (毫秒, 0=默认)
    pub timeout_ms: u32,
}

/// 主站 XML 配置
#[derive(Debug, Clone)]
pub struct MasterXmlConfiguration {
    /// 配置版本
    pub version: String,
    /// 周期时间 (微秒)
    pub cycle_time_us: u32,
    /// DC 周期 (纳秒)
    pub dc_cycle_ns: u32,
    /// 网卡名称
    pub adapter_name: String,
    /// 网卡描述
    pub adapter_description: String,
    /// 网卡 MAC 地址
    pub adapter_mac: String,
    /// 冗余网卡名称
    pub redundant_adapter_name: String,
    /// 冗余网卡描述
    pub redundant_adapter_description: String,
    /// 冗余网卡 MAC 地址
    pub redundant_adapter_mac: String,
    /// 是否启用冗余
    pub redundancy_enabled: bool,
    /// 期望从站数量
    pub expected_slave_count: i32,
    /// 是否使用 UDP 模式
    pub use_udp: bool,
    /// VLAN ID (0=不使用)
    pub vlan_id: u16,
    /// VLAN 优先级
    pub vlan_priority: u8,
    /// 是否启用重叠组
    pub enable_overlapping_groups: bool,
    /// 是否启用紧凑模式
    pub packed_mode: bool,
    /// 是否启用高优先级帧发送
    pub frame_high_priority: bool,
    /// CPU 亲和性核心号 (-1=不绑定)
    pub cpu_affinity: i32,
    /// 是否启用自适应超时
    pub adaptive_timeout: bool,
    /// 帧重复次数 (ETG.1500)
    pub frame_repeat_count: u8,
    /// 判断滤波阈值
    pub filter_threshold: u32,
    /// 是否启用 Mutex 保护
    pub mutex_protection: bool,
    /// DC 是否启用
    pub dc_enabled: bool,
    /// DC 漂移补偿
    pub drift_compensation: bool,
    /// 状态转换超时: INIT->PREOP (毫秒)
    pub timeout_init_to_preop: i32,
    /// 状态转换超时: PREOP->SAFEOP (毫秒)
    pub timeout_preop_to_safeop: i32,
    /// 状态转换超时: SAFEOP->OP (毫秒)
    pub timeout_safeop_to_op: i32,
    /// 过程数据看门狗 (毫秒)
    pub process_data_watchdog_ms: u32,
    /// PDI 看门狗 (毫秒)
    pub pdi_watchdog_ms: i32,
    /// 组配置列表
    pub group_configs: Vec<GroupConfigData>,
    /// 从站组分配 (从站索引 -> 组号)
    pub slave_group_assignments: HashMap<u16, u8>,
    /// 从站 DC 配置列表
    pub slave_dc_configs: Vec<SlaveDcConfig>,
    /// 从站配置列表
    pub slaves: Vec<SlaveXmlConfiguration>,
    /// 元数据: 保存日期
    pub saved_date: String,
    /// 元数据: 保存者
    pub saved_by: String,
    /// 元数据: 机器名
    pub machine_name: String,
    /// 元数据: DLL 版本
    pub dll_version: String,
    /// QoS 配置 (兼容旧字段)
    pub qos: QosConfiguration,
}

impl Default for MasterXmlConfiguration {
    fn default() -> Self {
        Self {
            version: "3.0".to_string(),
            cycle_time_us: 1000,
            dc_cycle_ns: 1000000,
            adapter_name: String::new(),
            adapter_description: String::new(),
            adapter_mac: String::new(),
            redundant_adapter_name: String::new(),
            redundant_adapter_description: String::new(),
            redundant_adapter_mac: String::new(),
            redundancy_enabled: false,
            expected_slave_count: 0,
            use_udp: false,
            vlan_id: 0,
            vlan_priority: 0,
            enable_overlapping_groups: false,
            packed_mode: false,
            frame_high_priority: false,
            cpu_affinity: -1,
            adaptive_timeout: false,
            frame_repeat_count: 1,
            filter_threshold: 3,
            mutex_protection: true,
            dc_enabled: false,
            drift_compensation: false,
            timeout_init_to_preop: 0,
            timeout_preop_to_safeop: 0,
            timeout_safeop_to_op: 0,
            process_data_watchdog_ms: 0,
            pdi_watchdog_ms: 0,
            group_configs: Vec::new(),
            slave_group_assignments: HashMap::new(),
            slave_dc_configs: Vec::new(),
            slaves: Vec::new(),
            saved_date: String::new(),
            saved_by: String::new(),
            machine_name: String::new(),
            dll_version: String::new(),
            qos: QosConfiguration::default(),
        }
    }
}

/// 将 XML 配置应用到主站 (对应 C# ApplyXMLConfiguration)
///
/// 将配置中的参数通过 FFI 设置到主站。
pub fn apply_xml_configuration(config: &MasterXmlConfiguration, master_index: u16) -> bool {
    unsafe {
        // 设置周期时间
        if config.cycle_time_us > 0 {
            crate::utils::ffi::SetMasterLoopCycleTime(master_index, config.cycle_time_us * 1000);
        }
        // 设置 CPU 亲和性
        if config.cpu_affinity >= 0 {
            crate::utils::ffi::SetMasterCpuAffinity(master_index, config.cpu_affinity);
        }
        // 设置 Mutex 保护
        crate::utils::ffi::SetMutexProtection(master_index, if config.mutex_protection { 1 } else { 0 });
    }
    true
}

// ===================== 从站 XML 配置数据模型 =====================

/// 组配置数据
#[derive(Debug, Clone, Default)]
pub struct GroupConfigData {
    pub group_index: u8,
    pub enabled: bool,
    pub cycle_divider: u8,
}

/// 从站 DC 配置
#[derive(Debug, Clone, Default)]
pub struct SlaveDcConfig {
    pub slave_index: u16,
    pub vendor_id: u32,
    pub product_code: u32,
    pub sync0_cycle_ns: u32,
    pub sync1_cycle_ns: u32,
    pub shift_ns: i32,
}

/// XML 配置导入结果
#[derive(Debug, Clone, Default)]
pub struct XmlConfigurationResult {
    pub success: bool,
    pub config_slave_count: i32,
    pub actual_slave_count: i32,
    pub matched_count: i32,
    pub slave_details: Vec<String>,
    pub warnings: Vec<String>,
}

/// SyncManager 配置
#[derive(Debug, Clone, Default)]
pub struct SyncManagerConfig {
    pub index: i32,
    pub start_addr: u16,
    pub length: u16,
    pub flags: u32,
    pub sm_type: u8,
    pub pdo_indices: Vec<u16>,
    pub watchdog: i32,
}

/// PDO 条目配置
#[derive(Debug, Clone, Default)]
pub struct PdoEntryConfig {
    pub index: u16,
    pub sub_index: u8,
    pub bit_length: u8,
    pub name: String,
    pub data_type: String,
    pub offset: i32,
    pub pdo_index: u16,
}

/// 从站 XML 配置 (完整版)
#[derive(Debug, Clone, Default)]
pub struct SlaveXmlConfiguration {
    pub index: i32,
    pub name: String,
    pub drive_name: String,
    pub vendor_id: u32,
    pub product_code: u32,
    pub revision: u32,
    pub config_addr: u16,
    pub input_size: i32,
    pub output_size: i32,
    pub input_pdos: Vec<PdoEntryConfig>,
    pub output_pdos: Vec<PdoEntryConfig>,
    /// Startup SDO 初始化命令列表
    pub sdo_init: Vec<StartupSdoConfig>,
    pub serial_no: u32,
    pub alias_addr: u16,
    pub mbx_write_offset: u16,
    pub mbx_read_offset: u16,
    pub mbx_write_length: u16,
    pub mbx_read_length: u16,
    pub mbx_poll_time: u16,
    pub cia402_profile_no: u16,
    pub bootstrap_send_offset: u16,
    pub bootstrap_send_length: u16,
    pub bootstrap_recv_offset: u16,
    pub bootstrap_recv_length: u16,
    pub has_dc: bool,
    pub sync0_cycle_ns: u32,
    pub sync1_cycle_ns: u32,
    pub shift_ns: i32,
    pub sync_managers: Vec<SyncManagerConfig>,
    pub should_write_pdo_assignment: bool,
    pub should_write_pdo_configuration: bool,
    pub supports_complete_access: bool,
    pub has_mdp: bool,
    pub block_lrw: bool,
    pub dtype: u16,
    pub has_coe: bool,
    pub has_foe: bool,
    pub has_eoe: bool,
    pub has_soe: bool,
    pub has_aoe: bool,
    pub has_voe: bool,
    pub mailbox_data_link_layer: bool,
    pub is_optional: bool,
    pub wd_time_pd: u16,
    pub wd_time_pdi: u16,
    pub wd_divider: u16,
    pub topology: u8,
    pub active_ports: u8,
    pub supports_frame_repeat: bool,
}

// ===================== XML 简易 DOM 解析器 =====================

/// 简易 XML 节点 (用于解析 ENI/DENI)
#[derive(Debug, Clone)]
struct XmlNode {
    /// 元素本地名 (不含命名空间前缀)
    local_name: String,
    /// 命名空间前缀 (如 "deni")
    prefix: String,
    /// 属性列表
    attributes: Vec<(String, String)>,
    /// 文本内容
    text: String,
    /// 子节点
    children: Vec<XmlNode>,
}

impl XmlNode {
    fn new(local_name: &str) -> Self {
        Self {
            local_name: local_name.to_string(),
            prefix: String::new(),
            attributes: Vec::new(),
            text: String::new(),
            children: Vec::new(),
        }
    }

    /// 查找第一个匹配本地名的子节点 (不区分大小写)
    fn find_child(&self, name: &str) -> Option<&XmlNode> {
        self.children.iter().find(|c| c.local_name.eq_ignore_ascii_case(name))
    }

    /// 查找所有匹配本地名的子节点
    fn find_children(&self, name: &str) -> Vec<&XmlNode> {
        self.children.iter().filter(|c| c.local_name.eq_ignore_ascii_case(name)).collect()
    }

    /// 查找第一个匹配本地名且具有指定命名空间前缀的子节点
    fn find_child_ns(&self, name: &str, prefix: &str) -> Option<&XmlNode> {
        self.children.iter().find(|c| {
            c.local_name.eq_ignore_ascii_case(name) && c.prefix == prefix
        })
    }

    /// 获取文本内容 (trimmed)
    fn text_trimmed(&self) -> &str {
        self.text.trim()
    }

    /// 获取属性值 (不区分大小写)
    fn attr(&self, name: &str) -> Option<&str> {
        self.attributes.iter()
            .find(|(k, _)| k.eq_ignore_ascii_case(name))
            .map(|(_, v)| v.as_str())
    }

    /// 获取子节点文本内容 (不区分大小写查找)
    fn child_text(&self, name: &str) -> Option<&str> {
        self.find_child(name).map(|c| c.text_trimmed())
    }

    /// 获取带命名空间前缀的子节点文本内容
    fn child_text_ns(&self, name: &str, prefix: &str) -> Option<&str> {
        self.find_child_ns(name, prefix).map(|c| c.text_trimmed())
    }
}

/// 从 quick-xml Reader 构建 DOM 树
fn build_dom<R: BufRead>(reader: &mut Reader<R>) -> Result<XmlNode, String> {
    let mut buf = Vec::new();
    let mut stack: Vec<XmlNode> = Vec::new();
    let mut root: Option<XmlNode> = None;

    loop {
        match reader.read_event_into(&mut buf) {
            Ok(Event::Start(ref e)) => {
                let (prefix, local) = split_qname(e.name().as_ref());
                let mut node = XmlNode::new(&local);
                node.prefix = prefix;

                // 解析属性
                for attr_result in e.attributes() {
                    if let Ok(attr) = attr_result {
                        let key = String::from_utf8_lossy(attr.key.as_ref()).to_string();
                        let val = attr.unescape_value().unwrap_or_default().to_string();
                        node.attributes.push((key, val));
                    }
                }

                stack.push(node);
            }
            Ok(Event::End(_)) => {
                if let Some(node) = stack.pop() {
                    if let Some(parent) = stack.last_mut() {
                        parent.children.push(node);
                    } else {
                        root = Some(node);
                    }
                }
            }
            Ok(Event::Empty(ref e)) => {
                let (prefix, local) = split_qname(e.name().as_ref());
                let mut node = XmlNode::new(&local);
                node.prefix = prefix;
                for attr_result in e.attributes() {
                    if let Ok(attr) = attr_result {
                        let key = String::from_utf8_lossy(attr.key.as_ref()).to_string();
                        let val = attr.unescape_value().unwrap_or_default().to_string();
                        node.attributes.push((key, val));
                    }
                }
                if let Some(parent) = stack.last_mut() {
                    parent.children.push(node);
                } else {
                    root = Some(node);
                }
            }
            Ok(Event::Text(ref e)) => {
                let text = e.unescape().unwrap_or_default().to_string();
                if let Some(current) = stack.last_mut() {
                    current.text.push_str(&text);
                }
            }
            Ok(Event::CData(ref e)) => {
                let text = String::from_utf8_lossy(e.as_ref()).to_string();
                if let Some(current) = stack.last_mut() {
                    current.text.push_str(&text);
                }
            }
            Ok(Event::Eof) => break,
            Ok(_) => {} // 忽略注释、PI 等
            Err(e) => return Err(format!("XML 解析错误: {}", e)),
        }
        buf.clear();
    }

    root.ok_or_else(|| "XML 文件为空或格式无效".to_string())
}

/// 分割 QName 为 (前缀, 本地名)
fn split_qname(name: &[u8]) -> (String, String) {
    let name_str = String::from_utf8_lossy(name);
    if let Some(pos) = name_str.find(':') {
        (name_str[..pos].to_string(), name_str[pos + 1..].to_string())
    } else {
        (String::new(), name_str.to_string())
    }
}

// ===================== 加载 ENI/DENI 配置 =====================

/// 从 XML 文件加载 ENI/DENI 配置
///
/// 支持两种格式:
/// - ENI 标准格式 (根元素 EtherCATConfig，含 DENI 扩展)
/// - 旧版 DENI 格式 (根元素 DarraEtherCATConfiguration)
///
/// # 参数
/// - `path`: XML 文件路径
///
/// # 返回
/// 成功返回配置对象，失败返回错误信息
pub fn load_xml_configuration(path: &str) -> Result<MasterXmlConfiguration, String> {
    // 读取文件内容
    let content = std::fs::read(path)
        .map_err(|e| format!("读取文件失败 '{}': {}", path, e))?;

    // 自动检测编码并转换为 UTF-8
    let xml_str = detect_and_decode(&content);

    let mut reader = Reader::from_str(&xml_str);
    reader.config_mut().trim_text(true);

    // 构建 DOM 树
    let root = build_dom(&mut reader)?;

    // 根据根元素名称选择解析方式
    match root.local_name.as_str() {
        "EtherCATConfig" => load_eni_configuration(&root),
        "DarraEtherCATConfiguration" => load_legacy_deni_configuration(&root),
        other => Err(format!(
            "不支持的配置格式: {}\n支持的格式: EtherCATConfig (ENI/DENI) 或 DarraEtherCATConfiguration (旧版)",
            other
        )),
    }
}

/// 自动检测编码并解码为 UTF-8 字符串
fn detect_and_decode(bytes: &[u8]) -> String {
    // 尝试 UTF-8
    if let Ok(s) = std::str::from_utf8(bytes) {
        return s.to_string();
    }

    // 尝试 GBK (中文 Windows 常见编码)
    let (decoded, _, had_errors) = encoding_rs::GBK.decode(bytes);
    if !had_errors {
        return decoded.to_string();
    }

    // 回退: 有损 UTF-8
    String::from_utf8_lossy(bytes).to_string()
}

/// 加载 ENI 标准格式配置 (EtherCATConfig)
fn load_eni_configuration(root: &XmlNode) -> Result<MasterXmlConfiguration, String> {
    let mut config = MasterXmlConfiguration::default();

    // 查找 Config 容器
    let config_el = match root.find_child("Config") {
        Some(el) => el,
        None => {
            // 如果没有 Config 容器，直接使用根节点
            root
        }
    };

    // ==================== 解析 Master ====================
    if let Some(master_el) = config_el.find_child("Master") {
        // 解析 DENI 扩展: deni:MasterConfig
        if let Some(deni_master) = master_el.find_child_ns("MasterConfig", DENI_PREFIX) {
            parse_deni_master_config(deni_master, &mut config);
        }
    }

    // ==================== 解析 Slave 列表 ====================
    let slave_els = config_el.find_children("Slave");
    for (i, slave_el) in slave_els.iter().enumerate() {
        let mut slave = parse_eni_slave(slave_el);
        // 为未设置索引的从站分配顺序索引
        if slave.index == 0 {
            slave.index = (i + 1) as i32;
        }
        config.slaves.push(slave);
    }

    // ==================== 解析 Cyclic 配置 (标准 ENI) ====================
    if let Some(cyclic_el) = config_el.find_child("Cyclic") {
        parse_cyclic_config(cyclic_el, &mut config);
    }

    Ok(config)
}

/// 加载旧版 DENI 格式 (DarraEtherCATConfiguration)
fn load_legacy_deni_configuration(root: &XmlNode) -> Result<MasterXmlConfiguration, String> {
    let mut config = MasterXmlConfiguration::default();

    config.version = root.attr("version").unwrap_or("2.0").to_string();

    // 主站配置
    if let Some(master_el) = root.find_child("Master") {
        if let Some(v) = master_el.child_text("CycleTimeUs") {
            config.cycle_time_us = v.parse().unwrap_or(1000);
        }
        if let Some(v) = master_el.child_text("DcCycleNs") {
            config.dc_cycle_ns = v.parse().unwrap_or(1000000);
        }
        if let Some(v) = master_el.child_text("ExpectedSlaveCount") {
            config.expected_slave_count = v.parse().unwrap_or(0);
        }
    }

    // 网络配置
    if let Some(network_el) = root.find_child("Network") {
        config.adapter_name = network_el.child_text("AdapterName").unwrap_or("").to_string();
        config.adapter_description = network_el.child_text("AdapterDescription").unwrap_or("").to_string();
        config.adapter_mac = network_el.child_text("AdapterMAC").unwrap_or("").to_string();
        config.use_udp = network_el.child_text("UseUDP").map_or(false, parse_bool_str);
        config.redundancy_enabled = network_el.child_text("RedundancyEnabled").map_or(false, parse_bool_str);
        config.redundant_adapter_name = network_el.child_text("RedundantAdapterName").unwrap_or("").to_string();
    }

    // 优化配置
    if let Some(opt_el) = root.find_child("Optimization") {
        config.frame_high_priority = opt_el.child_text("FrameHighPriority").map_or(false, parse_bool_str);
        config.enable_overlapping_groups = opt_el.child_text("OverlappingGroups").map_or(false, parse_bool_str);
        config.packed_mode = opt_el.child_text("PackedMode").map_or(false, parse_bool_str);
        config.cpu_affinity = opt_el.child_text("CpuAffinity")
            .and_then(|v| v.parse().ok()).unwrap_or(-1);
        config.adaptive_timeout = opt_el.child_text("AdaptiveTimeout").map_or(false, parse_bool_str);
        config.frame_repeat_count = opt_el.child_text("FrameRepeatCount")
            .and_then(|v| v.parse().ok()).unwrap_or(1);
        config.mutex_protection = opt_el.child_text("MutexProtection").map_or(true, parse_bool_str);
    }

    Ok(config)
}

/// 解析 DENI 主站扩展配置 (deni:MasterConfig)
fn parse_deni_master_config(deni: &XmlNode, config: &mut MasterXmlConfiguration) {
    // 网卡信息
    config.adapter_name = deni.child_text_ns("Interface", DENI_PREFIX)
        .or_else(|| deni.child_text("Interface"))
        .unwrap_or("").to_string();
    config.adapter_description = deni.child_text_ns("InterfaceDescription", DENI_PREFIX)
        .or_else(|| deni.child_text("InterfaceDescription"))
        .unwrap_or("").to_string();
    config.adapter_mac = deni.child_text_ns("InterfaceMAC", DENI_PREFIX)
        .or_else(|| deni.child_text("InterfaceMAC"))
        .unwrap_or("").to_string();

    // 周期时间 (支持 unit 属性)
    let cycle_node = deni.find_child_ns("CycleTime", DENI_PREFIX)
        .or_else(|| deni.find_child("CycleTime"));
    if let Some(node) = cycle_node {
        if let Ok(val) = node.text_trimmed().parse::<u32>() {
            let unit = node.attr("unit").unwrap_or("us");
            if unit == "ns" {
                config.cycle_time_us = val / 1000;
            } else {
                config.cycle_time_us = val;
            }
        }
    }

    // DC 周期时间
    let dc_cycle_node = deni.find_child_ns("DcCycleTime", DENI_PREFIX)
        .or_else(|| deni.find_child("DcCycleTime"));
    if let Some(node) = dc_cycle_node {
        if let Ok(val) = node.text_trimmed().parse::<u32>() {
            let unit = node.attr("unit").unwrap_or("ns");
            if unit == "ns" {
                config.dc_cycle_ns = val;
            } else {
                config.dc_cycle_ns = val * 1000;
            }
        }
    }

    // 期望从站数量
    if let Some(v) = deni.child_text_ns("ExpectedSlaveCount", DENI_PREFIX)
        .or_else(|| deni.child_text("ExpectedSlaveCount"))
    {
        config.expected_slave_count = v.parse().unwrap_or(0);
    }

    // 冗余网卡
    config.redundant_adapter_name = deni.child_text_ns("RedundantInterface", DENI_PREFIX)
        .or_else(|| deni.child_text("RedundantInterface"))
        .unwrap_or("").to_string();
    config.redundant_adapter_description = deni.child_text_ns("RedundantInterfaceDescription", DENI_PREFIX)
        .or_else(|| deni.child_text("RedundantInterfaceDescription"))
        .unwrap_or("").to_string();
    config.redundant_adapter_mac = deni.child_text_ns("RedundantInterfaceMAC", DENI_PREFIX)
        .or_else(|| deni.child_text("RedundantInterfaceMAC"))
        .unwrap_or("").to_string();
    if let Some(v) = deni.child_text_ns("RedundancyEnabled", DENI_PREFIX)
        .or_else(|| deni.child_text("RedundancyEnabled"))
    {
        config.redundancy_enabled = parse_bool_str(v);
    }

    // 传输模式配置 (deni:Transport)
    let transport = deni.find_child_ns("Transport", DENI_PREFIX)
        .or_else(|| deni.find_child("Transport"));
    if let Some(t) = transport {
        if let Some(v) = t.child_text_ns("UseUdp", DENI_PREFIX)
            .or_else(|| t.child_text("UseUdp"))
        {
            config.use_udp = parse_bool_str(v);
        }
        if let Some(v) = t.child_text_ns("VlanId", DENI_PREFIX)
            .or_else(|| t.child_text("VlanId"))
        {
            config.vlan_id = v.parse().unwrap_or(0);
        }
        if let Some(v) = t.child_text_ns("VlanPriority", DENI_PREFIX)
            .or_else(|| t.child_text("VlanPriority"))
        {
            config.vlan_priority = v.parse().unwrap_or(0);
        }
    }

    // 性能配置 (deni:Performance)
    let perf = deni.find_child_ns("Performance", DENI_PREFIX)
        .or_else(|| deni.find_child("Performance"));
    if let Some(p) = perf {
        if let Some(v) = p.child_text_ns("OverlappingGroups", DENI_PREFIX)
            .or_else(|| p.child_text("OverlappingGroups"))
        {
            config.enable_overlapping_groups = parse_bool_str(v);
        }
        if let Some(v) = p.child_text_ns("PackedMode", DENI_PREFIX)
            .or_else(|| p.child_text("PackedMode"))
        {
            config.packed_mode = parse_bool_str(v);
        }
        if let Some(v) = p.child_text_ns("FrameHighPriority", DENI_PREFIX)
            .or_else(|| p.child_text("FrameHighPriority"))
        {
            config.frame_high_priority = parse_bool_str(v);
        }
        if let Some(v) = p.child_text_ns("CpuAffinity", DENI_PREFIX)
            .or_else(|| p.child_text("CpuAffinity"))
        {
            config.cpu_affinity = v.parse().unwrap_or(-1);
        }
        if let Some(v) = p.child_text_ns("AdaptiveTimeout", DENI_PREFIX)
            .or_else(|| p.child_text("AdaptiveTimeout"))
        {
            config.adaptive_timeout = parse_bool_str(v);
        }
        if let Some(v) = p.child_text_ns("FrameRepeatCount", DENI_PREFIX)
            .or_else(|| p.child_text("FrameRepeatCount"))
        {
            config.frame_repeat_count = v.parse().unwrap_or(1);
        }
        if let Some(v) = p.child_text_ns("FilterThreshold", DENI_PREFIX)
            .or_else(|| p.child_text("FilterThreshold"))
        {
            config.filter_threshold = v.parse().unwrap_or(3);
        }
        if let Some(v) = p.child_text_ns("MutexProtection", DENI_PREFIX)
            .or_else(|| p.child_text("MutexProtection"))
        {
            config.mutex_protection = parse_bool_str(v);
        }
    }

    // 状态转换超时 (deni:StateTransitionTimeouts)
    let timeout = deni.find_child_ns("StateTransitionTimeouts", DENI_PREFIX)
        .or_else(|| deni.find_child("StateTransitionTimeouts"));
    if let Some(t) = timeout {
        if let Some(v) = t.child_text_ns("InitToPreOp", DENI_PREFIX)
            .or_else(|| t.child_text("InitToPreOp"))
        {
            config.timeout_init_to_preop = v.parse().unwrap_or(0);
        }
        if let Some(v) = t.child_text_ns("PreOpToSafeOp", DENI_PREFIX)
            .or_else(|| t.child_text("PreOpToSafeOp"))
        {
            config.timeout_preop_to_safeop = v.parse().unwrap_or(0);
        }
        if let Some(v) = t.child_text_ns("SafeOpToOp", DENI_PREFIX)
            .or_else(|| t.child_text("SafeOpToOp"))
        {
            config.timeout_safeop_to_op = v.parse().unwrap_or(0);
        }
    }

    // 看门狗配置 (deni:Watchdog)
    let watchdog = deni.find_child_ns("Watchdog", DENI_PREFIX)
        .or_else(|| deni.find_child("Watchdog"));
    if let Some(w) = watchdog {
        if let Some(v) = w.child_text_ns("ProcessDataWatchdogMs", DENI_PREFIX)
            .or_else(|| w.child_text("ProcessDataWatchdogMs"))
        {
            config.process_data_watchdog_ms = v.parse().unwrap_or(0);
        }
        if let Some(v) = w.child_text_ns("PdiWatchdogMs", DENI_PREFIX)
            .or_else(|| w.child_text("PdiWatchdogMs"))
        {
            config.pdi_watchdog_ms = v.parse().unwrap_or(0);
        }
    }

    // DC 漂移补偿
    if let Some(v) = deni.child_text_ns("DriftCompensation", DENI_PREFIX)
        .or_else(|| deni.child_text("DriftCompensation"))
    {
        config.drift_compensation = parse_bool_str(v);
    }

    // 组配置 (deni:GroupConfig)
    let group_config = deni.find_child_ns("GroupConfig", DENI_PREFIX)
        .or_else(|| deni.find_child("GroupConfig"));
    if let Some(gc) = group_config {
        // 解析 Group 元素
        for group_el in gc.children.iter().filter(|c| c.local_name.eq_ignore_ascii_case("Group")) {
            let mut gd = GroupConfigData::default();
            if let Some(v) = group_el.attr("Index") {
                gd.group_index = v.parse().unwrap_or(0);
            }
            if let Some(v) = group_el.attr("Enabled") {
                gd.enabled = parse_bool_str(v);
            }
            if let Some(v) = group_el.attr("CycleDivider") {
                gd.cycle_divider = v.parse().unwrap_or(1);
            }
            if gd.group_index > 0 {
                config.group_configs.push(gd);
            }
        }

        // 从站组分配 (SlaveGroupAssignment)
        let sga = gc.find_child_ns("SlaveGroupAssignment", DENI_PREFIX)
            .or_else(|| gc.find_child("SlaveGroupAssignment"));
        if let Some(sga_el) = sga {
            for slave_el in sga_el.children.iter().filter(|c| c.local_name.eq_ignore_ascii_case("Slave")) {
                if let (Some(idx_str), Some(grp_str)) = (slave_el.attr("Index"), slave_el.attr("Group")) {
                    if let (Ok(idx), Ok(grp)) = (idx_str.parse::<u16>(), grp_str.parse::<u8>()) {
                        config.slave_group_assignments.insert(idx, grp);
                    }
                }
            }
        }
    }

    // DC 配置 (deni:DistributedClocks)
    let dc = deni.find_child_ns("DistributedClocks", DENI_PREFIX)
        .or_else(|| deni.find_child("DistributedClocks"));
    if let Some(dc_el) = dc {
        if let Some(v) = dc_el.attr("enabled") {
            config.dc_enabled = parse_bool_str(v);
        }
        for slave_dc_el in dc_el.children.iter().filter(|c| c.local_name.eq_ignore_ascii_case("SlaveDC")) {
            let mut sdc = SlaveDcConfig::default();
            if let Some(v) = slave_dc_el.attr("index") {
                sdc.slave_index = v.parse().unwrap_or(0);
            }
            if let Some(v) = slave_dc_el.attr("vendorId") {
                sdc.vendor_id = parse_uint_hex_or_dec(v).unwrap_or(0);
            }
            if let Some(v) = slave_dc_el.attr("productCode") {
                sdc.product_code = parse_uint_hex_or_dec(v).unwrap_or(0);
            }
            if let Some(v) = slave_dc_el.child_text_ns("Sync0CycleNs", DENI_PREFIX)
                .or_else(|| slave_dc_el.child_text("Sync0CycleNs"))
            {
                sdc.sync0_cycle_ns = v.parse().unwrap_or(0);
            }
            if let Some(v) = slave_dc_el.child_text_ns("Sync1CycleNs", DENI_PREFIX)
                .or_else(|| slave_dc_el.child_text("Sync1CycleNs"))
            {
                sdc.sync1_cycle_ns = v.parse().unwrap_or(0);
            }
            if let Some(v) = slave_dc_el.child_text_ns("ShiftNs", DENI_PREFIX)
                .or_else(|| slave_dc_el.child_text("ShiftNs"))
            {
                sdc.shift_ns = v.parse().unwrap_or(0);
            }
            config.slave_dc_configs.push(sdc);
        }
    }

    // 元数据 (deni:Metadata)
    let metadata = deni.find_child_ns("Metadata", DENI_PREFIX)
        .or_else(|| deni.find_child("Metadata"));
    if let Some(m) = metadata {
        config.saved_date = m.child_text_ns("SavedDate", DENI_PREFIX)
            .or_else(|| m.child_text("SavedDate"))
            .unwrap_or("").to_string();
        config.saved_by = m.child_text_ns("SavedBy", DENI_PREFIX)
            .or_else(|| m.child_text("SavedBy"))
            .unwrap_or("").to_string();
        config.machine_name = m.child_text_ns("MachineName", DENI_PREFIX)
            .or_else(|| m.child_text("MachineName"))
            .unwrap_or("").to_string();
        config.dll_version = m.child_text_ns("DllVersion", DENI_PREFIX)
            .or_else(|| m.child_text("DllVersion"))
            .unwrap_or("").to_string();
    }

    // 同步 QoS 字段
    config.qos.vlan_id = config.vlan_id;
    config.qos.vlan_priority = config.vlan_priority;
    config.qos.frame_high_priority = config.frame_high_priority;
}

/// 解析 Cyclic 配置节 (标准 ENI)
fn parse_cyclic_config(cyclic: &XmlNode, config: &mut MasterXmlConfiguration) {
    // 回退: 从 Cyclic/CycleTime 读取周期时间
    if config.cycle_time_us == 1000 {
        if let Some(ct_node) = cyclic.find_child("CycleTime") {
            if let Ok(val) = ct_node.text_trimmed().parse::<u32>() {
                let unit = ct_node.attr("unit").unwrap_or("us");
                if unit == "ns" || val > 100000 {
                    config.cycle_time_us = val / 1000;
                } else {
                    config.cycle_time_us = val;
                }
            }
        }
    }

    // DC 配置回退
    if !config.dc_enabled {
        let dc_el = cyclic.find_child("Dc").or_else(|| cyclic.find_child("DC"));
        if let Some(dc) = dc_el {
            config.dc_enabled = true;
            let dc_cycle_el = dc.find_child("CycleTime")
                .or_else(|| dc.find_child("CycleTimeNs"));
            if let Some(node) = dc_cycle_el {
                if let Ok(val) = node.text_trimmed().parse::<u32>() {
                    let unit = node.attr("unit").unwrap_or("ns");
                    if unit == "ns" || val > 100000 {
                        config.dc_cycle_ns = val;
                    } else {
                        config.dc_cycle_ns = val * 1000;
                    }
                }
            }
        }
    }

    // 检测重叠组: 多个包含 LRW (Cmd=12) 的 Frame -> 分组模式
    let frames = cyclic.find_children("Frame");
    let mut lrw_frame_count = 0;
    for frame in &frames {
        for cmd_el in frame.find_children("Cmd") {
            if let Some(inner_cmd) = cmd_el.child_text("Cmd") {
                if let Ok(cmd_type) = inner_cmd.parse::<i32>() {
                    if cmd_type == 12 {
                        lrw_frame_count += 1;
                    }
                }
            }
        }
    }
    if lrw_frame_count > 1 {
        config.enable_overlapping_groups = true;
    }
}

/// 解析 ENI 格式的从站配置
fn parse_eni_slave(slave_el: &XmlNode) -> SlaveXmlConfiguration {
    let mut slave = SlaveXmlConfiguration::default();

    // Slave/Info (ENI 标准)
    if let Some(info) = slave_el.find_child("Info") {
        slave.name = info.child_text("Name").unwrap_or("").to_string();
        if let Some(v) = info.child_text("PhysAddr") {
            slave.config_addr = parse_u16_hex_or_dec(v).unwrap_or(0);
        }
        if let Some(v) = info.child_text("VendorId") {
            slave.vendor_id = parse_uint_hex_or_dec(v).unwrap_or(0);
        }
        if let Some(v) = info.child_text("ProductCode") {
            slave.product_code = parse_uint_hex_or_dec(v).unwrap_or(0);
        }
        if let Some(v) = info.child_text("RevisionNo") {
            slave.revision = parse_uint_hex_or_dec(v).unwrap_or(0);
        }
        if let Some(v) = info.child_text("SerialNo") {
            slave.serial_no = parse_uint_hex_or_dec(v).unwrap_or(0);
        }
        // ProductRevision -> DriveName
        if let Some(v) = info.child_text("ProductRevision") {
            slave.drive_name = v.to_string();
        }
    }

    // Slave/ProcessData (ENI 标准)
    if let Some(pd) = slave_el.find_child("ProcessData") {
        if let Some(send) = pd.find_child("Send") {
            if let Some(v) = send.child_text("BitLength") {
                if let Ok(bits) = v.parse::<i32>() {
                    slave.output_size = bits / 8;
                }
            }
        }
        if let Some(recv) = pd.find_child("Recv") {
            if let Some(v) = recv.child_text("BitLength") {
                if let Ok(bits) = v.parse::<i32>() {
                    slave.input_size = bits / 8;
                }
            }
        }
    }

    // Slave/Mailbox (ENI 标准)
    if let Some(mbx) = slave_el.find_child("Mailbox") {
        // 邮箱发送/接收配置
        if let Some(send) = mbx.find_child("Send") {
            if let Some(v) = send.child_text("Start") {
                slave.mbx_write_offset = parse_u16_hex_or_dec(v).unwrap_or(0);
            }
            if let Some(v) = send.child_text("Length") {
                slave.mbx_write_length = v.parse().unwrap_or(0);
            }
        }
        if let Some(recv) = mbx.find_child("Recv") {
            if let Some(v) = recv.child_text("Start") {
                slave.mbx_read_offset = parse_u16_hex_or_dec(v).unwrap_or(0);
            }
            if let Some(v) = recv.child_text("Length") {
                slave.mbx_read_length = v.parse().unwrap_or(0);
            }
            if let Some(v) = recv.child_text("PollTime") {
                slave.mbx_poll_time = v.parse().unwrap_or(0);
            }
        }

        // Bootstrap 邮箱
        if let Some(boot) = mbx.find_child("Bootstrap") {
            if let Some(s) = boot.find_child("Send") {
                if let Some(v) = s.child_text("Start") {
                    slave.bootstrap_send_offset = parse_u16_hex_or_dec(v).unwrap_or(0);
                }
                if let Some(v) = s.child_text("Length") {
                    slave.bootstrap_send_length = v.parse().unwrap_or(0);
                }
            }
            if let Some(r) = boot.find_child("Recv") {
                if let Some(v) = r.child_text("Start") {
                    slave.bootstrap_recv_offset = parse_u16_hex_or_dec(v).unwrap_or(0);
                }
                if let Some(v) = r.child_text("Length") {
                    slave.bootstrap_recv_length = v.parse().unwrap_or(0);
                }
            }
        }

        // CoE 初始化命令
        if let Some(coe) = mbx.find_child("CoE") {
            slave.has_coe = true;
            if let Some(init_cmds) = coe.find_child("InitCmds") {
                for init_cmd in init_cmds.find_children("InitCmd") {
                    if let Some(sdo) = parse_coe_init_cmd(init_cmd) {
                        slave.sdo_init.push(sdo);
                    }
                }
            }
            // CiA 402 配置文件编号
            if let Some(profile) = coe.find_child("Profile") {
                if let Some(ci) = profile.find_child("ChannelInfo") {
                    if let Some(v) = ci.child_text("ProfileNo") {
                        slave.cia402_profile_no = v.parse().unwrap_or(0);
                    }
                }
            }
        }

        // DataLinkLayer 属性
        if let Some(v) = mbx.attr("DataLinkLayer") {
            slave.mailbox_data_link_layer = parse_bool_str(v);
        }

        // 协议检测
        if mbx.find_child("SoE").is_some() { slave.has_soe = true; }
        if mbx.find_child("AoE").is_some() { slave.has_aoe = true; }
        if mbx.find_child("EoE").is_some() { slave.has_eoe = true; }
        if mbx.find_child("FoE").is_some() { slave.has_foe = true; }
        if mbx.find_child("VoE").is_some() { slave.has_voe = true; }
    }

    // Slave/Dc (ENI 标准 DC 配置)
    let dc_el = slave_el.find_child("Dc").or_else(|| slave_el.find_child("DC"));
    if let Some(dc) = dc_el {
        slave.has_dc = true;
        if let Some(v) = dc.child_text("CycleTime0") {
            slave.sync0_cycle_ns = v.parse().unwrap_or(0);
        }
        if let Some(v) = dc.child_text("CycleTime1") {
            slave.sync1_cycle_ns = v.parse().unwrap_or(0);
        }
        if let Some(v) = dc.child_text("ShiftTime") {
            slave.shift_ns = parse_i32_hex_or_dec(v).unwrap_or(0);
        }
    }

    // DENI 扩展: deni:SlaveConfig
    let deni_slave = slave_el.find_child_ns("SlaveConfig", DENI_PREFIX)
        .or_else(|| slave_el.children.iter().find(|c| c.local_name == "SlaveConfig" && !c.prefix.is_empty()));
    if let Some(ds) = deni_slave {
        parse_deni_slave_config(ds, &mut slave);
    }

    slave
}

/// 解析 CoE InitCmd (SDO 初始化命令)
fn parse_coe_init_cmd(cmd: &XmlNode) -> Option<StartupSdoConfig> {
    let mut sdo = StartupSdoConfig::default();

    // Transition (如 "PS", "IP", "SO" 等)
    sdo.transition = cmd.child_text("Transition").unwrap_or("PS").to_string();

    // Comment/描述
    sdo.comment = cmd.child_text("Comment").unwrap_or("").to_string();

    // 超时
    if let Some(v) = cmd.child_text("Timeout") {
        sdo.timeout_ms = v.parse().unwrap_or(0);
    }

    // CompleteAccess 标记
    if let Some(v) = cmd.child_text("CompleteAccess") {
        sdo.complete_access = parse_bool_str(v);
    }

    // Index (CoE 对象索引)
    if let Some(v) = cmd.child_text("Index") {
        sdo.index = parse_u16_hex_or_dec(v)?;
    }

    // SubIndex
    if let Some(v) = cmd.child_text("SubIndex") {
        sdo.sub_index = parse_u8_hex_or_dec(v).unwrap_or(0);
    }

    // Data (十六进制字节串)
    if let Some(v) = cmd.child_text("Data") {
        sdo.data = hex_string_to_bytes(v).unwrap_or_default();
    }

    Some(sdo)
}

/// 解析 DENI 从站扩展配置 (deni:SlaveConfig)
fn parse_deni_slave_config(ds: &XmlNode, slave: &mut SlaveXmlConfiguration) {
    // 位置/索引
    if let Some(v) = ds.child_text_ns("Position", DENI_PREFIX).or_else(|| ds.child_text("Position")) {
        slave.index = v.parse().unwrap_or(0);
    }

    // DriveName
    if let Some(v) = ds.child_text_ns("DriveName", DENI_PREFIX).or_else(|| ds.child_text("DriveName")) {
        slave.drive_name = v.to_string();
    }

    // 序列号
    if let Some(v) = ds.child_text_ns("SerialNumber", DENI_PREFIX).or_else(|| ds.child_text("SerialNumber")) {
        slave.serial_no = parse_uint_hex_or_dec(v).unwrap_or(0);
    }

    // 别名地址
    if let Some(v) = ds.child_text_ns("AliasAddress", DENI_PREFIX).or_else(|| ds.child_text("AliasAddress")) {
        slave.alias_addr = parse_u16_hex_or_dec(v).unwrap_or(0);
    }

    // 可选从站
    if let Some(v) = ds.child_text_ns("Optional", DENI_PREFIX).or_else(|| ds.child_text("Optional")) {
        slave.is_optional = parse_bool_str(v);
    }

    // 帧重复支持
    if let Some(v) = ds.child_text_ns("SupportsFrameRepeat", DENI_PREFIX).or_else(|| ds.child_text("SupportsFrameRepeat")) {
        slave.supports_frame_repeat = parse_bool_str(v);
    }

    // 邮箱配置
    let mbx = ds.find_child_ns("MailboxConfig", DENI_PREFIX).or_else(|| ds.find_child("MailboxConfig"));
    if let Some(m) = mbx {
        if let Some(v) = m.child_text_ns("WriteOffset", DENI_PREFIX).or_else(|| m.child_text("WriteOffset")) {
            slave.mbx_write_offset = parse_u16_hex_or_dec(v).unwrap_or(0);
        }
        if let Some(v) = m.child_text_ns("ReadOffset", DENI_PREFIX).or_else(|| m.child_text("ReadOffset")) {
            slave.mbx_read_offset = parse_u16_hex_or_dec(v).unwrap_or(0);
        }
        if let Some(v) = m.child_text_ns("WriteLength", DENI_PREFIX).or_else(|| m.child_text("WriteLength")) {
            slave.mbx_write_length = v.parse().unwrap_or(0);
        }
        if let Some(v) = m.child_text_ns("ReadLength", DENI_PREFIX).or_else(|| m.child_text("ReadLength")) {
            slave.mbx_read_length = v.parse().unwrap_or(0);
        }
    }

    // DC 配置
    let dc = ds.find_child_ns("DC", DENI_PREFIX).or_else(|| ds.find_child("DC"));
    if let Some(dc_el) = dc {
        if let Some(v) = dc_el.child_text_ns("HasDC", DENI_PREFIX).or_else(|| dc_el.child_text("HasDC")) {
            slave.has_dc = parse_bool_str(v);
        }
        if let Some(v) = dc_el.child_text_ns("Sync0CycleNs", DENI_PREFIX).or_else(|| dc_el.child_text("Sync0CycleNs")) {
            slave.sync0_cycle_ns = v.parse().unwrap_or(0);
        }
        if let Some(v) = dc_el.child_text_ns("Sync1CycleNs", DENI_PREFIX).or_else(|| dc_el.child_text("Sync1CycleNs")) {
            slave.sync1_cycle_ns = v.parse().unwrap_or(0);
        }
        if let Some(v) = dc_el.child_text_ns("ShiftNs", DENI_PREFIX).or_else(|| dc_el.child_text("ShiftNs")) {
            slave.shift_ns = v.parse().unwrap_or(0);
        }
    }

    // 兼容旧版直接 HasDC 节点
    if dc.is_none() {
        if let Some(v) = ds.child_text_ns("HasDC", DENI_PREFIX).or_else(|| ds.child_text("HasDC")) {
            slave.has_dc = parse_bool_str(v);
        }
    }

    // 看门狗配置
    let wd = ds.find_child_ns("Watchdog", DENI_PREFIX).or_else(|| ds.find_child("Watchdog"));
    if let Some(w) = wd {
        if let Some(v) = w.child_text_ns("WdDivider", DENI_PREFIX).or_else(|| w.child_text("WdDivider")) {
            slave.wd_divider = v.parse().unwrap_or(0);
        }
        if let Some(v) = w.child_text_ns("WdTimePdi", DENI_PREFIX).or_else(|| w.child_text("WdTimePdi")) {
            slave.wd_time_pdi = v.parse().unwrap_or(0);
        }
        if let Some(v) = w.child_text_ns("WdTimePd", DENI_PREFIX).or_else(|| w.child_text("WdTimePd")) {
            slave.wd_time_pd = v.parse().unwrap_or(0);
        }
    }

    // SyncManager 配置
    let sm_list = ds.find_child_ns("SyncManagers", DENI_PREFIX).or_else(|| ds.find_child("SyncManagers"));
    if let Some(sml) = sm_list {
        for sm_el in sml.children.iter().filter(|c| c.local_name.eq_ignore_ascii_case("SM")) {
            let mut sm = SyncManagerConfig::default();
            if let Some(v) = sm_el.attr("index") {
                sm.index = v.parse().unwrap_or(0);
            }
            if let Some(v) = sm_el.child_text_ns("StartAddr", DENI_PREFIX).or_else(|| sm_el.child_text("StartAddr")) {
                sm.start_addr = parse_u16_hex_or_dec(v).unwrap_or(0);
            }
            if let Some(v) = sm_el.child_text_ns("Length", DENI_PREFIX).or_else(|| sm_el.child_text("Length")) {
                sm.length = v.parse().unwrap_or(0);
            }
            if let Some(v) = sm_el.child_text_ns("Flags", DENI_PREFIX).or_else(|| sm_el.child_text("Flags")) {
                sm.flags = parse_uint_hex_or_dec(v).unwrap_or(0);
            }
            if let Some(v) = sm_el.child_text_ns("Type", DENI_PREFIX).or_else(|| sm_el.child_text("Type")) {
                sm.sm_type = v.parse().unwrap_or(0);
            }
            slave.sync_managers.push(sm);
        }
    }

    // PDO 控制标志
    let pdo_cfg = ds.find_child_ns("PDOConfig", DENI_PREFIX).or_else(|| ds.find_child("PDOConfig"));
    if let Some(pc) = pdo_cfg {
        if let Some(v) = pc.child_text_ns("WriteAssignment", DENI_PREFIX).or_else(|| pc.child_text("WriteAssignment")) {
            slave.should_write_pdo_assignment = parse_bool_str(v);
        }
        if let Some(v) = pc.child_text_ns("WriteConfiguration", DENI_PREFIX).or_else(|| pc.child_text("WriteConfiguration")) {
            slave.should_write_pdo_configuration = parse_bool_str(v);
        }
        if let Some(v) = pc.child_text_ns("CompleteAccess", DENI_PREFIX).or_else(|| pc.child_text("CompleteAccess")) {
            slave.supports_complete_access = parse_bool_str(v);
        }
    }

    // 设备信息
    let dev_info = ds.find_child_ns("DeviceInfo", DENI_PREFIX).or_else(|| ds.find_child("DeviceInfo"));
    if let Some(di) = dev_info {
        if let Some(v) = di.child_text_ns("HasMDP", DENI_PREFIX).or_else(|| di.child_text("HasMDP")) {
            slave.has_mdp = parse_bool_str(v);
        }
        if let Some(v) = di.child_text_ns("BlockLRW", DENI_PREFIX).or_else(|| di.child_text("BlockLRW")) {
            slave.block_lrw = parse_bool_str(v);
        }
        if let Some(v) = di.child_text_ns("Dtype", DENI_PREFIX).or_else(|| di.child_text("Dtype")) {
            slave.dtype = v.parse().unwrap_or(0);
        }
        if let Some(v) = di.child_text_ns("Topology", DENI_PREFIX).or_else(|| di.child_text("Topology")) {
            slave.topology = v.parse().unwrap_or(0);
        }
        if let Some(v) = di.child_text_ns("ActivePorts", DENI_PREFIX).or_else(|| di.child_text("ActivePorts")) {
            slave.active_ports = v.parse().unwrap_or(0);
        }
        if let Some(v) = di.child_text_ns("SupportsFrameRepeat", DENI_PREFIX).or_else(|| di.child_text("SupportsFrameRepeat")) {
            slave.supports_frame_repeat = parse_bool_str(v);
        }
    } else {
        // 兼容旧版直接 HasMDP 节点
        if let Some(v) = ds.child_text_ns("HasMDP", DENI_PREFIX).or_else(|| ds.child_text("HasMDP")) {
            slave.has_mdp = parse_bool_str(v);
        }
    }

    // 协议支持
    let protocols = ds.find_child_ns("Protocols", DENI_PREFIX).or_else(|| ds.find_child("Protocols"));
    if let Some(p) = protocols {
        if let Some(v) = p.child_text_ns("CoE", DENI_PREFIX).or_else(|| p.child_text("CoE")) {
            slave.has_coe = parse_bool_str(v);
        }
        if let Some(v) = p.child_text_ns("FoE", DENI_PREFIX).or_else(|| p.child_text("FoE")) {
            slave.has_foe = parse_bool_str(v);
        }
        if let Some(v) = p.child_text_ns("EoE", DENI_PREFIX).or_else(|| p.child_text("EoE")) {
            slave.has_eoe = parse_bool_str(v);
        }
        if let Some(v) = p.child_text_ns("SoE", DENI_PREFIX).or_else(|| p.child_text("SoE")) {
            slave.has_soe = parse_bool_str(v);
        }
        if let Some(v) = p.child_text_ns("AoE", DENI_PREFIX).or_else(|| p.child_text("AoE")) {
            slave.has_aoe = parse_bool_str(v);
        }
        if let Some(v) = p.child_text_ns("VoE", DENI_PREFIX).or_else(|| p.child_text("VoE")) {
            slave.has_voe = parse_bool_str(v);
        }
    }

    // PDO 映射详情
    let pdo_mappings = ds.find_child_ns("PDOMappings", DENI_PREFIX).or_else(|| ds.find_child("PDOMappings"));
    if let Some(pm) = pdo_mappings {
        for pdo_el in &pm.children {
            let is_input = pdo_el.local_name == "TxPdo";
            let target = if is_input { &mut slave.input_pdos } else { &mut slave.output_pdos };
            let deni_pdo_idx = pdo_el.attr("index")
                .and_then(parse_u16_hex_or_dec)
                .unwrap_or(0);

            for entry_el in pdo_el.find_children("Entry") {
                let mut entry = PdoEntryConfig::default();
                entry.pdo_index = deni_pdo_idx;
                if let Some(v) = entry_el.attr("index") {
                    entry.index = parse_u16_hex_or_dec(v).unwrap_or(0);
                }
                if let Some(v) = entry_el.attr("subIndex") {
                    entry.sub_index = parse_u8_hex_or_dec(v).unwrap_or(0);
                }
                if let Some(v) = entry_el.attr("bitLength") {
                    entry.bit_length = v.parse().unwrap_or(0);
                }
                entry.name = entry_el.attr("name").unwrap_or("").to_string();
                entry.data_type = entry_el.attr("dataType").unwrap_or("").to_string();
                target.push(entry);
            }
        }
    }

    // Startup 参数 (DENI 扩展)
    let startup_params = ds.find_child_ns("StartupParameters", DENI_PREFIX)
        .or_else(|| ds.find_child("StartupParameters"));
    if let Some(sp) = startup_params {
        for param_el in sp.children.iter().filter(|c| c.local_name.eq_ignore_ascii_case("StartupParam")) {
            let mut sdo = StartupSdoConfig::default();
            if let Some(v) = param_el.attr("Index") {
                sdo.index = parse_u16_hex_or_dec(v).unwrap_or(0);
            }
            if let Some(v) = param_el.attr("SubIndex") {
                sdo.sub_index = parse_u8_hex_or_dec(v).unwrap_or(0);
            }
            if let Some(v) = param_el.attr("Data") {
                sdo.data = hex_string_to_bytes(v).unwrap_or_default();
            }
            if let Some(v) = param_el.attr("Transition") {
                sdo.transition = v.to_string();
            }
            if let Some(v) = param_el.attr("CompleteAccess") {
                sdo.complete_access = parse_bool_str(v);
            }
            sdo.comment = param_el.attr("Comment").unwrap_or("").to_string();
            slave.sdo_init.push(sdo);
        }
    }
}


// ===================== 保存 ENI/DENI 配置 (已移除) =====================
//
// save_xml_configuration 已从公开 API 中删除:
// DENI/ENI 导出是 Darra 产品内部功能 (由 Darra 工具链写入), SDK 用户只应
// 读取 (load_xml_configuration / apply_xml_configuration) 而不应写回。
// 对应的全部 write_* 辅助函数也一并移除, 避免留下 dead_code。

// ===================== 单元测试 =====================

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn test_parse_uint_hex_or_dec() {
        assert_eq!(parse_uint_hex_or_dec("0x1234"), Some(0x1234));
        assert_eq!(parse_uint_hex_or_dec("#x00001234"), Some(0x1234));
        assert_eq!(parse_uint_hex_or_dec("1000"), Some(1000));
        assert_eq!(parse_uint_hex_or_dec(""), None);
    }

    #[test]
    fn test_hex_string_round_trip() {
        let data = vec![0x01, 0x02, 0xAB, 0xCD];
        let hex = bytes_to_hex_string(&data);
        assert_eq!(hex, "0102abcd");
        let back = hex_string_to_bytes(&hex).unwrap();
        assert_eq!(back, data);
    }

    // test_save_and_load_round_trip 已移除:
    // save_xml_configuration 不再是公开 API, 相关保存-加载往返测试随之删除。
    // load_xml_configuration / apply_xml_configuration 的独立测试请另行添加。
}
