//! EoE (Ethernet over EtherCAT) 完整实现
//!
//! 对齐 C# EoEInstance，提供:
//! - EoEInstance: IP/子网/网关/MAC/DNS 属性读写、帧收发、Ping
//! - EoEPingResult: Ping 结果
//! - 以太网帧构建辅助 (IP/ICMP/ARP)
//! - ARP 缓存管理
//! - 地址过滤器管理
//!
//! # 异步使用 (对齐 C# EoEInstance.PingAsync / SendFrameAsync)
//!
//! EoE 方法同步阻塞, Ping 尤其建议异步化 (超时前要等若干秒)。
//! 本 crate 提供**双轨**异步 API:
//!
//! ## 轨道 1: std::thread (无依赖)
//!
//! ```ignore
//! let handle = EoEInstance::ping_blocking(0, 1, 0, target_ip_u32, 5000);
//! let result: EoEPingResult = handle.join().unwrap();
//!
//! let handle = EoEInstance::receive_frame_blocking(0, 1, 0, 100);
//! let frame = handle.join().unwrap()?;
//! ```
//!
//! ## 轨道 2: tokio async (可选 feature `async-tokio`)
//!
//! ```ignore
//! let eoe = slave.eoe(port);
//! let result = eoe.ping_async(target_ip, 5000).await;
//! let frame = eoe.receive_frame_async(100).await?;
//! eoe.send_frame_async(frame_bytes, 100).await?;
//!
//! // 并行 Ping 多个从站
//! use tokio::task::JoinSet;
//! let mut set = JoinSet::new();
//! for slave_idx in 1..=num_slaves {
//!     set.spawn(async move {
//!         let eoe = master.slave(slave_idx).eoe(0);
//!         eoe.ping_async(target_ip, 1000).await
//!     });
//! }
//! ```

use std::collections::HashMap;
use std::time::{Duration, Instant};
use crate::data::error::{DarraError, Result};
use crate::utils::ffi;
use std::os::raw::c_int;

// ===================== IP/ICMP 校验和 =====================

/// 计算 Internet 校验和（RFC 1071）
///
/// 适用于 IP 头、ICMP 报文等需要 16 位反码累加和的场景。
pub fn internet_checksum(data: &[u8]) -> u16 {
    let mut sum: u32 = 0;
    let mut i = 0;
    while i + 1 < data.len() {
        sum += u16::from_be_bytes([data[i], data[i + 1]]) as u32;
        i += 2;
    }
    // 奇数字节补零处理
    if i < data.len() {
        sum += (data[i] as u32) << 8;
    }
    // 折叠进位
    while (sum >> 16) != 0 {
        sum = (sum & 0xFFFF) + (sum >> 16);
    }
    !(sum as u16)
}

// ===================== 以太网帧构建辅助 =====================

/// 构建最小以太网帧（不含 FCS）
///
/// - dst_mac: 6 字节目标 MAC
/// - src_mac: 6 字节源 MAC
/// - ethertype: 0x0800=IPv4, 0x0806=ARP
/// - payload: 有效载荷
fn build_ethernet_frame(dst_mac: &[u8; 6], src_mac: &[u8; 6], ethertype: u16, payload: &[u8]) -> Vec<u8> {
    let mut frame = Vec::with_capacity(14 + payload.len());
    frame.extend_from_slice(dst_mac);
    frame.extend_from_slice(src_mac);
    frame.extend_from_slice(&ethertype.to_be_bytes());
    frame.extend_from_slice(payload);
    // 以太网最小帧长度为 60 字节（不含 FCS）
    while frame.len() < 60 {
        frame.push(0);
    }
    frame
}

/// 构建 IPv4 头（20 字节，不含选项）
fn build_ip_header(src_ip: u32, dst_ip: u32, protocol: u8, payload_len: u16) -> Vec<u8> {
    let total_len = 20u16 + payload_len;
    let mut header = vec![
        0x45,                              // 版本=4, 头长度=5*4=20
        0x00,                              // DSCP/ECN
        (total_len >> 8) as u8,            // 总长度高字节
        (total_len & 0xFF) as u8,          // 总长度低字节
        0x00, 0x01,                        // 标识
        0x40, 0x00,                        // 标志=DF, 分片偏移=0
        0x40,                              // TTL=64
        protocol,                          // 协议
        0x00, 0x00,                        // 校验和（先填0）
        // 源 IP（大端）
        ((src_ip >> 24) & 0xFF) as u8,
        ((src_ip >> 16) & 0xFF) as u8,
        ((src_ip >>  8) & 0xFF) as u8,
        ( src_ip        & 0xFF) as u8,
        // 目标 IP（大端）
        ((dst_ip >> 24) & 0xFF) as u8,
        ((dst_ip >> 16) & 0xFF) as u8,
        ((dst_ip >>  8) & 0xFF) as u8,
        ( dst_ip        & 0xFF) as u8,
    ];
    // 填写 IP 头校验和
    let checksum = internet_checksum(&header);
    header[10] = (checksum >> 8) as u8;
    header[11] = (checksum & 0xFF) as u8;
    header
}

