//! 主站诊断信息 - 帧/错误/抖动统计, 5秒滑动窗口, 0.2秒刷新
//!
//! 通过 `master.diagnostics_info()` 访问。
//! 对应 C# MasterDiagnosticsInfo 类。

use crate::master::core::EtherCATMaster;
use crate::data::types::{RingMode, SlaveErrorCounters};
// [2026-05-08 修复] 删除本地 mini `InternalDiagnostics` mirror (字段顺序与 C 端 internal_diagnostics_t
//   完全错位, 所有读取数据都是垃圾). 改用 data::structures::InternalDiagnostics (字段顺序已验证与 C 一致).
use crate::data::structures::InternalDiagnostics;

/// 摘要数据 (C 端 ec_diagnostics_summary_t, 零拷贝指针访问)
#[repr(C)]
struct NativeSummary {
    total_errors: u32,
    error_rate_per_1000: f64,
    worst_link_quality: i16,
    worst_slave_index: u16,
    // 网口状态
    redundancy_active: i32,
    primary_port_ok: i32,
    secondary_port_ok: i32,
    primary_port_errors_window: u32,
    secondary_port_errors_window: u32,
    // 实时性能 (应用层)
    rt_frequency: u32,
    cycle_time_us: u32,
    packet_loss_percent: f64,
    avg_jitter_us: f64,
    max_jitter_us: f64,
    avg_cycle_time_us: f64,
    // 总线性能 (RT 内核层)
    bus_avg_jitter_us: f64,
    bus_max_jitter_us: f64,
    bus_clean_max_jitter_us: f64,  // 干净最大抖动 (排除SMI)
    bus_cycle_hz: u32,
    bus_roundtrip_us: f64,  // 报文往返延迟 (µs)
    smi_count: u32,         // SMI累计次数
    smi_peak_us: f64,       // SMI峰值抖动 (µs)
    // 拓扑
    topology_mode: u8,
    _reserved: u8,
    break_point_count: i16,
}

// ===================== 故障点信息 =====================

/// 故障点信息 (断线或CRC故障)
#[derive(Debug, Clone, Copy)]
pub struct BreakPointInfo {
    /// 故障从站索引 (1-based)
    pub slave_index: u16,
    /// 故障端口号 (0-3, 对应 P0-P3)
    pub port: u8,
    /// 故障类型: 0=断线, 1=CRC故障(线缆/连接器劣化)
    pub fault_type: u8,
}

impl BreakPointInfo {
    /// 是否为断线故障
    pub fn is_link_down(&self) -> bool {
        self.fault_type == 0
    }

    /// 是否为 CRC 故障 (线缆/连接器劣化)
    pub fn is_crc_fault(&self) -> bool {
        self.fault_type == 1
    }
}

impl std::fmt::Display for BreakPointInfo {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        match self.fault_type {
            0 => write!(f, "从站{} P{} 断线", self.slave_index, self.port),
            1 => write!(f, "从站{} P{} CRC故障", self.slave_index, self.port),
            _ => write!(f, "从站{} P{} 未知故障({})", self.slave_index, self.port, self.fault_type),
        }
    }
}

// ===================== PDO 丢帧统计 =====================

/// PDO 丢帧统计
#[derive(Debug, Clone, Copy, Default)]
pub struct PDOFrameLossStats {
    /// 累计丢帧数
    pub total_lost: u32,
    /// 当前连续丢帧数
    pub consecutive_lost: u32,
    /// 最大连续丢帧数
    pub max_consecutive_lost: u32,
}

// ===================== PDO 诊断 =====================

/// PDO 丢帧诊断
/// 通过 `master.diagnostics_info().pdo()` 访问
pub struct MasterPDODiagnostics<'a> {
    master: &'a EtherCATMaster,
}

impl<'a> MasterPDODiagnostics<'a> {
    /// 指定组的 PDO 丢帧统计
    pub fn frame_loss_stats(&self, group: u8) -> PDOFrameLossStats {
        if group <= 7 {
            let (total, consecutive, max_consecutive) = self.master.pdo_frame_loss_stats(group);
            PDOFrameLossStats { total_lost: total, consecutive_lost: consecutive, max_consecutive_lost: max_consecutive }
        } else {
            self.all_groups_stats()
        }
    }

