//! ETG.1510 主站诊断对象字典
//!
//! 对应 C# Master/MasterDiagnostics_ETG1510.cs
//! 提供符合 ETG.1510 规范的主站诊断对象字典读写。

use crate::utils::ffi;

/// ETG.1510 主站对象字典索引常量
pub const OBJ_DEVICE_TYPE: u16 = 0x1000;
pub const OBJ_DEVICE_NAME: u16 = 0x1008;
pub const OBJ_HW_VERSION: u16 = 0x1009;
pub const OBJ_SW_VERSION: u16 = 0x100A;
pub const OBJ_IDENTITY: u16 = 0x1018;
pub const OBJ_DETECT_MODULES: u16 = 0xF002;
pub const OBJ_MASTER_DIAG_DATA: u16 = 0xF120;
pub const OBJ_DIAG_INTERFACE_CTRL: u16 = 0xF200;

/// ETG.1510 主站对象字典管理器
///
/// 对应 C# MasterObjectDictionary (ETG.1510 规范)
pub struct MasterOdEtg1510 {
    master_index: u16,
    /// 主站 Vendor ID (ETG 分配)
    pub vendor_id: u32,
    /// 主站 Product Code
    pub product_code: u32,
    /// 序列号（按实例自增）
    pub serial_number: u32,
}

impl MasterOdEtg1510 {
    /// 创建新的 ETG.1510 OD 管理器
    pub fn new(master_index: u16, instance_id: u32) -> Self {
        Self {
            master_index,
            vendor_id: 0x00001164,
            product_code: 0x00000001,
            serial_number: instance_id,
        }
    }

    /// 获取主站 Revision Number (从 DLL 版本派生)
    pub fn revision_number(&self) -> u32 {
        let ver = crate::statics::version_info::dll_version().unwrap_or_default();
        ((ver.major as u32) << 16) | (ver.minor as u32)
    }

    /// 读取 0x1000 - Device Type
    pub fn read_device_type(&self) -> Vec<u8> {
        // EtherCAT Master = 0x00001389
        0x00001389u32.to_le_bytes().to_vec()
    }

    /// 读取 0x1008 - Manufacturer Device Name
    pub fn read_device_name(&self) -> Vec<u8> {
        b"Darra EtherCAT Master".to_vec()
    }

    /// 读取 0x1009 - Hardware Version
    pub fn read_hw_version(&self) -> Vec<u8> {
        if cfg!(target_pointer_width = "64") {
            b"x64".to_vec()
        } else {
            b"x86".to_vec()
        }
    }

    /// 读取 0x100A - Software Version
    pub fn read_sw_version(&self) -> Vec<u8> {
        let ver = crate::statics::version_info::dll_version().unwrap_or_default();
        format!("{}.{}.{}.{}", ver.major, ver.minor, ver.patch, ver.build)
            .into_bytes()
    }

    /// 读取 0x1018 - Identity Object
    pub fn read_identity(&self, subindex: u8) -> Option<Vec<u8>> {
        match subindex {
            0 => Some(vec![4]),
            1 => Some(self.vendor_id.to_le_bytes().to_vec()),
            2 => Some(self.product_code.to_le_bytes().to_vec()),
            3 => Some(self.revision_number().to_le_bytes().to_vec()),
            4 => Some(self.serial_number.to_le_bytes().to_vec()),
            _ => None,
        }
    }

    /// ETG.1510 主站身份信息
    pub fn master_identity(&self) -> Option<crate::utils::ffi::MasterIdentity> {
        let mut identity = crate::utils::ffi::MasterIdentity::default();
        unsafe {
            if ffi::GetMasterIdentity(self.master_index, &mut identity) != 0 {
                Some(identity)
            } else {
                None
            }
        }
    }

    /// ETG.1510 主站诊断数据 (0xF120)
    pub fn master_diag_data(&self) -> Option<crate::utils::ffi::MasterDiagData> {
        let mut diag = crate::utils::ffi::MasterDiagData::default();
        unsafe {
            if ffi::GetMasterDiagData(self.master_index, &mut diag) != 0 {
                Some(diag)
            } else {
                None
            }
        }
    }

