//! 从站诊断信息
//!
//! 提供 SlaveDiagnostics 和 SlaveDCDiagnostics 结构体，
//! 封装 ESC 端口错误计数器和 DC 同步诊断。

use crate::data::error::SyncWindowStatus;
use crate::utils::ffi;

/// ESC 端口错误计数器 (ETG.1000 5.3, 寄存器 0x0300-0x0313)
///
/// [2026-05-08 修复] 与 C 端 `esc_port_error_stats_t` 布局对齐 (16 字节, 4 个 u8[4] 字段).
/// 之前缺 `fwd_rx_error` (转发 RX 错误计数), 仅声明 12 字节, 长度不匹配.
#[derive(Debug, Clone)]
pub struct EscPortErrors {
    /// 各端口 RX 错误计数 [Port0..Port3]
    pub rx_error: [u8; 4],
    /// 各端口无效帧计数 [Port0..Port3]
    pub invalid_frame: [u8; 4],
    /// 各端口链路丢失计数 [Port0..Port3]
    pub lost_link: [u8; 4],
    /// 各端口转发 RX 错误计数 [Port0..Port3] (Forwarded RX Error Counter, ETG.1000 5.3)
    pub fwd_rx_error: [u8; 4],
}

impl EscPortErrors {
    /// 是否存在任何错误
    pub fn has_errors(&self) -> bool {
        self.rx_error.iter().any(|&b| b > 0)
            || self.invalid_frame.iter().any(|&b| b > 0)
            || self.lost_link.iter().any(|&b| b > 0)
            || self.fwd_rx_error.iter().any(|&b| b > 0)
    }
}

/// 从站 DC 同步诊断
pub struct SlaveDCDiagnostics {
    master_index: u16,
    slave_index: u16,
}

impl SlaveDCDiagnostics {
    /// 创建 DC 诊断实例 (内部使用)
    pub(crate) fn new(master_index: u16, slave_index: u16) -> Self {
        Self { master_index, slave_index }
    }

    /// 是否在同步窗口内
    pub fn is_in_sync(&self) -> bool {
        let mut diff_ns: i32 = 0;
        let mut max_diff_ns: i32 = 0;
        let mut min_diff_ns: i32 = 0;
        let mut in_sync: i32 = 0;
        let mut out_of_sync_count: u32 = 0;
        let ret = unsafe {
            ffi::GetSlaveSyncWindowStatus(
                self.master_index, self.slave_index,
                &mut diff_ns, &mut max_diff_ns, &mut min_diff_ns,
                &mut in_sync, &mut out_of_sync_count,
            )
        };
        ret != 0 && in_sync != 0
    }

    /// 当前时间差 (纳秒) - 0x092C System Time Difference 寄存器
    pub fn sync_time_difference(&self) -> i32 {
        let mut diff_ns: i32 = 0;
        let mut max_diff_ns: i32 = 0;
        let mut min_diff_ns: i32 = 0;
        let mut in_sync: i32 = 0;
        let mut out_of_sync_count: u32 = 0;
        let ret = unsafe {
            ffi::GetSlaveSyncWindowStatus(
                self.master_index, self.slave_index,
                &mut diff_ns, &mut max_diff_ns, &mut min_diff_ns,
                &mut in_sync, &mut out_of_sync_count,
            )
        };
        if ret != 0 { diff_ns } else { 0 }
    }

    /// 获取完整的同步窗口状态
    pub fn sync_window_status(&self) -> Option<SyncWindowStatus> {
        let mut diff_ns: i32 = 0;
        let mut max_diff_ns: i32 = 0;
        let mut min_diff_ns: i32 = 0;
        let mut in_sync: i32 = 0;
        let mut out_of_sync_count: u32 = 0;
        let ret = unsafe {
            ffi::GetSlaveSyncWindowStatus(
                self.master_index, self.slave_index,
                &mut diff_ns, &mut max_diff_ns, &mut min_diff_ns,
                &mut in_sync, &mut out_of_sync_count,
            )
        };
        if ret != 0 {
            Some(SyncWindowStatus {
                diff_ns,
                max_diff_ns,
                min_diff_ns,
                in_sync: in_sync != 0,
                out_of_sync_count,
            })
        } else {
            None
        }
    }

    /// 重置同步窗口统计
    pub fn reset_stats(&self) {
        unsafe { ffi::ResetSlaveSyncWindowStats(self.master_index, self.slave_index) };
    }
}

/// 从站诊断信息
pub struct SlaveDiagnostics {
    master_index: u16,
    slave_index: u16,
}

impl SlaveDiagnostics {
    /// 创建从站诊断实例 (内部使用)
    pub(crate) fn new(master_index: u16, slave_index: u16) -> Self {
        Self { master_index, slave_index }
    }

    /// 获取 DC 同步诊断
    pub fn dc(&self) -> SlaveDCDiagnostics {
        SlaveDCDiagnostics::new(self.master_index, self.slave_index)
    }

    /// 读取 ESC 端口错误计数器 (寄存器 0x0300-0x0313)
    ///
    /// 注意: D_1317 仅返回 3 个 u8[4] (rx_error / invalid_frame / lost_link),
    /// `fwd_rx_error` 默认 0; 若需要完整 4 字段, 走缓存 API
    /// `GetSlavePortErrorStats` (D_1319) 拿 `esc_port_error_stats_t` 结构指针.
    pub fn read_port_errors(&self) -> Option<EscPortErrors> {
        let mut rx_error = [0u8; 4];
        let mut invalid_frame = [0u8; 4];
        let mut lost_link = [0u8; 4];
        let ret = unsafe {
            ffi::ReadSlavePortErrorCounters(
                self.master_index, self.slave_index,
                rx_error.as_mut_ptr(), invalid_frame.as_mut_ptr(), lost_link.as_mut_ptr(),
            )
        };
        if ret != 0 {
            Some(EscPortErrors { rx_error, invalid_frame, lost_link, fwd_rx_error: [0; 4] })
        } else {
            None
        }
    }

    /// 重置端口错误计数器
    pub fn reset_port_errors(&self) -> bool {
        unsafe { ffi::ResetSlavePortErrorCounters(self.master_index, self.slave_index) != 0 }
    }

    /// 获取从站链路质量 (0-100%)
    pub fn link_quality(&self) -> i16 {
        unsafe { ffi::GetSlaveLinkQuality(self.master_index, self.slave_index) }
    }

    /// 冗余是否已激活 (需要双网卡配置)
    pub fn redundancy_activated(&self) -> bool {
        // 通过主站级冗余状态判断
        let mode = unsafe { ffi::GetRingMode(self.master_index) };
        mode == 1 // Dual 模式
    }

    /// 主链路是否断开 (基于端口错误检测)
    pub fn primary_link_broken(&self) -> bool {
        if let Some(errors) = self.read_port_errors() {
            // Port 0 通常为上行链路 (主链路)
            errors.lost_link[0] > 0
        } else {
            false
        }
    }

    /// 副链路是否断开 (基于端口错误检测)
    pub fn secondary_link_broken(&self) -> bool {
        if let Some(errors) = self.read_port_errors() {
            // Port 1 通常为下行链路 (副链路/冗余链路)
            errors.lost_link[1] > 0
        } else {
            false
        }
    }
}
