//! ETG.1510 主站对象字典
//!
//! 提供符合 ETG.1510 规范的主站对象字典，用于诊断工具和 HMI 访问。
//! 通过 master.master_od() 获取实例。
//!
//! 支持的对象索引范围:
//! - 0x1000: Device Type
//! - 0x1008: Manufacturer Device Name
//! - 0x1009: Manufacturer Hardware Version
//! - 0x100A: Manufacturer Software Version
//! - 0x1018: Identity Object
//! - 0x8nnn: Configuration Data (从站配置数据)
//! - 0x9nnn: Information Data (从站信息数据)
//! - 0xAnnn: Diagnosis Data (从站诊断数据)
//! - 0xF002: Detect Modules Command
//! - 0xF120: Master Diag Data
//! - 0xF200: Diag Interface Control

use crate::utils::ffi;
use crate::master::core::EtherCATMaster;

use std::sync::atomic::{AtomicU32, Ordering};

/// 全局实例计数器，用于生成唯一序列号
static INSTANCE_COUNTER: AtomicU32 = AtomicU32::new(0);

/// 主站 Vendor ID (ETG 分配，固定值)
pub const VENDOR_ID: u32 = 0x00001164;
/// 主站 Product Code (固定值)
pub const PRODUCT_CODE: u32 = 0x00000001;

/// ETG.1510 主站对象字典
///
/// 用于诊断工具和 HMI 通过 SDO 访问主站诊断信息。
///
/// # 示例
/// ```no_run
/// let master = EtherCATMaster::new().unwrap();
/// let od = master.master_od();
/// // 读取 Device Type
/// let data = od.read_object(0x1000, 0);
/// // 获取支持的对象列表
/// let indices = od.supported_object_indices();
/// ```
pub struct MasterObjectDictionary<'a> {
    master: &'a EtherCATMaster,
    /// 实例序列号（多主站实例区分）
    serial_number: u32,
}

impl<'a> MasterObjectDictionary<'a> {
    /// 创建主站对象字典实例 (内部使用, 通过 master.master_od() 获取)
    pub(crate) fn new(master: &'a EtherCATMaster) -> Self {
        let serial_number = INSTANCE_COUNTER.fetch_add(1, Ordering::SeqCst);
        Self { master, serial_number }
    }

    /// 主站 Vendor ID
    pub fn vendor_id(&self) -> u32 {
        VENDOR_ID
    }

    /// 主站 Product Code
    pub fn product_code(&self) -> u32 {
        PRODUCT_CODE
    }

    /// 主站 Revision Number（从 DLL 版本派生: 高字=主版本, 低字=次版本）
    pub fn revision_number(&self) -> u32 {
        match EtherCATMaster::dll_version() {
            Some((major, minor, _, _)) => ((major as u32) << 16) | (minor as u32),
            None => 0,
        }
    }

    /// 主站 Serial Number（按实例自增）
    pub fn serial_number(&self) -> u32 {
        self.serial_number
    }

    /// 读取主站对象字典 (SDO Read)
    ///
    /// 根据 ETG.1510 规范实现主站诊断对象的读取。
    ///
    /// # 参数
    /// - `index`: 对象索引
    /// - `subindex`: 子索引
    ///
    /// # 返回
    /// 读取的数据，失败返回 None
    pub fn read_object(&self, index: u16, subindex: u8) -> Option<Vec<u8>> {
        match index {
            // Device Type (EtherCAT Master, 0x000011xx)
            0x1000 => {
                Some(0x000011A4u32.to_le_bytes().to_vec())
            }
            // Manufacturer Device Name
            0x1008 => {
                Some(b"Darra EtherCAT Master".to_vec())
            }
            // Manufacturer Hardware Version
            0x1009 => {
                Some(b"1.0".to_vec())
            }
            // Manufacturer Software Version
            0x100A => {
                match EtherCATMaster::dll_version() {
                    Some((major, minor, patch, build)) => {
                        let ver = format!("{}.{}.{}.{}", major, minor, patch, build);
                        Some(ver.into_bytes())
                    }
                    None => Some(b"0.0.0.0".to_vec()),
                }
            }
            // Identity Object
            0x1018 => {
                self.read_identity_object(subindex)
            }
            // Configuration Data (从站配置)
            0x8000..=0x8FFF => {
                let slave_idx = index & 0x0FFF;
                self.read_slave_config_data(slave_idx, subindex)
            }
            // Information Data (从站信息)
            0x9000..=0x9FFF => {
                let slave_idx = index & 0x0FFF;
                self.read_slave_info_data(slave_idx, subindex)
            }
            // Diagnosis Data (从站诊断)
            0xA000..=0xAFFF => {
                let slave_idx = index & 0x0FFF;
                self.read_slave_diag_data(slave_idx, subindex)
            }
            // Detect Modules Command
            0xF002 => {
                self.read_detect_modules(subindex)
            }
            // Master Diag Data
            0xF120 => {
                self.read_master_diag_data(subindex)
            }
            // Diag Interface Control
            0xF200 => {
                // 返回默认控制状态
                Some(vec![0u8; 4])
            }
            _ => None,
        }
    }