    /// 读取对象字典项
    ///
    /// 支持 ETG.1510 定义的所有对象索引范围:
    /// - 0x1000~0x1018: 主站设备信息
    /// - 0x8nnn: 从站配置数据 (slave_index = (index - 0x8000) / 0x10)
    /// - 0x9nnn: 从站信息数据
    /// - 0xAnnn: 从站诊断数据
    /// - 0xF002: 模块检测命令
    /// - 0xF120: 已配置地址列表
    /// - 0xF200: 扫描命令 / 诊断接口控制
    pub fn read_object(&self, index: u16, subindex: u8) -> Option<Vec<u8>> {
        match index {
            OBJ_DEVICE_TYPE => {
                if subindex == 0 { Some(self.read_device_type()) } else { None }
            }
            OBJ_DEVICE_NAME => {
                if subindex == 0 { Some(self.read_device_name()) } else { None }
            }
            OBJ_HW_VERSION => {
                if subindex == 0 { Some(self.read_hw_version()) } else { None }
            }
            OBJ_SW_VERSION => {
                if subindex == 0 { Some(self.read_sw_version()) } else { None }
            }
            OBJ_IDENTITY => self.read_identity(subindex),
            // 0x8nnn - 从站配置数据 (Configuration Data)
            // slave_index = (index - 0x8000) / 0x10, 子索引对应具体配置项
            0x8000..=0x8FFF => {
                self.read_slave_object(index, subindex)
            }
            // 0x9nnn - 从站信息数据 (Information Data)
            // slave_index = (index - 0x9000) / 0x10
            0x9000..=0x9FFF => {
                self.read_slave_object(index, subindex)
            }
            // 0xAnnn - 从站诊断数据 (Diagnosis Data)
            // slave_index = (index - 0xA000) / 0x10
            0xA000..=0xAFFF => {
                self.read_slave_object(index, subindex)
            }
            // 0xF002 - 模块检测命令 (Detect Modules)
            OBJ_DETECT_MODULES => {
                self.read_command_object(index, subindex)
            }
            // 0xF120 - 已配置地址列表 (Configured Address List / Master Diag Data)
            OBJ_MASTER_DIAG_DATA => {
                self.read_command_object(index, subindex)
            }
            // 0xF200 - 扫描命令 / 诊断接口控制 (Scan Command)
            OBJ_DIAG_INTERFACE_CTRL => {
                self.read_command_object(index, subindex)
            }
            _ => None,
        }
    }

    /// 读取从站范围的对象 (0x8nnn/0x9nnn/0xAnnn)
    ///
    /// 注意: DLL 未导出 ReadMasterObject, 当前返回 None。
    /// 从站诊断数据请通过 GetMasterDiagData 或从站属性获取。
    fn read_slave_object(&self, _index: u16, _subindex: u8) -> Option<Vec<u8>> {
        // DLL 未导出 ReadMasterObject, 暂不支持直接读取从站范围对象
        None
    }

    /// 读取命令/控制对象 (0xF002/0xF120/0xF200)
    ///
    /// 注意: DLL 未导出 ReadMasterObject, 当前返回 None。
    /// 诊断数据请通过 GetMasterDiagData 获取。
    fn read_command_object(&self, _index: u16, _subindex: u8) -> Option<Vec<u8>> {
        // DLL 未导出 ReadMasterObject, 暂不支持直接读取命令对象
        None
    }

    /// 获取当前支持的对象索引列表
    ///
    /// 返回所有可读取的 ETG.1510 对象字典索引。
    /// 包括固定对象 (0x1000~0x1018) 和动态从站对象 (0x8nnn/0x9nnn/0xAnnn)。
    pub fn get_supported_object_indices(&self) -> Vec<u16> {
        let mut indices = vec![
            OBJ_DEVICE_TYPE,        // 0x1000
            OBJ_DEVICE_NAME,        // 0x1008
            OBJ_HW_VERSION,         // 0x1009
            OBJ_SW_VERSION,         // 0x100A
            OBJ_IDENTITY,           // 0x1018
            OBJ_DETECT_MODULES,     // 0xF002
            OBJ_MASTER_DIAG_DATA,   // 0xF120
            OBJ_DIAG_INTERFACE_CTRL,// 0xF200
        ];

        // 动态添加从站对象索引 (每个从站占 0x10 个索引)
        // 通过尝试读取 subindex 0 来检测有效的从站对象
        for slave_idx in 0u16..64 {
            let config_index = 0x8000 + slave_idx * 0x10;
            if self.read_slave_object(config_index, 0).is_some() {
                indices.push(config_index);
                // 对应的信息和诊断索引
                indices.push(0x9000 + slave_idx * 0x10);
                indices.push(0xA000 + slave_idx * 0x10);
            } else {
                break; // 从站索引连续, 遇到无效索引即停止
            }
        }

        indices
    }

