//! VoE (Vendor over EtherCAT) 高级封装
//!
//! 提供 VoEInstance 和 VoEResponse 结构体，封装厂商自定义数据传输。
//! 支持标准发送/接收、原始帧操作、帧构建/解析。
//!
//! 基础 VoE 发送/接收已在 `slave.rs` 中实现,
//! 本模块提供更高级的 VoEInstance 接口。
//!
//! # 异步使用 (对齐 C# VoEInstance.SendAsync / ReceiveAsync)
//!
//! 本 crate 提供**双轨**异步 API:
//!
//! ## 轨道 1: std::thread (无依赖)
//!
//! ```ignore
//! let handle = VoEInstance::send_blocking(0, 1, vendor_id, vendor_type, data, 500);
//! handle.join().unwrap()?;
//!
//! let handle = VoEInstance::receive_blocking(0, 1, 500);
//! let response = handle.join().unwrap()?;
//! ```
//!
//! ## 轨道 2: tokio async (可选 feature `async-tokio`)
//!
//! ```ignore
//! let voe = slave.voe();
//! voe.send_async(vendor_id, vendor_type, data).await?;
//! let response = voe.receive_async().await?;
//!
//! // tokio timeout 包装 (留 1.5x 余量超过 VoE 内部 timeout)
//! let result = tokio::time::timeout(
//!     std::time::Duration::from_millis(750),
//!     voe.receive_async()
//! ).await??;
//! ```

use crate::data::error::{DarraError, Result};
use crate::utils::ffi;
use std::os::raw::c_void;

/// VoE 头部大小 (VendorID 4字节 + VendorType 2字节)
pub const VOE_HEADER_SIZE: usize = 6;

/// VoE 响应数据
#[derive(Debug, Clone)]
pub struct VoEResponse {
    /// 厂商 ID
    pub vendor_id: u32,
    /// 厂商类型
    pub vendor_type: u16,
    /// 响应数据
    pub data: Vec<u8>,
}

impl VoEResponse {
    /// 格式化为十六进制字符串
    pub fn to_hex_string(&self) -> String {
        self.data.iter()
            .map(|b| format!("{:02X}", b))
            .collect::<Vec<_>>()
            .join(" ")
    }

    /// 获取数据长度
    pub fn data_length(&self) -> usize {
        self.data.len()
    }
}

impl std::fmt::Display for VoEResponse {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        write!(f, "VoE Response: VendorID=0x{:08X}, VendorType=0x{:04X}, DataLength={}",
            self.vendor_id, self.vendor_type, self.data.len())
    }
}

/// VoE 实例 - 为每个从站提供 VoE 功能
///
/// 通过 `Slave::voe_instance()` 获取实例。
pub struct VoEInstance {
    master_index: u16,
    slave_index: u16,
    /// 默认超时 (毫秒)
    pub default_timeout_ms: i32,
}

impl VoEInstance {
    /// 创建 VoE 实例 (内部使用)
    pub(crate) fn new(master_index: u16, slave_index: u16) -> Self {
        Self {
            master_index,
            slave_index,
            default_timeout_ms: 500,
        }
    }

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

    /// 发送 VoE 数据
    pub fn send(&self, vendor_id: u32, vendor_type: u16, data: &[u8]) -> Result<()> {
        self.send_with_timeout(vendor_id, vendor_type, data, self.default_timeout_ms)
    }

    /// 发送 VoE 数据 (带超时)
    pub fn send_with_timeout(&self, vendor_id: u32, vendor_type: u16, data: &[u8], timeout_ms: i32) -> Result<()> {
        let ret = unsafe {
            ffi::VOESend(
                self.master_index, self.slave_index,
                vendor_id, vendor_type,
                data.as_ptr(), data.len() as i32,
                timeout_ms * 1000, // 转换为微秒
            )
        };
        if ret != 0 { Ok(()) } else { Err(DarraError::VoeFailed) }
    }

    /// 接收 VoE 数据
    pub fn receive(&self) -> Result<VoEResponse> {
        self.receive_with_timeout(self.default_timeout_ms)
    }