/// 构建 ICMP Echo 请求报文
fn build_icmp_echo(id: u16, seq: u16, data: &[u8]) -> Vec<u8> {
    let mut icmp = Vec::with_capacity(8 + data.len());
    icmp.push(8);                          // 类型=8 (Echo Request)
    icmp.push(0);                          // 代码=0
    icmp.extend_from_slice(&[0, 0]);       // 校验和（先填0）
    icmp.extend_from_slice(&id.to_be_bytes());
    icmp.extend_from_slice(&seq.to_be_bytes());
    icmp.extend_from_slice(data);
    // 填写 ICMP 校验和
    let checksum = internet_checksum(&icmp);
    icmp[2] = (checksum >> 8) as u8;
    icmp[3] = (checksum & 0xFF) as u8;
    icmp
}

// ===================== EoE Ping =====================

/// Ping 结果
#[derive(Debug, Clone)]
pub struct PingResult {
    /// 是否收到回应
    pub success: bool,
    /// RTT（往返时间），None 表示超时
    pub rtt: Option<Duration>,
    /// 响应报文的 ICMP 序列号
    pub seq: u16,
}

/// 通过 EoE 向从站内部 IP 发送 ICMP Echo 请求（Ping）
///
/// 参数说明：
/// - `master_index`: 主站索引
/// - `slave_index`: 从站索引
/// - `port`: EoE 端口号（通常为 0）
/// - `src_mac`: 主站侧虚拟 MAC
/// - `src_ip`: 主站侧 IP（u32 大端, 如 192.168.1.1 = 0xC0A80101）
/// - `dst_ip`: 目标 IP
/// - `seq`: ICMP 序列号
/// - `payload`: ICMP 数据载荷
/// - `timeout_us`: 等待回应超时（微秒）
pub fn eoe_ping(
    master_index: u16,
    slave_index: u16,
    port: u8,
    src_mac: &[u8; 6],
    dst_mac: &[u8; 6],
    src_ip: u32,
    dst_ip: u32,
    seq: u16,
    payload: &[u8],
    timeout_us: i32,
) -> Result<PingResult> {
    // 构建 ICMP 报文
    let icmp = build_icmp_echo(0xDA12, seq, payload);
    // 构建 IP 报文
    let mut ip = build_ip_header(src_ip, dst_ip, 1, icmp.len() as u16);
    ip.extend_from_slice(&icmp);
    // 构建以太网帧 (EtherType 0x0800 = IPv4)
    let frame = build_ethernet_frame(dst_mac, src_mac, 0x0800, &ip);

    let start = Instant::now();

    // 通过 EoE 发送
    let ok = unsafe {
        ffi::EOESendFrame(master_index, slave_index, port,
                          frame.as_ptr(), frame.len() as c_int, timeout_us)
    };
    if ok == 0 {
        return Ok(PingResult { success: false, rtt: None, seq });
    }

    // 等待接收回应
    let mut resp_ptr: *mut std::ffi::c_void = std::ptr::null_mut();
    let mut resp_size: c_int = 0;
    let recv_ok = unsafe {
        ffi::EOEReceiveFrame(master_index, slave_index, port,
                             &mut resp_ptr, &mut resp_size, timeout_us)
    };
    let rtt = start.elapsed();

    if recv_ok == 0 || resp_ptr.is_null() || resp_size < 42 {
        if !resp_ptr.is_null() { unsafe { ffi::FreeMemory(resp_ptr) }; }
        return Ok(PingResult { success: false, rtt: None, seq });
    }

    // 解析回应帧，验证 ICMP 类型和序列号
    let resp = unsafe {
        std::slice::from_raw_parts(resp_ptr as *const u8, resp_size as usize).to_vec()
    };
    unsafe { ffi::FreeMemory(resp_ptr) };

    // 以太网头 14 字节，IP 头 20 字节，ICMP 从偏移 34 开始
    if resp.len() < 36 {
        return Ok(PingResult { success: false, rtt: None, seq });
    }
    // 检查 EtherType = 0x0800
    let ethertype = u16::from_be_bytes([resp[12], resp[13]]);
    if ethertype != 0x0800 {
        return Ok(PingResult { success: false, rtt: None, seq });
    }
    // IP 协议 = ICMP (1)
    let protocol = resp[23];
    if protocol != 1 {
        return Ok(PingResult { success: false, rtt: None, seq });
    }
    // ICMP 类型 = 0 (Echo Reply)
    let icmp_type = resp[34];
    // ICMP 序列号（偏移 38-39）
    let resp_seq = u16::from_be_bytes([resp[38], resp[39]]);
    let success = icmp_type == 0 && resp_seq == seq;

    Ok(PingResult { success, rtt: Some(rtt), seq })
}

// ===================== ARP 缓存 =====================