    /// 对象名称
    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",
            0xF002 => "Detect Modules Command",
            0xF120 => "Master Diag Data",
            0xF200 => "Diag Interface Control",
            _ if index >= 0x8000 && index <= 0x8FFF => "Configuration Data",
            _ if index >= 0x9000 && index <= 0x9FFF => "Information Data",
            _ if index >= 0xA000 && index <= 0xAFFF => "Diagnosis Data",
            _ => "Unknown",
        }
    }

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

// ===================== ETG.1510 从站诊断数据 =====================

/// 从站诊断数据
///
/// 对应 C# SlaveDiagData 结构体
#[derive(Debug, Clone, Default)]
pub struct SlaveDiagData {
    /// 扩展 AL 状态码
    pub al_status_extended: u16,
    /// 最后的 AL 错误码
    pub last_al_status_code: u16,
    /// 最后的 CoE/SoE 协议错误
    pub last_coe_soe_protocol_error: u32,
    /// WKC 错误计数器
    pub cyclic_wc_error_counter: u32,
    /// 是否有新的诊断消息
    pub new_diag_messages_available: bool,
    /// 是否禁用自动链路控制
    pub disable_automatic_link_control: bool,
}

/// ETG.1510 诊断接口
///
/// 对应 C# MasterDiagnostics_ETG1510
pub struct Etg1510DiagInterface {
    master_index: u16,
    /// Master OD (managed) — 提供 0x1000~0x1018 设备信息以及 ETG.1510 派生数据
    od: MasterOdEtg1510,
}

impl Etg1510DiagInterface {
    /// 创建诊断接口
    pub fn new(master_index: u16) -> Self {
        Self {
            master_index,
            od: MasterOdEtg1510::new(master_index, 0),
        }
    }

    /// 写入主站对象字典对象 (managed 实装)
    ///
    /// 路由优先级 (与 Python `MasterObjectDictionary.write_object` 对齐):
    /// 1. FFI `Diag_Etg1510Write` (DLL 端 SDO 直写) — 解析到则用 DLL
    /// 2. SDO 路由: `slave_index = 0` 走 FFI `SDOwrite_raw` (主站本地 OD)
    ///
    /// 0xF002/0xF200 等命令对象走 SDO 写入路径; 0x1000~0x1018 等只读
    /// 设备信息对象通过 `MasterOdEtg1510::read_object` 直接处理, 写入返回 false.
    pub fn write_master_object(&self, index: u16, subindex: u8, data: &[u8]) -> bool {
        // 1) 优先 FFI Diag_Etg1510Write (DLL 实装)
        if let Some(f) = ffi::dynamic_ffi::ffi_gap().diag_etg1510_write {
            let rc = unsafe {
                f(self.master_index, index, subindex,
                  data.as_ptr(), data.len() as u32)
            };
            if rc != 0 {
                return true;
            }
        }
        // 2) 只读对象拒写
        match index {
            OBJ_DEVICE_TYPE | OBJ_DEVICE_NAME | OBJ_HW_VERSION | OBJ_SW_VERSION
            | OBJ_IDENTITY => false,
            // 命令/控制对象 + 0xAnnn 诊断数据通过 SDO 路由 (slave_index = 0)
            OBJ_DETECT_MODULES | OBJ_DIAG_INTERFACE_CTRL
            | 0xA000..=0xAFFF => {
                let ok = unsafe {
                    ffi::SDOwrite_raw(
                        self.master_index, 0, index, subindex, 0,
                        data.as_ptr(), data.len() as core::ffi::c_int,
                    )
                };
                ok != 0
            }
            _ => false,
        }
    }