    /// 所有组汇总的 PDO 丢帧统计
    pub fn all_groups_stats(&self) -> PDOFrameLossStats {
        let mut total_sum = 0u32;
        let mut consecutive_max = 0u32;
        let mut max_consecutive_max = 0u32;
        for g in 0..8u8 {
            let (total, consecutive, max_consecutive) = self.master.pdo_frame_loss_stats(g);
            total_sum += total;
            if consecutive > consecutive_max { consecutive_max = consecutive; }
            if max_consecutive > max_consecutive_max { max_consecutive_max = max_consecutive; }
        }
        PDOFrameLossStats {
            total_lost: total_sum,
            consecutive_lost: consecutive_max,
            max_consecutive_lost: max_consecutive_max,
        }
    }

    /// 累计丢帧数 (所有组合计)
    pub fn total_lost(&self) -> u32 {
        self.all_groups_stats().total_lost
    }

    /// 当前连续丢帧数 (所有组中最大值)
    pub fn consecutive_lost(&self) -> u32 {
        self.all_groups_stats().consecutive_lost
    }
}

// ===================== 诊断数据快照 =====================

/// 诊断数据快照
///
/// 包含某一时刻所有诊断指标的一致副本，避免多次读取共享内存时数据不一致。
#[derive(Debug, Clone)]
pub struct DiagnosticsSnapshot {
    /// 应用层帧频率 (Hz)
    pub frequency: i32,
    /// 累计错误数
    pub error_count: u32,
    /// 丢包率 (0.0 ~ 1.0) — TX vs RX, 5 秒滑窗
    pub packet_loss_rate: f32,
    /// 过慢帧率 (0.0 ~ 1.0) — idx 出 8 帧窗 stale, 不计丢
    pub late_frame_rate: f32,
    /// 平均抖动 (微秒)
    pub avg_jitter_us: f64,
    /// 最大抖动 (微秒)
    pub max_jitter_us: f64,
    /// 实际周期时间 (微秒)
    pub cycle_time_us: i32,
    /// 当前工作计数器
    pub wkc_actual: u16,
    /// 期望工作计数器
    pub wkc_expected: u16,
    /// 总线帧发送频率 (Hz, RT 内核层)
    pub bus_cycle_hz: u32,
    /// 总线最大抖动 (微秒, RT 内核层)
    pub bus_max_jitter_us: f64,
    /// 总线平均抖动 (微秒, RT 内核层)
    pub bus_avg_jitter_us: f64,
    /// 报文往返延迟 (微秒)
    pub bus_roundtrip_us: f64,
    /// 通讯负载 (%) — RTT/周期×100, <30% 健康 / 30-70% 中等 / >70% 须降频
    pub bus_load_percent: f64,
    /// SMI 累计次数
    pub smi_count: u32,
    /// SMI 峰值抖动 (微秒)
    pub smi_peak_us: f64,
    /// 主端口是否正常
    pub primary_port_ok: bool,
    /// 副端口是否正常
    pub secondary_port_ok: bool,
    /// 冗余是否激活
    pub redundancy_active: bool,
}

// ===================== 主站诊断信息 =====================

/// 主站诊断信息
///
/// 提供帧/错误/抖动统计, 通过 DLL 共享内存零拷贝读取。
/// 对应 C# MasterDiagnosticsInfo 类。
///
/// # 使用方式
/// ```no_run
/// let diag = master.diagnostics_info();
/// diag.set_enabled(true);
/// println!("丢包率: {:.2}%", diag.lost() * 100.0);
/// println!("每秒帧数: {}", diag.rt_cnt());
/// println!("平均抖动: {:.2}us", diag.avg_jitter_us());
/// ```
pub struct MasterDiagnosticsInfo<'a> {
    master: &'a EtherCATMaster,
}

impl<'a> MasterDiagnosticsInfo<'a> {
    /// 创建诊断信息实例 (内部使用)
    pub(crate) fn new(master: &'a EtherCATMaster) -> Self {
        Self { master }
    }