    /// 接收 VoE 数据 (带超时)
    pub fn receive_with_timeout(&self, timeout_ms: i32) -> Result<VoEResponse> {
        let mut vendor_id: u32 = 0;
        let mut vendor_type: u16 = 0;
        let mut data_ptr: *mut c_void = std::ptr::null_mut();
        let mut data_size: i32 = 0;

        let ret = unsafe {
            ffi::VOEReceive(
                self.master_index, self.slave_index,
                &mut vendor_id, &mut vendor_type,
                &mut data_ptr, &mut data_size,
                timeout_ms * 1000,
            )
        };

        if ret != 0 {
            let data = if !data_ptr.is_null() && data_size > 0 {
                let mut buf = vec![0u8; data_size as usize];
                unsafe {
                    std::ptr::copy_nonoverlapping(data_ptr as *const u8, buf.as_mut_ptr(), data_size as usize);
                    ffi::FreeMemory(data_ptr);
                }
                buf
            } else {
                if !data_ptr.is_null() {
                    unsafe { ffi::FreeMemory(data_ptr) };
                }
                Vec::new()
            };

            Ok(VoEResponse { vendor_id, vendor_type, data })
        } else {
            Err(DarraError::VoeFailed)
        }
    }

    /// 发送 VoE 数据并等待响应
    pub fn send_and_receive(&self, vendor_id: u32, vendor_type: u16, data: &[u8]) -> Result<VoEResponse> {
        self.send(vendor_id, vendor_type, data)?;
        self.receive()
    }

    /// 发送 VoE 原始帧 (用户自行组织帧格式)
    pub fn send_raw(&self, frame_data: &[u8]) -> Result<()> {
        self.send_raw_with_timeout(frame_data, self.default_timeout_ms)
    }

    /// 发送 VoE 原始帧 (带超时)
    pub fn send_raw_with_timeout(&self, frame_data: &[u8], timeout_ms: i32) -> Result<()> {
        if frame_data.is_empty() {
            return Err(DarraError::InvalidParameter("帧数据不能为空".into()));
        }
        let ret = unsafe {
            ffi::VOESendRaw(
                self.master_index, self.slave_index,
                frame_data.as_ptr(), frame_data.len() as i32,
                timeout_ms * 1000,
            )
        };
        if ret != 0 { Ok(()) } else { Err(DarraError::VoeFailed) }
    }

    /// 接收 VoE 原始帧
    pub fn receive_raw(&self) -> Result<Vec<u8>> {
        self.receive_raw_with_timeout(self.default_timeout_ms)
    }

    /// 接收 VoE 原始帧 (带超时)
    pub fn receive_raw_with_timeout(&self, timeout_ms: i32) -> Result<Vec<u8>> {
        let mut frame_ptr: *mut c_void = std::ptr::null_mut();
        let mut frame_size: i32 = 0;

        let ret = unsafe {
            ffi::VOEReceiveRaw(
                self.master_index, self.slave_index,
                &mut frame_ptr, &mut frame_size,
                timeout_ms * 1000,
            )
        };

        if ret != 0 && !frame_ptr.is_null() && frame_size > 0 {
            let mut data = vec![0u8; frame_size as usize];
            unsafe {
                std::ptr::copy_nonoverlapping(frame_ptr as *const u8, data.as_mut_ptr(), frame_size as usize);
                ffi::FreeMemory(frame_ptr);
            }
            Ok(data)
        } else {
            if !frame_ptr.is_null() {
                unsafe { ffi::FreeMemory(frame_ptr) };
            }
            Err(DarraError::VoeFailed)
        }
    }

    /// 发送原始帧并等待响应
    pub fn send_raw_and_receive(&self, frame_data: &[u8]) -> Result<Vec<u8>> {
        self.send_raw(frame_data)?;
        self.receive_raw()
    }

    /// 构建标准 VoE 帧 (VoE 头 + 数据)
    pub fn build_frame(vendor_id: u32, vendor_type: u16, data: &[u8]) -> Vec<u8> {
        let mut frame = Vec::with_capacity(VOE_HEADER_SIZE + data.len());
        // VendorID (小端序)
        frame.push((vendor_id & 0xFF) as u8);
        frame.push(((vendor_id >> 8) & 0xFF) as u8);
        frame.push(((vendor_id >> 16) & 0xFF) as u8);
        frame.push(((vendor_id >> 24) & 0xFF) as u8);
        // VendorType (小端序)
        frame.push((vendor_type & 0xFF) as u8);
        frame.push(((vendor_type >> 8) & 0xFF) as u8);
        // 数据
        frame.extend_from_slice(data);
        frame
    }