    /// 读取主站对象字典对象 (managed 实装)
    ///
    /// 路由优先级 (与 Python `MasterObjectDictionary.read_object` 对齐):
    /// 1. FFI `Diag_Etg1510Read` (DLL 端 SDO 直读) — 解析到则用 DLL
    /// 2. Managed 内置: 0x1000~0x1018 设备信息走 [`MasterOdEtg1510::read_object`]
    /// 3. SDO 路由: `slave_index = 0` 走 FFI `SDOread` (主站本地 OD)
    pub fn read_master_object(&self, index: u16, subindex: u8) -> Option<Vec<u8>> {
        // 1) FFI 实装 (DLL 端直读 SDO)
        if let Some(f) = ffi::dynamic_ffi::ffi_gap().diag_etg1510_read {
            let mut buf = [0u8; 4096];
            let mut out_size: u32 = 0;
            let rc = unsafe {
                f(self.master_index, index, subindex,
                  buf.as_mut_ptr(), buf.len() as u32, &mut out_size)
            };
            if rc != 0 && out_size > 0 {
                return Some(buf[..out_size as usize].to_vec());
            }
        }
        // 2) Managed 0x1000~0x1018: 直接派生
        if let Some(v) = self.od.read_object(index, subindex) {
            return Some(v);
        }
        // 3) SDO slave_index=0 路由 (从站范围对象一律由 DLL OD 承载)
        let mut size: core::ffi::c_int = 0;
        let ptr = unsafe {
            ffi::SDOread(self.master_index, 0, index, subindex, 0, &mut size)
        };
        if !ptr.is_null() && size > 0 {
            let data = unsafe {
                std::slice::from_raw_parts(ptr, size as usize).to_vec()
            };
            unsafe { ffi::FreeMemory(ptr as *mut _) };
            return Some(data);
        }
        if !ptr.is_null() {
            unsafe { ffi::FreeMemory(ptr as *mut _) };
        }
        None
    }

    /// 获取从站扩展 AL 状态码
    pub fn al_status_extended(&self, slave_index: u16) -> u16 {
        self.read_master_object(0xA000 + slave_index, 1)
            .and_then(|d| if d.len() >= 2 { Some(u16::from_le_bytes([d[0], d[1]])) } else { None })
            .unwrap_or(0)
    }

    /// 获取从站最后的 AL 错误码
    pub fn last_al_status_code(&self, slave_index: u16) -> u16 {
        self.read_master_object(0xA000 + slave_index, 2)
            .and_then(|d| if d.len() >= 2 { Some(u16::from_le_bytes([d[0], d[1]])) } else { None })
            .unwrap_or(0)
    }

    /// 获取从站最后的 CoE/SoE 协议错误
    pub fn last_coe_soe_protocol_error(&self, slave_index: u16) -> u32 {
        self.read_master_object(0xA000 + slave_index, 4)
            .and_then(|d| if d.len() >= 4 { Some(u32::from_le_bytes([d[0], d[1], d[2], d[3]])) } else { None })
            .unwrap_or(0)
    }

    /// 获取从站 WKC 错误计数器
    pub fn cyclic_wc_error_counter(&self, slave_index: u16) -> u32 {
        self.read_master_object(0xA000 + slave_index, 3)
            .and_then(|d| if d.len() >= 4 { Some(u32::from_le_bytes([d[0], d[1], d[2], d[3]])) } else { None })
            .unwrap_or(0)
    }

    /// 检查从站是否有新诊断消息
    pub fn new_diag_messages_available(&self, slave_index: u16) -> bool {
        self.read_master_object(0xA000 + slave_index, 6)
            .map(|d| d.first().copied().unwrap_or(0) != 0)
            .unwrap_or(false)
    }

    /// 获取从站自动链路控制是否已禁用
    pub fn disable_automatic_link_control(&self, slave_index: u16) -> bool {
        self.read_master_object(0xA000 + slave_index, 5)
            .map(|d| d.first().copied().unwrap_or(0) != 0)
            .unwrap_or(false)
    }
}