/// ARP 缓存条目
#[derive(Debug, Clone)]
pub struct ArpEntry {
    /// IP 地址（u32 大端）
    pub ip: u32,
    /// MAC 地址
    pub mac: [u8; 6],
    /// 最后更新时间
    pub last_seen: Instant,
    /// 是否由 ARP 请求学习（false = 静态配置）
    pub dynamic: bool,
}

impl ArpEntry {
    /// 检查条目是否已超时（默认 300 秒）
    pub fn is_expired(&self, ttl: Duration) -> bool {
        self.last_seen.elapsed() > ttl
    }
}

/// EoE ARP 缓存
///
/// 维护 IP -> MAC 的映射关系，支持：
/// - 静态手动添加
/// - 通过 EoE 发送 ARP 请求动态解析
/// - 从接收帧中学习
pub struct ArpCache {
    /// IP -> ARP 条目映射
    entries: HashMap<u32, ArpEntry>,
    /// 动态条目生存时间
    ttl: Duration,
}

impl ArpCache {
    /// 创建新的 ARP 缓存，默认 TTL 300 秒
    pub fn new() -> Self {
        Self {
            entries: HashMap::new(),
            ttl: Duration::from_secs(300),
        }
    }

    /// 设置动态条目 TTL
    pub fn set_ttl(&mut self, ttl: Duration) {
        self.ttl = ttl;
    }

    /// 手动添加静态 ARP 条目
    pub fn add_static(&mut self, ip: u32, mac: [u8; 6]) {
        self.entries.insert(ip, ArpEntry {
            ip, mac,
            last_seen: Instant::now(),
            dynamic: false,
        });
    }

    /// 查找 IP 对应的 MAC，自动过滤超时的动态条目
    pub fn lookup(&self, ip: u32) -> Option<[u8; 6]> {
        self.entries.get(&ip).and_then(|e| {
            if e.dynamic && e.is_expired(self.ttl) {
                None
            } else {
                Some(e.mac)
            }
        })
    }

    /// 从接收到的以太网帧中学习 ARP 映射（被动学习）
    ///
    /// 若帧为 ARP 回复（操作码 2），则提取发送方 IP 和 MAC 存入缓存。
    pub fn learn_from_frame(&mut self, frame: &[u8]) {
        if frame.len() < 42 { return; }
        // 检查 EtherType = 0x0806 (ARP)
        if frame[12] != 0x08 || frame[13] != 0x06 { return; }
        // ARP 操作码 (偏移 20-21)
        let opcode = u16::from_be_bytes([frame[20], frame[21]]);
        if opcode != 2 { return; } // 仅处理 ARP 回复
        // 发送方 MAC (偏移 22-27)
        let mut mac = [0u8; 6];
        mac.copy_from_slice(&frame[22..28]);
        // 发送方 IP (偏移 28-31)
        let ip = u32::from_be_bytes([frame[28], frame[29], frame[30], frame[31]]);
        self.entries.insert(ip, ArpEntry {
            ip, mac,
            last_seen: Instant::now(),
            dynamic: true,
        });
    }

    /// 通过 EoE 发送 ARP 请求并等待回应，结果加入缓存
    ///
    /// 广播 ARP 请求 (目标 MAC = FF:FF:FF:FF:FF:FF)，
    /// 等待目标 IP 的拥有者回应其 MAC 地址。
    pub fn resolve(
        &mut self,
        master_index: u16,
        slave_index: u16,
        port: u8,
        src_mac: &[u8; 6],
        src_ip: u32,
        target_ip: u32,
        timeout_us: i32,
    ) -> Result<Option<[u8; 6]>> {
        // 先查缓存（避免重复请求）
        if let Some(mac) = self.lookup(target_ip) {
            return Ok(Some(mac));
        }

        // 构建 ARP 请求帧
        let arp_frame = build_arp_request(src_mac, src_ip, target_ip);
        let broadcast_mac = [0xFF; 6];
        let frame = build_ethernet_frame(&broadcast_mac, src_mac, 0x0806, &arp_frame);

        // 发送 ARP 请求
        let send_ok = unsafe {
            ffi::EOESendFrame(master_index, slave_index, port,
                              frame.as_ptr(), frame.len() as c_int, timeout_us)
        };
        if send_ok == 0 {
            return Err(DarraError::EoeFailed);
        }

        // 等待 ARP 回应
        let mut resp_ptr: *mut std::ffi::c_void = std::ptr::null_mut();
        let mut resp_size: c_int = 0;
        let recv_ok = unsafe {
            ffi::EOEReceiveFrame(master_index, slave_index, port,
                                 &mut resp_ptr, &mut resp_size, timeout_us)
        };
        if recv_ok == 0 || resp_ptr.is_null() {
            if !resp_ptr.is_null() { unsafe { ffi::FreeMemory(resp_ptr) }; }
            return Ok(None);
        }

        let resp = unsafe {
            std::slice::from_raw_parts(resp_ptr as *const u8, resp_size as usize).to_vec()
        };
        unsafe { ffi::FreeMemory(resp_ptr) };

        // 从响应帧中学习
        self.learn_from_frame(&resp);

        // 再次查缓存
        Ok(self.lookup(target_ip))
    }