    /// 解析 VoE 帧头部
    pub fn parse_frame(frame: &[u8]) -> Option<VoEResponse> {
        if frame.len() < VOE_HEADER_SIZE {
            return None;
        }
        let vendor_id = u32::from_le_bytes([frame[0], frame[1], frame[2], frame[3]]);
        let vendor_type = u16::from_le_bytes([frame[4], frame[5]]);
        let data = frame[VOE_HEADER_SIZE..].to_vec();
        Some(VoEResponse { vendor_id, vendor_type, data })
    }
}

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

impl VoEInstance {
    /// VoE 发送 (std::thread 异步包装)
    pub fn send_blocking(
        master_index: u16,
        slave_index: u16,
        vendor_id: u32,
        vendor_type: u16,
        data: Vec<u8>,
        timeout_ms: i32,
    ) -> std::thread::JoinHandle<Result<()>> {
        std::thread::spawn(move || {
            let voe = VoEInstance::new(master_index, slave_index);
            voe.send_with_timeout(vendor_id, vendor_type, &data, timeout_ms)
        })
    }

    /// VoE 接收 (std::thread 异步包装)
    pub fn receive_blocking(
        master_index: u16,
        slave_index: u16,
        timeout_ms: i32,
    ) -> std::thread::JoinHandle<Result<VoEResponse>> {
        std::thread::spawn(move || {
            let voe = VoEInstance::new(master_index, slave_index);
            voe.receive_with_timeout(timeout_ms)
        })
    }

    /// VoE 发送原始帧 (std::thread 异步包装)
    pub fn send_raw_blocking(
        master_index: u16,
        slave_index: u16,
        frame_data: Vec<u8>,
        timeout_ms: i32,
    ) -> std::thread::JoinHandle<Result<()>> {
        std::thread::spawn(move || {
            let voe = VoEInstance::new(master_index, slave_index);
            voe.send_raw_with_timeout(&frame_data, timeout_ms)
        })
    }
}

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

#[cfg(feature = "async-tokio")]
impl VoEInstance {
    /// VoE 发送 (tokio async, 使用实例默认 timeout)
    pub async fn send_async(&self, vendor_id: u32, vendor_type: u16, data: Vec<u8>) -> Result<()> {
        let master = self.master_index;
        let slave = self.slave_index;
        let timeout_ms = self.default_timeout_ms;
        tokio::task::spawn_blocking(move || {
            let voe = VoEInstance::new(master, slave);
            voe.send_with_timeout(vendor_id, vendor_type, &data, timeout_ms)
        })
        .await
        .map_err(|e| DarraError::Other(format!("tokio join error: {}", e)))?
    }

    /// VoE 接收 (tokio async, 使用实例默认 timeout)
    pub async fn receive_async(&self) -> Result<VoEResponse> {
        let master = self.master_index;
        let slave = self.slave_index;
        let timeout_ms = self.default_timeout_ms;
        tokio::task::spawn_blocking(move || {
            let voe = VoEInstance::new(master, slave);
            voe.receive_with_timeout(timeout_ms)
        })
        .await
        .map_err(|e| DarraError::Other(format!("tokio join error: {}", e)))?
    }

    /// VoE 发送原始帧 (tokio async)
    pub async fn send_raw_async(&self, frame_data: Vec<u8>) -> Result<()> {
        let master = self.master_index;
        let slave = self.slave_index;
        let timeout_ms = self.default_timeout_ms;
        tokio::task::spawn_blocking(move || {
            let voe = VoEInstance::new(master, slave);
            voe.send_raw_with_timeout(&frame_data, timeout_ms)
        })
        .await
        .map_err(|e| DarraError::Other(format!("tokio join error: {}", e)))?
    }
}

// ===================== Vendor-initiated 异步通知 (对齐 C# VoE NotificationReceived) =====================
//
// C# 侧依赖 DLL.VOEStartNotificationListener / VOERegisterNotification /
// VOEUnregisterNotification / VOEStopNotificationListener / VOEIsNotificationListening
// 5 个导出符号. Rust 通过 [`crate::utils::ffi::dynamic_ffi`] 用 libloading 运行时解析.
//
// 静态链接限制: Rust extern "C" 块对缺失符号会直接 link error, 因此这里
// 不能使用静态 extern, 必须走 dynamic_ffi 的 Option<fn> 懒加载方案.
// DLL 未导出符号时各方法返回 false, 保留无副作用.