    /// 写入主站对象字典 (SDO Write)
    ///
    /// # 参数
    /// - `index`: 对象索引
    /// - `subindex`: 子索引
    /// - `data`: 要写入的数据
    ///
    /// # 返回
    /// 成功返回 true
    pub fn write_object(&self, index: u16, subindex: u8, data: &[u8]) -> bool {
        match index {
            // Detect Modules Command (可写)
            0xF002 => {
                // subindex 1 = 扫描命令
                subindex == 1 && !data.is_empty()
            }
            // Diag Interface Control (可写)
            0xF200 => {
                !data.is_empty()
            }
            // Diagnosis Data 中部分子索引可写 (重置诊断)
            0xA000..=0xAFFF => {
                // subindex 0 写入触发重置
                subindex == 0 && !data.is_empty()
            }
            // 其他对象均为只读
            _ => false,
        }
    }

    /// 获取对象名称
    pub fn object_name(&self, index: u16) -> &str {
        match index {
            0x1000 => "Device Type",
            0x1008 => "Manufacturer Device Name",
            0x1009 => "Manufacturer Hardware Version",
            0x100A => "Manufacturer Software Version",
            0x1018 => "Identity Object",
            0x8000..=0x8FFF => "Configuration Data",
            0x9000..=0x9FFF => "Information Data",
            0xA000..=0xAFFF => "Diagnosis Data",
            0xF002 => "Detect Modules Command",
            0xF120 => "Master Diag Data",
            0xF200 => "Diag Interface Control",
            _ => "Unknown",
        }
    }

    /// 获取对象的子索引数量
    pub fn subindex_count(&self, index: u16) -> u8 {
        match index {
            0x1000 | 0x1008 | 0x1009 | 0x100A => 0,
            0x1018 => 4,
            0x8000..=0x8FFF => 40,
            0x9000..=0x9FFF => 32,
            0xA000..=0xAFFF => 19,
            0xF002 => 3,
            0xF120 | 0xF200 => 16,
            _ => 0,
        }
    }

    /// 获取支持的对象索引列表
    pub fn supported_object_indices(&self) -> Vec<u16> {
        let mut indices = vec![
            0x1000, 0x1008, 0x1009, 0x100A, 0x1018,
            0xF002, 0xF120, 0xF200,
        ];

        // 添加从站相关对象 (每个从站有 3 个对象索引)
        let slave_count = self.slave_count();
        for i in 1..=slave_count {
            indices.push(0x8000 | i);  // Configuration Data
            indices.push(0x9000 | i);  // Information Data
            indices.push(0xA000 | i);  // Diagnosis Data
        }

        indices
    }

    // ===================== 内部辅助方法 =====================

    /// 获取从站数量
    fn slave_count(&self) -> u16 {
        // 通过组0的从站数量获取
        unsafe { ffi::GetGroupSlaveCount(self.master.index(), 0) }
    }

    /// 读取 Identity Object (0x1018)
    fn read_identity_object(&self, subindex: u8) -> Option<Vec<u8>> {
        match subindex {
            // 子索引数量
            0 => Some(vec![4]),
            // Vendor ID
            1 => Some(VENDOR_ID.to_le_bytes().to_vec()),
            // Product Code
            2 => Some(PRODUCT_CODE.to_le_bytes().to_vec()),
            // Revision Number
            3 => Some(self.revision_number().to_le_bytes().to_vec()),
            // Serial Number
            4 => Some(self.serial_number.to_le_bytes().to_vec()),
            _ => None,
        }
    }