    /// 清除所有超时的动态条目
    pub fn purge_expired(&mut self) {
        let ttl = self.ttl;
        self.entries.retain(|_, e| !e.dynamic || !e.is_expired(ttl));
    }

    /// 删除指定 IP 的缓存条目
    pub fn remove(&mut self, ip: u32) {
        self.entries.remove(&ip);
    }

    /// 返回当前缓存条目数量
    pub fn len(&self) -> usize {
        self.entries.len()
    }

    /// 检查缓存是否为空
    pub fn is_empty(&self) -> bool {
        self.entries.is_empty()
    }
}

impl Default for ArpCache {
    fn default() -> Self {
        Self::new()
    }
}

// ===================== EoE 地址过滤器 =====================

/// 估算 FoE 传输需要的数据包数量 (纯计算, 不依赖 DLL)
///
/// - `file_size`: 文件大小 (字节)
/// - `max_data_size`: 每包最大数据量 (字节, 通常取决于邮箱大小)
pub fn foe_estimate_packet_count(file_size: u32, max_data_size: u32) -> u32 {
    if max_data_size == 0 {
        return 0;
    }
    // 向上取整: (file_size + max_data_size - 1) / max_data_size
    (file_size + max_data_size - 1) / max_data_size
}

// ===================== ARP 帧构建辅助 =====================

// ===================== EoE Ping 结果 (对齐 C# EoEPingResult) =====================

/// EoE Ping 结果
#[derive(Debug, Clone)]
pub struct EoEPingResult {
    /// 是否成功
    pub success: bool,
    /// 往返时间 (毫秒)
    pub round_trip_time_ms: f64,
    /// 目标地址
    pub target_address: String,
    /// TTL
    pub ttl: u8,
    /// 错误消息
    pub error_message: String,
}

impl std::fmt::Display for EoEPingResult {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        if self.success {
            write!(f, "来自 {} 的回复: 时间={:.2}ms TTL={}", self.target_address, self.round_trip_time_ms, self.ttl)
        } else {
            write!(f, "Ping {} 失败: {}", self.target_address, self.error_message)
        }
    }
}

// ===================== EoE 实例 (对齐 C# EoEInstance) =====================

/// EoE 实例 - 为从站提供完整的 EoE 功能
///
/// 通过 `Slave::eoe()` 获取实例。
pub struct EoEInstance {
    master_index: u16,
    slave_index: u16,
    port: u8,
    /// ARP 缓存
    pub arp_cache: ArpCache,
}

impl EoEInstance {
    /// 创建 EoE 实例
    pub(crate) fn new(master_index: u16, slave_index: u16, port: u8) -> Self {
        Self { master_index, slave_index, port, arp_cache: ArpCache::new() }
    }

    /// 主站索引
    pub fn master_index(&self) -> u16 { self.master_index }

    /// 从站索引
    pub fn slave_index(&self) -> u16 { self.slave_index }

    /// 从站是否支持 EoE 邮箱协议 (对齐 C# EoEInstance.IsSupported).
    ///
    /// 读取 SII mbx_proto bit 1 (ECT_MBXPROT_EOE = 0x02) 判断支持情况.
    /// DLL 调用失败时保守返回 true (未知能力视为支持).
    pub fn is_supported(&self) -> bool {
        let proto = unsafe { ffi::GetSlaveMailboxProto(self.master_index, self.slave_index) };
        (proto & 0x02) != 0
    }

    // ==================== IP 配置 ====================

    /// 读取 IP 地址 (u32, 网络序)
    pub fn ip(&self, timeout_ms: i32) -> Result<u32> {
        let mut ip: u32 = 0;
        let mut subnet: u32 = 0;
        let mut gateway: u32 = 0;
        let ret = unsafe {
            ffi::EOEGetIP(self.master_index, self.slave_index, self.port,
                         &mut ip, &mut subnet, &mut gateway, timeout_ms * 1000)
        };
        if ret != 0 { Ok(ip) } else { Err(DarraError::EoeFailed) }
    }

    /// 读取子网掩码 (u32, 网络序)
    pub fn subnet(&self, timeout_ms: i32) -> Result<u32> {
        let mut ip: u32 = 0;
        let mut subnet: u32 = 0;
        let mut gateway: u32 = 0;
        let ret = unsafe {
            ffi::EOEGetIP(self.master_index, self.slave_index, self.port,
                         &mut ip, &mut subnet, &mut gateway, timeout_ms * 1000)
        };
        if ret != 0 { Ok(subnet) } else { Err(DarraError::EoeFailed) }
    }

    /// 读取网关 (u32, 网络序)
    pub fn gateway(&self, timeout_ms: i32) -> Result<u32> {
        let mut ip: u32 = 0;
        let mut subnet: u32 = 0;
        let mut gateway: u32 = 0;
        let ret = unsafe {
            ffi::EOEGetIP(self.master_index, self.slave_index, self.port,
                         &mut ip, &mut subnet, &mut gateway, timeout_ms * 1000)
        };
        if ret != 0 { Ok(gateway) } else { Err(DarraError::EoeFailed) }
    }