    // ===================== 诊断开关 =====================

    /// 诊断数据采集是否启用
    pub fn enabled(&self) -> bool {
        self.master.diagnostics_enabled()
    }

    /// 设置诊断数据采集开关
    pub fn set_enabled(&self, enable: bool) {
        self.master.set_diagnostics_enabled(enable);
    }

    // ===================== PDO 通信状态 (从 Summary 指针读取) =====================

    /// 获取 Summary 指针, 读取字段 (unsafe 内部使用)
    fn with_summary<T, F: FnOnce(&NativeSummary) -> T>(&self, default: T, f: F) -> T {
        let ptr = self.master.summary_pointer() as *const NativeSummary;
        if ptr.is_null() { return default; }
        unsafe { f(&*ptr) }
    }

    /// 获取 Diagnostics 指针, 读取字段 (unsafe 内部使用)
    fn with_diag<T, F: FnOnce(&InternalDiagnostics) -> T>(&self, default: T, f: F) -> T {
        let ptr = self.master.diagnostics_pointer() as *const InternalDiagnostics;
        if ptr.is_null() { return default; }
        unsafe { f(&*ptr) }
    }

    /// 丢包率 (0.0 ~ 1.0) — 最近 5 秒滑窗.
    ///
    /// 用户原话 (2026-04-27): "丢包率 = 发出 vs 接收, 过慢 (pipeline) 不算".
    /// 算法: max(0, ΣTX - ΣRX - 2 帧 pipeline) / ΣTX, 内核统一计算 (单一数据源).
    /// 对齐 C# PacketLossRate.
    pub fn packet_loss_rate(&self) -> f32 {
        unsafe { crate::utils::ffi::GetPacketLossRate(self.master.index()) }
    }

    /// 过慢帧率 (0.0 ~ 1.0) — 最近 5 秒滑窗.
    /// idx 出 8 帧窗的 stale 帧 kernel drop, 不计入丢包. 对齐 C# LateFrameRate.
    pub fn late_frame_rate(&self) -> f32 {
        unsafe { crate::utils::ffi::GetLateFrameRate(self.master.index()) }
    }


    /// 每秒帧数 (Hz), 来自摘要数据
    pub fn rt_cnt(&self) -> u32 {
        self.with_summary(0, |s| s.rt_frequency)
    }

    /// 实际周期时间 (微秒), 来自诊断指针
    pub fn cycle_time_span(&self) -> u32 {
        self.with_diag(0, |d| d.cycle_time_span)
    }

    /// 平均抖动 (微秒), 来自摘要数据
    pub fn avg_jitter_us(&self) -> f64 {
        self.with_summary(0.0, |s| s.avg_jitter_us)
    }

    /// 最大抖动 (微秒), 来自摘要数据
    pub fn max_jitter_us(&self) -> f64 {
        self.with_summary(0.0, |s| s.max_jitter_us)
    }

    /// 平均周期时间 (微秒)
    pub fn avg_cycle_time_us(&self) -> f64 {
        self.with_summary(0.0, |s| s.avg_cycle_time_us)
    }

    /// 当前工作计数器
    pub fn wkc(&self) -> u16 {
        self.with_diag(0, |d| d.wkc)
    }

    /// 期望工作计数器
    pub fn expected_wkc(&self) -> u16 {
        self.with_diag(0, |d| d.expected_wkc)
    }

    /// 累计错误数 (所有类型)
    pub fn error_cnt(&self) -> u32 {
        self.with_summary(0, |s| s.total_errors)
    }

    /// 总线帧发送频率 (Hz, RT 内核层测量)
    pub fn bus_cycle_hz(&self) -> u32 {
        self.with_summary(0, |s| s.bus_cycle_hz)
    }

    /// 总线最大抖动 (微秒, RT 内核层测量)
    pub fn bus_max_jitter_us(&self) -> f64 {
        self.with_summary(0.0, |s| s.bus_max_jitter_us)
    }