/// Vendor-initiated VoE 通知事件参数 (对齐 C# `VoENotificationEventArgs`).
#[derive(Debug, Clone)]
pub struct VoENotificationEventArgs {
    pub slave_index: u16,
    pub vendor_id: u32,
    pub vendor_type: u16,
    pub data: Vec<u8>,
    /// 接收时间戳 (相对 UNIX_EPOCH 的微秒数)
    pub timestamp_us: u64,
}

impl VoENotificationEventArgs {
    pub fn new(slave_index: u16, vendor_id: u32, vendor_type: u16, data: Vec<u8>) -> Self {
        let ts = std::time::SystemTime::now()
            .duration_since(std::time::UNIX_EPOCH)
            .map(|d| d.as_micros() as u64)
            .unwrap_or(0);
        Self { slave_index, vendor_id, vendor_type, data, timestamp_us: ts }
    }
}

/// VoE 通知监听器 trait — 对齐 C# `event EventHandler<VoENotificationEventArgs>`.
pub trait VoENotificationListener: Send + Sync + 'static {
    fn on_notification(&self, args: &VoENotificationEventArgs);
}

impl<F> VoENotificationListener for F
where
    F: Fn(&VoENotificationEventArgs) + Send + Sync + 'static,
{
    fn on_notification(&self, args: &VoENotificationEventArgs) { self(args); }
}

impl VoEInstance {
    /// 启动 VoE 监听线程 + 注册通配订阅 (对齐 C# `StartNotificationListener`).
    ///
    /// FFI 路径: `dynamic_ffi.voe_start_notification_listener(master_index)` →
    /// `dynamic_ffi.voe_register_notification(slave, 0, 0, trampoline, NULL)`.
    /// DLL 未导出时返回 `false`, 全局订阅状态不变.
    pub fn start_notification_listener(&self) -> bool {
        let gap = ffi::dynamic_ffi::ffi_gap();
        let start = match gap.voe_start_notification_listener {
            Some(f) => f,
            None => return false,
        };
        let register = match gap.voe_register_notification {
            Some(f) => f,
            None => return false,
        };
        let started = unsafe { start(self.master_index) } != 0;
        if !started {
            return false;
        }
        // 注册通配订阅 (vendor_id=0/vendor_type=0). 用 None 作回调占位 — 待
        // 用户层接入 trampoline 时再扩展; 当前仅打通 FFI 路径, 不让 native 触发回调.
        let _idx = unsafe {
            register(self.slave_index, 0, 0, None, std::ptr::null_mut())
        };
        true
    }

    /// 停止本实例订阅 (对齐 C# `StopNotificationListener`).
    ///
    /// 当前骨架: 真实 unregister 需要保存 `_idx` 才能精准注销;
    /// 简化为不操作, 由 `stop_all_listeners()` 整体停掉.
    pub fn stop_notification_listener(&self) {
        // 实例级 unregister 需要保存 register 返回的 subscription_index.
        // 留待后续如果需要细粒度订阅, 加 instance-level Mutex<Vec<i32>> 跟踪.
    }

    /// 停止整个 master 监听线程 (对齐 C# `StopAllListeners`).
    ///
    /// FFI 路径: `dynamic_ffi.voe_stop_notification_listener()`.
    pub fn stop_all_listeners() {
        if let Some(f) = ffi::dynamic_ffi::ffi_gap().voe_stop_notification_listener {
            unsafe { let _ = f(); }
        }
    }

    /// 监听线程是否运行 (对齐 C# `IsListenerRunning`).
    ///
    /// FFI 路径: `dynamic_ffi.voe_is_notification_listening()`.
    pub fn is_listener_running() -> bool {
        match ffi::dynamic_ffi::ffi_gap().voe_is_notification_listening {
            Some(f) => {
                let v = unsafe { f() };
                v != 0
            }
            None => false,
        }
    }
}

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

impl crate::abstractions::MailboxProtocol for VoEInstance {
    // VoE 在 ECT_MBXT 中值为 0x0F (vendor-specific)
    fn protocol_type(&self) -> u8 { 0x0F }
    fn protocol_name(&self) -> &'static str { "VoE" }

    fn is_supported(&self) -> bool {
        VoEInstance::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, 0x0F, &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, 0x0F);
        }
    }
}