    /// 设置 IP 配置
    pub fn set_ip(&self, ip: u32, subnet: u32, gateway: u32, timeout_ms: i32) -> Result<()> {
        let ret = unsafe {
            ffi::EOESetIP(self.master_index, self.slave_index, self.port,
                         ip, subnet, gateway, timeout_ms * 1000)
        };
        if ret != 0 { Ok(()) } else { Err(DarraError::EoeFailed) }
    }

    // ==================== MAC 配置 ====================

    /// 读取 MAC 地址
    pub fn mac(&self, timeout_ms: i32) -> Result<[u8; 6]> {
        let mut mac = [0u8; 6];
        let ret = unsafe {
            ffi::EOEGetMAC(self.master_index, self.slave_index, self.port,
                          mac.as_mut_ptr(), timeout_ms * 1000)
        };
        if ret != 0 { Ok(mac) } else { Err(DarraError::EoeFailed) }
    }

    /// 读取 MAC 地址字符串 (AA:BB:CC:DD:EE:FF)
    pub fn mac_string(&self, timeout_ms: i32) -> Result<String> {
        let mac = self.mac(timeout_ms)?;
        Ok(format!("{:02X}:{:02X}:{:02X}:{:02X}:{:02X}:{:02X}",
                   mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]))
    }

    /// 设置 MAC 地址
    pub fn set_mac(&self, mac: &[u8; 6], timeout_ms: i32) -> Result<()> {
        let ret = unsafe {
            ffi::EOESetMAC(self.master_index, self.slave_index, self.port,
                          mac.as_ptr(), timeout_ms * 1000)
        };
        if ret != 0 { Ok(()) } else { Err(DarraError::EoeFailed) }
    }

    // ==================== DNS 配置 ====================

    /// 读取 DNS 地址 (u32, 网络序)
    pub fn dns(&self, timeout_ms: i32) -> Result<u32> {
        let mut dns_ip: u32 = 0;
        let mut dns_name = vec![0i8; 33];
        let ret = unsafe {
            ffi::EOEGetDNS(self.master_index, self.slave_index, self.port,
                          &mut dns_ip, dns_name.as_mut_ptr(), timeout_ms * 1000)
        };
        if ret != 0 { Ok(dns_ip) } else { Err(DarraError::EoeFailed) }
    }

    /// 设置 DNS 配置
    pub fn set_dns(&self, dns_ip: u32, dns_name: &str, timeout_ms: i32) -> Result<()> {
        let c_name = std::ffi::CString::new(dns_name).unwrap_or_default();
        let ret = unsafe {
            ffi::EOESetDNS(self.master_index, self.slave_index, self.port,
                          dns_ip, c_name.as_ptr(), timeout_ms * 1000)
        };
        if ret != 0 { Ok(()) } else { Err(DarraError::EoeFailed) }
    }

    // ==================== 帧收发 ====================

    /// 发送以太网帧
    pub fn send_frame(&self, frame: &[u8], timeout_ms: i32) -> Result<()> {
        let ret = unsafe {
            ffi::EOESendFrame(self.master_index, self.slave_index, self.port,
                             frame.as_ptr(), frame.len() as c_int, timeout_ms * 1000)
        };
        if ret != 0 { Ok(()) } else { Err(DarraError::EoeFailed) }
    }

    /// 接收以太网帧
    pub fn receive_frame(&self, timeout_ms: i32) -> Result<Vec<u8>> {
        let mut frame_ptr: *mut std::ffi::c_void = std::ptr::null_mut();
        let mut frame_size: c_int = 0;
        let ret = unsafe {
            ffi::EOEReceiveFrame(self.master_index, self.slave_index, self.port,
                                &mut frame_ptr, &mut frame_size, timeout_ms * 1000)
        };
        if ret != 0 && !frame_ptr.is_null() && frame_size > 0 {
            let data = unsafe {
                std::slice::from_raw_parts(frame_ptr as *const u8, frame_size as usize).to_vec()
            };
            unsafe { ffi::FreeMemory(frame_ptr) };
            Ok(data)
        } else {
            Err(DarraError::EoeFailed)
        }
    }

    // ==================== 带时间戳的帧发送 ====================

    /// 发送带 DC 时间戳的以太网帧 (对应 C# SendFrameWithTimestamp)
    ///
    /// ETG.1000.6 §5.7 TimeAppended: 在帧末尾附加 4 字节时间戳
    /// (Unsigned32, DC 时间低 32 位), 用于时间同步场景。
    ///
    /// # 参数
    /// - `frame`: 以太网帧数据
    /// - `timestamp`: DC 时间戳 (纳秒), 取低 32 位附加到帧末尾
    /// - `timeout_ms`: 超时 (毫秒)
    pub fn send_frame_with_timestamp(&self, frame: &[u8], timestamp: u64, timeout_ms: i32) -> Result<()> {
        // 在帧末尾附加 4 字节时间戳 (ETG.1000.6 Table 78, Unsigned32)
        let ts32 = timestamp as u32;
        let mut frame_with_ts = Vec::with_capacity(frame.len() + 4);
        frame_with_ts.extend_from_slice(frame);
        frame_with_ts.extend_from_slice(&ts32.to_le_bytes());

        let ret = unsafe {
            ffi::EOESendFrame(
                self.master_index, self.slave_index, self.port,
                frame_with_ts.as_ptr(), frame_with_ts.len() as c_int,
                timeout_ms * 1000,
            )
        };
        if ret != 0 { Ok(()) } else { Err(DarraError::EoeFailed) }
    }

    // ==================== 地址过滤器管理 ====================

    /// 获取当前地址过滤器列表 (对应 C# GetAddressFilters)
    ///
    /// 返回当前从站配置的 MAC 过滤器列表。
    pub fn get_address_filters(&self, timeout_ms: i32) -> Result<Vec<[u8; 6]>> {
        let mut filter_count: u8 = 0;
        // 最多支持 16 个过滤器, 每个 6 字节
        let mut mac_buffer = vec![0u8; 16 * 6];
        let ret = unsafe {
            ffi::EOEGetAddressFilter(
                self.master_index, self.slave_index, self.port,
                &mut filter_count, mac_buffer.as_mut_ptr(), 16, timeout_ms * 1000,
            )
        };
        if ret == 0 {
            return Err(DarraError::EoeFailed);
        }
        let count = filter_count as usize;
        let mut filters = Vec::with_capacity(count);
        for i in 0..count {
            let mut mac = [0u8; 6];
            mac.copy_from_slice(&mac_buffer[i * 6..(i + 1) * 6]);
            filters.push(mac);
        }
        Ok(filters)
    }

    /// 批量设置地址过滤器 (对应 C# SetAddressFiltersBatch)
    ///
    /// 一次性设置多个 MAC 过滤器, 替换现有配置。
    ///
    /// # 参数
    /// - `filters`: MAC 地址列表
    /// - `timeout_ms`: 超时 (毫秒)
    pub fn set_address_filters_batch(&self, filters: &[[u8; 6]], timeout_ms: i32) -> Result<()> {
        // 直接通过 EOESetAddressFilter 设置过滤器列表 (替换现有配置)
        let mac_data: Vec<u8> = filters.iter().flat_map(|m| m.iter().copied()).collect();
        let ret = unsafe {
            ffi::EOESetAddressFilter(
                self.master_index, self.slave_index, self.port,
                filters.len() as u8, mac_data.as_ptr(), timeout_ms * 1000,
            )
        };
        if ret != 0 { Ok(()) } else { Err(DarraError::EoeFailed) }
    }

    // ==================== ARP 缓存管理 ====================

    /// 清除 ARP 缓存 (对应 C# ClearArpCache)
    pub fn clear_arp_cache(&mut self) {
        self.arp_cache = ArpCache::new();
    }

    // ==================== Ping ====================

    /// 通过 EoE 发送 Ping
    pub fn ping(&self, target_ip: u32, timeout_ms: i32) -> EoEPingResult {
        // 获取本地配置
        let ip = match self.ip(timeout_ms) {
            Ok(ip) => ip,
            Err(_) => return EoEPingResult {
                success: false, round_trip_time_ms: 0.0,
                target_address: format_ip(target_ip), ttl: 0,
                error_message: "本地网络配置无效".to_string(),
            },
        };
        let mac = match self.mac(timeout_ms) {
            Ok(mac) => mac,
            Err(_) => return EoEPingResult {
                success: false, round_trip_time_ms: 0.0,
                target_address: format_ip(target_ip), ttl: 0,
                error_message: "无法获取MAC地址".to_string(),
            },
        };

        let dst_mac = self.arp_cache.lookup(target_ip).unwrap_or([0xFF; 6]);
        match eoe_ping(self.master_index, self.slave_index, self.port,
                       &mac, &dst_mac, ip, target_ip, 1, &[0u8; 32], timeout_ms * 1000) {
            Ok(result) => EoEPingResult {
                success: result.success,
                round_trip_time_ms: result.rtt.map(|r| r.as_secs_f64() * 1000.0).unwrap_or(0.0),
                target_address: format_ip(target_ip),
                ttl: 64,
                error_message: if result.success { String::new() } else { "超时".to_string() },
            },
            Err(e) => EoEPingResult {
                success: false, round_trip_time_ms: 0.0,
                target_address: format_ip(target_ip), ttl: 0,
                error_message: format!("{:?}", e),
            },
        }
    }
}