    /// 总线平均抖动 (微秒, RT 内核层测量)
    pub fn bus_avg_jitter_us(&self) -> f64 {
        self.with_summary(0.0, |s| s.bus_avg_jitter_us)
    }

    /// 报文往返延迟 (微秒, 发送→接收) - 对齐 C# BusRoundtripUs
    pub fn bus_roundtrip_us(&self) -> f64 {
        self.with_summary(0.0, |s| s.bus_roundtrip_us)
    }

    /// 通讯负载 (%) — 一个 PDO 周期内, 报文发送到接收占用的时间百分比.
    ///
    /// 计算: `bus_roundtrip_us / cycle_time_span × 100`.
    ///
    /// 含义:
    /// - <30%  健康, 链路宽裕
    /// - 30-70% 中等, 升频率/加从站需谨慎
    /// - >70%  接近极限, 必须降频或减少从站
    ///
    /// 对齐 C# BusLoadPercent.
    pub fn bus_load_percent(&self) -> f64 {
        let rtt = self.bus_roundtrip_us();
        let cycle_us = self.cycle_time_span() as f64;
        if cycle_us <= 0.0 || rtt <= 0.0 {
            return 0.0;
        }
        let pct = rtt / cycle_us * 100.0;
        if pct > 100.0 { 100.0 } else { pct }
    }

    /// 总线干净最大抖动 (微秒, 排除SMI) - 对齐 C# BusCleanMaxJitterUs
    pub fn bus_clean_max_jitter_us(&self) -> f64 {
        self.with_summary(0.0, |s| s.bus_clean_max_jitter_us)
    }

    /// SMI累计次数 - 对齐 C# SmiCount
    pub fn smi_count(&self) -> u32 {
        self.with_summary(0, |s| s.smi_count)
    }

    /// SMI峰值抖动 (微秒) - 对齐 C# SmiPeakUs
    pub fn smi_peak_us(&self) -> f64 {
        self.with_summary(0.0, |s| s.smi_peak_us)
    }

    // ===================== 网口状态 =====================

    /// 主端口是否正常 (有流量且5秒内无错误)
    pub fn primary_port_ok(&self) -> bool {
        self.with_summary(false, |s| s.primary_port_ok != 0)
    }

    /// 副端口是否正常 (有流量且5秒内无错误, 无冗余时始终 false)
    pub fn secondary_port_ok(&self) -> bool {
        self.with_summary(false, |s| s.secondary_port_ok != 0)
    }

    /// 主端口最近5秒错误数
    pub fn primary_port_errors(&self) -> u32 {
        self.with_summary(0, |s| s.primary_port_errors_window)
    }

    /// 副端口最近5秒错误数
    pub fn secondary_port_errors(&self) -> u32 {
        self.with_summary(0, |s| s.secondary_port_errors_window)
    }

    /// 冗余是否激活 (双端口均有流量)
    pub fn redundancy_active(&self) -> bool {
        self.with_summary(false, |s| s.redundancy_active != 0)
    }

    /// 冗余模式
    pub fn ring_mode(&self) -> RingMode {
        RingMode::from_value(self.master.ring_mode())
    }

    // ===================== 从站链路与断线 =====================

    /// 最差链路质量的从站索引
    pub fn worst_slave_index(&self) -> u16 {
        self.with_summary(0, |s| s.worst_slave_index)
    }

    /// 最差链路质量百分比 (0-100%)
    pub fn worst_link_quality(&self) -> i16 {
        self.with_summary(100, |s| s.worst_link_quality)
    }