    /// 读取从站配置数据 (0x8nnn)
    fn read_slave_config_data(&self, slave_idx: u16, subindex: u8) -> Option<Vec<u8>> {
        if slave_idx == 0 { return None; }

        let slave = crate::slave::Slave::new(self.master.index(), slave_idx);

        match subindex {
            // 子索引数量
            0 => Some(vec![40]),
            // 从站身份 (Vendor ID, Product Code, Revision, Serial)
            1 => {
                match slave.identity() {
                    Ok(id) => Some(id.vendor_id.to_le_bytes().to_vec()),
                    Err(_) => Some(vec![0; 4]),
                }
            }
            2 => {
                match slave.identity() {
                    Ok(id) => Some(id.product_code.to_le_bytes().to_vec()),
                    Err(_) => Some(vec![0; 4]),
                }
            }
            3 => {
                match slave.identity() {
                    Ok(id) => Some(id.revision_no.to_le_bytes().to_vec()),
                    Err(_) => Some(vec![0; 4]),
                }
            }
            4 => {
                match slave.identity() {
                    Ok(id) => Some(id.serial_no.to_le_bytes().to_vec()),
                    Err(_) => Some(vec![0; 4]),
                }
            }
            _ => Some(vec![0; 4]),
        }
    }

    /// 读取从站信息数据 (0x9nnn)
    fn read_slave_info_data(&self, slave_idx: u16, subindex: u8) -> Option<Vec<u8>> {
        if slave_idx == 0 { return None; }

        let slave = crate::slave::Slave::new(self.master.index(), slave_idx);

        match subindex {
            // 子索引数量
            0 => Some(vec![32]),
            // 从站当前状态
            1 => {
                let state = slave.state().map(|s| s as u8).unwrap_or(0);
                Some(vec![state])
            }
            // AL Status Code
            2 => Some(slave.error_code_raw().to_le_bytes().to_vec()),
            _ => Some(vec![0; 4]),
        }
    }

    /// 读取从站诊断数据 (0xAnnn)
    fn read_slave_diag_data(&self, slave_idx: u16, subindex: u8) -> Option<Vec<u8>> {
        if slave_idx == 0 { return None; }

        let slave = crate::slave::Slave::new(self.master.index(), slave_idx);

        match subindex {
            // 子索引数量
            0 => Some(vec![19]),
            // 从站当前状态
            1 => {
                let state = slave.state().map(|s| s as u8).unwrap_or(0);
                Some(vec![state])
            }
            // AL Status Code
            2 => Some(slave.error_code_raw().to_le_bytes().to_vec()),
            // 链路质量
            3 => {
                let quality = unsafe {
                    ffi::GetSlaveLinkQuality(self.master.index(), slave_idx)
                };
                Some(quality.to_le_bytes().to_vec())
            }
            _ => Some(vec![0; 4]),
        }
    }

    /// 读取 Detect Modules Command (0xF002)
    fn read_detect_modules(&self, subindex: u8) -> Option<Vec<u8>> {
        match subindex {
            // 子索引数量
            0 => Some(vec![3]),
            // 扫描命令状态 (1=就绪)
            1 => Some(vec![1]),
            // 已发现从站数量
            2 => {
                let count = self.slave_count();
                Some(count.to_le_bytes().to_vec())
            }
            // 扫描结果
            3 => Some(vec![0]),
            _ => None,
        }
    }

    /// 读取 Master Diag Data (0xF120)
    fn read_master_diag_data(&self, subindex: u8) -> Option<Vec<u8>> {
        match subindex {
            // 子索引数量
            0 => Some(vec![16]),
            _ => {
                // 尝试从 DLL 获取诊断数据
                let mut diag = ffi::MasterDiagData {
                    cyclic_lost_frames: 0,
                    acyclic_lost_frames: 0,
                    cyclic_frames_per_sec: 0,
                    acyclic_frames_per_sec: 0,
                    master_state: 0,
                };
                let ok = unsafe {
                    ffi::GetMasterDiagData(self.master.index(), &mut diag)
                };
                if ok == 0 { return Some(vec![0; 4]); }

                match subindex {
                    // 循环丢帧数
                    1 => Some(diag.cyclic_lost_frames.to_le_bytes().to_vec()),
                    // 非循环丢帧数
                    2 => Some(diag.acyclic_lost_frames.to_le_bytes().to_vec()),
                    // 每秒循环帧数
                    3 => Some(diag.cyclic_frames_per_sec.to_le_bytes().to_vec()),
                    // 每秒非循环帧数
                    4 => Some(diag.acyclic_frames_per_sec.to_le_bytes().to_vec()),
                    // 主站状态
                    5 => Some(diag.master_state.to_le_bytes().to_vec()),
                    _ => Some(vec![0; 4]),
                }
            }
        }
    }
}

impl<'a> std::fmt::Display for MasterObjectDictionary<'a> {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        write!(
            f,
            "ETG.1510 主站对象字典 (VendorID=0x{:08X}, Serial={})",
            self.vendor_id(),
            self.serial_number
        )
    }
}