/// 格式化 IP 地址 (u32 网络序 -> 字符串)
fn format_ip(ip: u32) -> String {
    format!("{}.{}.{}.{}",
            (ip >> 24) & 0xFF, (ip >> 16) & 0xFF, (ip >> 8) & 0xFF, ip & 0xFF)
}

// ===================== ARP 帧构建辅助 =====================

/// 构建 ARP 请求载荷（28 字节，不含以太网头）
fn build_arp_request(src_mac: &[u8; 6], src_ip: u32, target_ip: u32) -> Vec<u8> {
    let mut arp = Vec::with_capacity(28);
    // 硬件类型 = 以太网 (1)
    arp.extend_from_slice(&1u16.to_be_bytes());
    // 协议类型 = IPv4 (0x0800)
    arp.extend_from_slice(&0x0800u16.to_be_bytes());
    // 硬件地址长度 = 6
    arp.push(6);
    // 协议地址长度 = 4
    arp.push(4);
    // 操作码 = 请求 (1)
    arp.extend_from_slice(&1u16.to_be_bytes());
    // 发送方 MAC
    arp.extend_from_slice(src_mac);
    // 发送方 IP
    arp.extend_from_slice(&src_ip.to_be_bytes());
    // 目标 MAC（全零，表示未知）
    arp.extend_from_slice(&[0u8; 6]);
    // 目标 IP
    arp.extend_from_slice(&target_ip.to_be_bytes());
    arp
}