    /// 拓扑模式描述
    pub fn topology_description(&self) -> &'static str {
        let mode = self.with_summary(0u8, |s| s.topology_mode);
        match mode {
            0 => "线性",
            1 => "环形",
            2 => "环+分支",
            _ => "未知",
        }
    }

    /// 获取当前故障点 (第一个故障点, 无故障返回 None)
    pub fn break_point(&self) -> Option<BreakPointInfo> {
        let results = self.master.break_points(1);
        results.first().map(|&(slave, port, fault_type)| {
            BreakPointInfo { slave_index: slave, port, fault_type }
        })
    }

    /// 获取所有故障点 (断线 + CRC 故障)
    pub fn all_break_points(&self) -> Vec<BreakPointInfo> {
        self.master.break_points(64)
            .into_iter()
            .map(|(slave, port, fault_type)| BreakPointInfo { slave_index: slave, port, fault_type })
            .collect()
    }

    // ===================== 控制 =====================

    /// 定时模式描述
    pub fn timing_mode(&self) -> &'static str {
        match self.master.timing_mode() {
            1 => "硬件定时器",
            2 => "软件定时器",
            3 => "降级",
            4 => "RT就绪",
            _ => "未知",
        }
    }

    /// DC 同步窗口阈值 (纳秒)
    pub fn sync_window_threshold(&self) -> i32 {
        self.master.sync_window_threshold()
    }

    /// 设置 DC 同步窗口阈值 (纳秒)
    pub fn set_sync_window_threshold(&self, threshold_ns: i32) {
        self.master.set_sync_window_threshold(threshold_ns);
    }

    /// 重置所有诊断统计
    pub fn reset(&self) {
        self.master.reset_diagnostics();
        for g in 0..8u8 {
            self.master.reset_pdo_frame_loss_stats(g);
        }
    }

    // ===================== 从站错误计数 =====================

    /// 读取指定从站的错误计数器 (寄存器 0x0300-0x0307)
    pub fn read_slave_error_counters(&self, slave_index: i32) -> SlaveErrorCounters {
        let mut counters = SlaveErrorCounters {
            slave_index,
            ..Default::default()
        };

        if let Some((rx_error, invalid_frame, lost_link)) =
            self.master.read_slave_port_error_counters(slave_index as u16)
        {
            counters.port0_crc_errors = rx_error[0] as u32;
            counters.port1_crc_errors = rx_error[1] as u32;
            counters.port2_crc_errors = rx_error[2] as u32;
            counters.port3_crc_errors = rx_error[3] as u32;
            counters.frame_errors = invalid_frame.iter().map(|&x| x as u32).sum();
            counters.lost_frames = lost_link.iter().map(|&x| x as u32).sum();
        }

        counters
    }

    // ===================== PDO 丢帧诊断 =====================

    /// PDO 丢帧诊断
    pub fn pdo(&self) -> MasterPDODiagnostics<'_> {
        MasterPDODiagnostics { master: self.master }
    }

    // ===================== 诊断快照 =====================

    /// 获取诊断数据的一致快照
    ///
    /// 将当前所有诊断指标复制到一个独立结构体中，避免多次读取共享内存时数据不一致。
    /// 适用于 UI 刷新、日志记录等需要原子性读取的场景。
    pub fn get_snapshot(&self) -> DiagnosticsSnapshot {
        DiagnosticsSnapshot {
            frequency: self.rt_cnt() as i32,
            error_count: self.error_cnt(),
            packet_loss_rate: self.packet_loss_rate(),
            late_frame_rate: self.late_frame_rate(),
            avg_jitter_us: self.avg_jitter_us(),
            max_jitter_us: self.max_jitter_us(),
            cycle_time_us: self.cycle_time_span() as i32,
            wkc_actual: self.wkc(),
            wkc_expected: self.expected_wkc(),
            bus_cycle_hz: self.bus_cycle_hz(),
            bus_max_jitter_us: self.bus_max_jitter_us(),
            bus_avg_jitter_us: self.bus_avg_jitter_us(),
            bus_roundtrip_us: self.bus_roundtrip_us(),
            bus_load_percent: self.bus_load_percent(),
            smi_count: self.smi_count(),
            smi_peak_us: self.smi_peak_us(),
            primary_port_ok: self.primary_port_ok(),
            secondary_port_ok: self.secondary_port_ok(),
            redundancy_active: self.redundancy_active(),
        }
    }
}

impl<'a> std::fmt::Display for MasterDiagnosticsInfo<'a> {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        write!(f, "Lost: {:.2}%, RTcnt: {}, Jitter: {:.2}us",
            self.packet_loss_rate() * 100.0, self.rt_cnt(), self.avg_jitter_us())
    }
}