// ARP 表条目设置功能: DLL 未导出 EOESetArpEntry, 仅在 C# SDK 中可用

// ===================== 异步 API (轨道 1: std::thread, 无依赖) =====================

impl EoEInstance {
    /// 发送以太网帧 (std::thread 异步包装)
    pub fn send_frame_blocking(
        master_index: u16,
        slave_index: u16,
        port: u8,
        frame: Vec<u8>,
        timeout_ms: i32,
    ) -> std::thread::JoinHandle<Result<()>> {
        std::thread::spawn(move || {
            let eoe = EoEInstance::new(master_index, slave_index, port);
            eoe.send_frame(&frame, timeout_ms)
        })
    }

    /// 接收以太网帧 (std::thread 异步包装)
    pub fn receive_frame_blocking(
        master_index: u16,
        slave_index: u16,
        port: u8,
        timeout_ms: i32,
    ) -> std::thread::JoinHandle<Result<Vec<u8>>> {
        std::thread::spawn(move || {
            let eoe = EoEInstance::new(master_index, slave_index, port);
            eoe.receive_frame(timeout_ms)
        })
    }

    /// Ping (std::thread 异步包装)
    pub fn ping_blocking(
        master_index: u16,
        slave_index: u16,
        port: u8,
        target_ip: u32,
        timeout_ms: i32,
    ) -> std::thread::JoinHandle<EoEPingResult> {
        std::thread::spawn(move || {
            let eoe = EoEInstance::new(master_index, slave_index, port);
            eoe.ping(target_ip, timeout_ms)
        })
    }
}

// ===================== 异步接收 Hook (对齐 C# EoEInstance.FrameReceived) =====================
//
// FFI 路径: 走 [`crate::utils::ffi::dynamic_ffi`] (libloading 运行时绑定),
// 因为 EOESetReceiveHook / EOEClearReceiveHook 在不同 DLL 版本可能未导出,
// Rust 静态 extern 会 link 失败. 解析失败时方法返回 `DarraError::Other` 而不 panic.
//
// 全局回调表: 用 OnceLock + Mutex<HashMap<master_index, Arc<dyn Fn>>> 固定 trait object
// 生命周期, 防止 Box 被 drop 后 native 仍持有悬挂指针.

use std::sync::{Mutex as StdMutex, OnceLock as StdOnceLock, Arc};

/// 用户回调类型别名 (master_index, slave_index, &frame).
type EoEReceiveHook = Arc<dyn Fn(u16, u16, &[u8]) + Send + Sync + 'static>;

/// 全局回调注册表: master_index → 用户回调.
fn eoe_hook_registry() -> &'static StdMutex<HashMap<u16, EoEReceiveHook>> {
    static REG: StdOnceLock<StdMutex<HashMap<u16, EoEReceiveHook>>> = StdOnceLock::new();
    REG.get_or_init(|| StdMutex::new(HashMap::new()))
}

/// 共享 trampoline: native 回调 → 查 master 注册表 → 触发用户闭包.
unsafe extern "C" fn eoe_receive_trampoline(
    master_index: u16,
    slave: u16,
    frame_data: *const u8,
    frame_size: c_int,
) {
    if frame_data.is_null() || frame_size <= 0 {
        return;
    }
    let slice = unsafe { std::slice::from_raw_parts(frame_data, frame_size as usize) };
    let cb_opt = {
        match eoe_hook_registry().lock() {
            Ok(g) => g.get(&master_index).cloned(),
            Err(p) => p.into_inner().get(&master_index).cloned(),
        }
    };
    if let Some(cb) = cb_opt {
        cb(master_index, slave, slice);
    }
}

impl EoEInstance {
    /// 注册 EoE 异步接收回调.
    ///
    /// 内部用全局 trampoline 转发到用户闭包. 同一 `master_index` 多次调用会**覆盖**
    /// 之前的闭包 (与 C# DLL.EoE.EOESetReceiveHook 单回调语义一致).
    /// DLL 未导出 `EOESetReceiveHook` 时返回错误.
    pub fn set_receive_hook<F>(&self, callback: F) -> Result<()>
    where
        F: Fn(u16, u16, &[u8]) + Send + Sync + 'static,
    {
        let f = ffi::dynamic_ffi::ffi_gap()
            .eoe_set_receive_hook
            .ok_or_else(|| DarraError::Other(
                // 错误信息 obfstr 混淆, 反编译看不到符号/DLL 名明文
                obfstr::obfstr!("EOESetReceiveHook 未在 Darra.Core.dll 中导出").to_string()
            ))?;
        // 写入全局注册表 (后写入再调 native, 防止 native 在写入前已触发).
        match eoe_hook_registry().lock() {
            Ok(mut g) => { g.insert(self.master_index, Arc::new(callback)); }
            Err(p) => { p.into_inner().insert(self.master_index, Arc::new(callback)); }
        }
        let ok = unsafe { f(self.master_index, Some(eoe_receive_trampoline)) };
        if ok == 0 {
            // native 拒绝, 回滚注册表.
            if let Ok(mut g) = eoe_hook_registry().lock() {
                g.remove(&self.master_index);
            }
            return Err(DarraError::Other(
                obfstr::obfstr!("EOESetReceiveHook 返回 false (DLL 拒绝注册)").to_string()
            ));
        }
        Ok(())
    }

    /// 清除 EoE 异步接收回调.
    pub fn clear_receive_hook(&self) -> Result<()> {
        let f = ffi::dynamic_ffi::ffi_gap()
            .eoe_clear_receive_hook
            .ok_or_else(|| DarraError::Other(
                obfstr::obfstr!("EOEClearReceiveHook 未在 Darra.Core.dll 中导出").to_string()
            ))?;
        let _ok = unsafe { f(self.master_index) };
        if let Ok(mut g) = eoe_hook_registry().lock() {
            g.remove(&self.master_index);
        }
        Ok(())
    }
}

// ===================== 异步 API (轨道 2: tokio, feature 门控) =====================

#[cfg(feature = "async-tokio")]
impl EoEInstance {
    /// 发送帧 (tokio async)
    pub async fn send_frame_async(&self, frame: Vec<u8>, timeout_ms: i32) -> Result<()> {
        let master = self.master_index;
        let slave = self.slave_index;
        let port = self.port;
        tokio::task::spawn_blocking(move || {
            let eoe = EoEInstance::new(master, slave, port);
            eoe.send_frame(&frame, timeout_ms)
        })
        .await
        .map_err(|e| DarraError::Other(format!("tokio join error: {}", e)))?
    }

    /// 接收帧 (tokio async)
    pub async fn receive_frame_async(&self, timeout_ms: i32) -> Result<Vec<u8>> {
        let master = self.master_index;
        let slave = self.slave_index;
        let port = self.port;
        tokio::task::spawn_blocking(move || {
            let eoe = EoEInstance::new(master, slave, port);
            eoe.receive_frame(timeout_ms)
        })
        .await
        .map_err(|e| DarraError::Other(format!("tokio join error: {}", e)))?
    }

    /// Ping (tokio async)
    pub async fn ping_async(&self, target_ip: u32, timeout_ms: i32) -> EoEPingResult {
        let master = self.master_index;
        let slave = self.slave_index;
        let port = self.port;
        match tokio::task::spawn_blocking(move || {
            let eoe = EoEInstance::new(master, slave, port);
            eoe.ping(target_ip, timeout_ms)
        })
        .await
        {
            Ok(r) => r,
            Err(e) => EoEPingResult {
                success: false,
                round_trip_time_ms: 0.0,
                target_address: format_ip(target_ip),
                ttl: 0,
                error_message: format!("tokio join error: {}", e),
            },
        }
    }
}

// ===================== IMailboxProtocol trait impl (对齐 C# EoEInstance) =====================

impl crate::abstractions::MailboxProtocol for EoEInstance {
    fn protocol_type(&self) -> u8 { 0x02 }
    fn protocol_name(&self) -> &'static str { "EoE" }

    fn is_supported(&self) -> bool {
        EoEInstance::is_supported(self)
    }

    fn statistics(&self) -> crate::abstractions::MailboxStatistics {
        let mut stats = ffi::EcMbxStatsC::default();
        let rc = unsafe {
            ffi::mbx_get_stats_by_master(
                self.master_index, self.slave_index, 0x02, &mut stats,
            )
        };
        if rc == 1 {
            stats.into()
        } else {
            crate::abstractions::MailboxStatistics::empty()
        }
    }

    fn reset_statistics(&self) {
        unsafe {
            ffi::mbx_reset_stats_by_master(self.master_index, self.slave_index, 0x02);
        }
    }
}
