
use crate::data::error::{DarraError, EcState, LinkState, Result};
use crate::utils::ffi::{self, TopologyNode, MasterIdentity, MasterDiagData, SlaveIdentity};
use crate::slave::core::Slave;
use crate::statics::network::NetworkInfo;
use std::ffi::{CStr, CString};
use std::os::raw::c_int;
use std::ops::Deref;
use std::ptr::NonNull;

pub struct EtherCATMaster {

    index: u16,

    started: bool,

    owned: bool,
}

impl EtherCATMaster {

    pub fn new() -> Result<Self> {
        let index = unsafe { ffi::Initialize() };
        if index == 0xFFFF {
            return Err(DarraError::AlreadyInitialized);
        }
        Ok(Self { index, started: false, owned: true })
    }

    pub fn with_index(master_index: u16) -> Result<Self> {
        let index = unsafe { ffi::InitializeSpecificMaster(master_index) };
        if index == 0xFFFF {
            return Err(DarraError::AlreadyInitialized);
        }
        Ok(Self { index, started: false, owned: true })
    }

    pub fn from_json(json_config: &str) -> Result<Self> {

        let c_json = CString::new(json_config)
            .map_err(|_| DarraError::InvalidParameter(obfstr::obfstr!("JSON 包含空字节").into()))?;
        let index = unsafe { ffi::EcInit(c_json.as_ptr()) };
        if index == 0xFFFF {
            return Err(DarraError::ConfigLoadFailed(-1));
        }
        Ok(Self { index, started: true, owned: true })
    }

    pub fn from_json_file(path: &str) -> Result<Self> {
        let c_path = CString::new(path)
            .map_err(|_| DarraError::InvalidParameter(obfstr::obfstr!("路径包含空字节").into()))?;
        let index = unsafe { ffi::EcInitFromFile(c_path.as_ptr()) };
        if index == 0xFFFF {
            return Err(DarraError::ConfigLoadFailed(-1));
        }
        Ok(Self { index, started: true, owned: true })
    }

    pub fn builder() -> MasterBuilder {
        MasterBuilder::new()
    }

    pub fn index(&self) -> u16 {
        self.index
    }

    pub fn master_number(&self) -> u16 {
        self.index
    }

    pub fn state(&self) -> EcState {
        let raw = unsafe { ffi::GetMasterState(self.index) };
        if raw.is_null() { return EcState::None; }

        let state_raw = unsafe { *(raw as *const u16) };
        EcState::from_raw(state_raw as u8).unwrap_or(EcState::None)
    }

    pub fn obits(&self) -> u16 {
        let ptr = unsafe { ffi::GetSlave(self.index, 0) };
        if ptr.is_null() { return 0; }
        unsafe { (*(ptr as *const crate::utils::ffi::EcSlaveBlittable)).output.bits }
    }

    pub fn obytes(&self) -> u32 {
        let ptr = unsafe { ffi::GetSlave(self.index, 0) };
        if ptr.is_null() { return 0; }
        unsafe { (*(ptr as *const crate::utils::ffi::EcSlaveBlittable)).output.bytes }
    }

    pub fn ibits(&self) -> u16 {
        let ptr = unsafe { ffi::GetSlave(self.index, 0) };
        if ptr.is_null() { return 0; }
        unsafe { (*(ptr as *const crate::utils::ffi::EcSlaveBlittable)).input.bits }
    }

    pub fn ibytes(&self) -> u32 {
        let ptr = unsafe { ffi::GetSlave(self.index, 0) };
        if ptr.is_null() { return 0; }
        unsafe { (*(ptr as *const crate::utils::ffi::EcSlaveBlittable)).input.bytes }
    }

    pub fn has_dc(&self) -> bool {
        let ptr = unsafe { ffi::GetSlave(self.index, 0) };
        if ptr.is_null() { return false; }
        unsafe { (*(ptr as *const crate::utils::ffi::EcSlaveBlittable)).topo.has_dc != 0 }
    }

    pub fn link_state(&self) -> LinkState {
        self.link_status()
    }

    pub fn loop_cycle(&self) -> u32 {
        unsafe { ffi::GetTimingMode(self.index) }
    }

    pub fn set_loop_cycle(&self, time_ns: u32) {
        unsafe { ffi::SetMasterLoopCycleTime(self.index, time_ns) };
    }

    pub fn dispose(&mut self) {
        if self.owned {

            #[cfg(feature = "async-tokio")]
            crate::master::async_isolation::mark_shutdown(self.index);
            if self.started {
                unsafe { ffi::Stop(self.index) };
                self.started = false;
            }
            unsafe { ffi::Dispose(self.index) };
            self.owned = false;
            #[cfg(feature = "async-tokio")]
            crate::master::async_isolation::release_state(self.index);
        }
    }

    pub fn set_network(&self, adapter: &str, redundant: &str) -> Result<()> {
        let c_adapter = CString::new(adapter)
            .map_err(|_| DarraError::InvalidParameter(obfstr::obfstr!("适配器名称包含空字节").into()))?;
        let c_redundant = CString::new(redundant)
            .map_err(|_| DarraError::InvalidParameter(obfstr::obfstr!("冗余适配器名称包含空字节").into()))?;
        let ret = unsafe { ffi::SetNetwork(self.index, c_adapter.as_ptr(), c_redundant.as_ptr()) };
        if ret > 0 { Ok(()) } else { Err(DarraError::NetworkFailed(ret)) }
    }

    pub fn set_network_with_count(&self, adapter: &str, redundant: &str) -> Result<i32> {
        let c_adapter = CString::new(adapter)
            .map_err(|_| DarraError::InvalidParameter(obfstr::obfstr!("适配器名称包含空字节").into()))?;
        let c_redundant = CString::new(redundant)
            .map_err(|_| DarraError::InvalidParameter(obfstr::obfstr!("冗余适配器名称包含空字节").into()))?;
        let ret = unsafe { ffi::SetNetwork(self.index, c_adapter.as_ptr(), c_redundant.as_ptr()) };
        if ret > 0 { Ok(ret) } else { Err(DarraError::NetworkFailed(ret)) }
    }

    pub fn primary_network_info(&self) -> Option<NetworkInfo> {

        None
    }

    pub fn redundant_network_info(&self) -> Option<NetworkInfo> {

        None
    }

    pub fn quick_slave_count(adapter: &str) -> Result<i32> {
        let c_adapter = CString::new(adapter)
            .map_err(|_| DarraError::InvalidParameter(obfstr::obfstr!("适配器名称包含空字节").into()))?;
        let ret = unsafe { ffi::QuickSlaveCount(c_adapter.as_ptr()) };
        if ret >= 0 { Ok(ret) } else { Err(DarraError::NetworkFailed(ret)) }
    }

    pub fn quick_slave_count_redundant(primary: &str, secondary: &str) -> Result<i32> {
        let c_pri = CString::new(primary)
            .map_err(|_| DarraError::InvalidParameter(obfstr::obfstr!("主适配器名称包含空字节").into()))?;
        let _c_sec = CString::new(secondary)
            .map_err(|_| DarraError::InvalidParameter(obfstr::obfstr!("副适配器名称包含空字节").into()))?;

        let ret = unsafe { ffi::QuickSlaveCount(c_pri.as_ptr()) };
        if ret >= 0 { Ok(ret) } else { Err(DarraError::NetworkFailed(ret)) }
    }

    pub fn scan_slave_count(adapter: &str) -> Result<i32> {
        let c_adapter = CString::new(adapter)
            .map_err(|_| DarraError::InvalidParameter(obfstr::obfstr!("适配器名称包含空字节").into()))?;
        let ret = unsafe { ffi::QuickSlaveCount(c_adapter.as_ptr()) };
        if ret >= 0 { Ok(ret) } else { Err(DarraError::NetworkFailed(ret)) }
    }

    pub fn scan_slave_count_redundant(primary: &str, secondary: &str) -> Result<i32> {
        let c_pri = CString::new(primary)
            .map_err(|_| DarraError::InvalidParameter(obfstr::obfstr!("主适配器名称包含空字节").into()))?;
        let _c_sec = CString::new(secondary)
            .map_err(|_| DarraError::InvalidParameter(obfstr::obfstr!("副适配器名称包含空字节").into()))?;
        let ret = unsafe { ffi::QuickSlaveCount(c_pri.as_ptr()) };
        if ret >= 0 { Ok(ret) } else { Err(DarraError::NetworkFailed(ret)) }
    }

    pub fn read_slave_info(adapter: &str) -> Result<i32> {
        let c_adapter = CString::new(adapter)
            .map_err(|_| DarraError::InvalidParameter(obfstr::obfstr!("适配器名称包含空字节").into()))?;
        let ret = unsafe { ffi::ReadSlaveInfo(c_adapter.as_ptr()) };
        if ret >= 0 { Ok(ret) } else { Err(DarraError::NetworkFailed(ret)) }
    }

    pub fn scanned_slave_count() -> i32 {
        unsafe { ffi::GetScannedSlaveCount() }
    }

    pub fn ring_slave_count() -> i32 {
        unsafe { ffi::GetRingSlaveCount() }
    }

    const OP_DEMOTE_GRACE_WAIT_MS: u64 = 10000;

    const OP_DEMOTE_GRACE_POLL_MS: u64 = 200;

    const AL_STATUS_CODE_WATCHDOG_CFG_INVALID: u16 = 0x001F;

    fn state_of(index: u16) -> EcState {
        let raw = unsafe { ffi::GetMasterState(index) };
        if raw.is_null() {
            return EcState::None;
        }
        let state_raw = unsafe { *(raw as *const u16) };
        EcState::from_raw(state_raw as u8).unwrap_or(EcState::None)
    }

    fn probe_slave_demote_grace(index: u16, slave_count: u16) -> bool {
        let mut any_demote_candidate = false;

        for i in 1..=slave_count {

            let alc = unsafe { ffi::GetSlaveALStatusCode(index, i) };
            let slave_base_state = unsafe { ffi::GetSlaveState(index, i) } & 0x0F;

            if alc == Self::AL_STATUS_CODE_WATCHDOG_CFG_INVALID {
                return true;
            }

            if slave_base_state == EcState::SafeOp as u8 {
                any_demote_candidate = true;
            }
        }
        any_demote_candidate
    }

    fn probe_hard_state_error(index: u16, slave_count: u16) -> Option<String> {

        for i in 1..=slave_count {

            let raw_state = unsafe { ffi::GetSlaveState(index, i) };
            let alc = unsafe { ffi::GetSlaveALStatusCode(index, i) };

            let base_state = raw_state & 0x0F;
            let err_bit = (raw_state & 0x10) != 0;

            if base_state == 0 {
                return Some(format!("从站 {} 掉站/不响应 (state=0)", i));
            }

            if err_bit && alc != 0 && alc != Self::AL_STATUS_CODE_WATCHDOG_CFG_INVALID {
                return Some(format!(
                    "从站 {} 致命 AL 错误 (state=0x{:02X}, ALstatuscode=0x{:04X}, 非 0x001F-demote)",
                    i, raw_state, alc
                ));
            }
        }
        None
    }

    fn op_demote_grace_wait(index: u16, was_started: bool) -> Option<Result<()>> {

        let slave_cnt_for_grace = unsafe { ffi::GetGroupSlaveCount(index, 0) };

        if slave_cnt_for_grace == 0 {
            return None;
        }
        if Self::state_of(index) == EcState::Operational {
            return None;
        }
        if Self::probe_hard_state_error(index, slave_cnt_for_grace).is_some() {
            return None;
        }
        if !Self::probe_slave_demote_grace(index, slave_cnt_for_grace) {
            return None;
        }

        let grace_sw = std::time::Instant::now();
        let mut last_repush_ms: i64 = -1;

        while (grace_sw.elapsed().as_millis() as u64) < Self::OP_DEMOTE_GRACE_WAIT_MS {

            if Self::probe_hard_state_error(index, slave_cnt_for_grace).is_some() {

                for i in 1..=slave_cnt_for_grace {
                    let _ = unsafe { ffi::GetSlaveState(index, i) };
                }
                return Some(Err(DarraError::StateChangeFailed(EcState::Operational as u8)));
            }

            if Self::state_of(index) == EcState::Operational {

                if !was_started {
                    unsafe { ffi::Start(index) };
                }
                return Some(Ok(()));
            }

            let now_ms = grace_sw.elapsed().as_millis() as i64;
            if last_repush_ms < 0 || now_ms - last_repush_ms >= 1500 {
                last_repush_ms = now_ms;

                let from_for_to = match Self::state_of(index) {
                    EcState::None => EcState::SafeOp,
                    s => s,
                };
                let mut repush_timeout_ms =
                    crate::master::state::esm_default_timeout_ms(from_for_to, EcState::Operational)
                        .max(1000);
                if repush_timeout_ms == 1000 {
                    repush_timeout_ms = 5000;
                }

                let _ = unsafe {
                    ffi::SetStateSequence(index, EcState::Operational as c_int, repush_timeout_ms)
                };
            }

            std::thread::sleep(std::time::Duration::from_millis(Self::OP_DEMOTE_GRACE_POLL_MS));
        }

        None
    }

    pub fn set_state(&mut self, state: EcState) -> Result<()> {

        let per_step_slave_count = {
            let n = self.slave_count() as i32;
            if n <= 0 { 1 } else { n }
        };
        let transition_timeout_ms: u32 =
            (per_step_slave_count * 2000).clamp(4000, 30000) as u32;

        for attempt in 0..3 {

            let attempt_sw = std::time::Instant::now();
            let ok = unsafe {
                ffi::SetStateSequence(self.index, state as c_int, transition_timeout_ms)
            } != 0;
            let elapsed_ms = attempt_sw.elapsed().as_millis() as u32;
            if ok {
                if matches!(state, EcState::SafeOp | EcState::Operational) && !self.started {
                    unsafe { ffi::Start(self.index) };
                    self.started = true;
                }
                return Ok(());
            }

            if elapsed_ms >= transition_timeout_ms {
                return Err(DarraError::StateChangeFailed(state as u8));
            }
            if attempt < 2 {
                std::thread::sleep(std::time::Duration::from_millis(1500));
            }
        }

        if state == EcState::Operational {
            let was_started = self.started;
            match Self::op_demote_grace_wait(self.index, was_started) {
                Some(Ok(())) => {

                    self.started = true;
                    return Ok(());
                }
                Some(Err(e)) => return Err(e),
                None => {}
            }
        }

        Err(DarraError::StateChangeFailed(state as u8))
    }

    pub fn set_state_async(&self, state: EcState) -> std::thread::JoinHandle<Result<()>> {
        let mi = self.index;

        let per_step_slave_count = {
            let n = self.slave_count() as i32;
            if n <= 0 { 1 } else { n }
        };
        let transition_timeout_ms: u32 =
            (per_step_slave_count * 2000).clamp(4000, 30000) as u32;

        let was_started = self.started;
        std::thread::spawn(move || {
            let ok = unsafe {
                ffi::SetStateSequence(mi, state as c_int, transition_timeout_ms)
            } != 0;
            if !ok {

                if state == EcState::Operational {
                    match Self::op_demote_grace_wait(mi, was_started) {
                        Some(Ok(())) => return Ok(()),
                        Some(Err(e)) => return Err(e),
                        None => {}
                    }
                }
                return Err(DarraError::StateChangeFailed(state as u8));
            }
            if matches!(state, EcState::SafeOp | EcState::Operational) {
                unsafe { ffi::Start(mi) };
            }
            Ok(())
        })
    }

    pub fn link_status(&self) -> LinkState {
        LinkState::from_raw(unsafe { ffi::GetLinkStatus(self.index) })
    }

    pub fn start(&mut self) {
        unsafe { ffi::Start(self.index) };
        self.started = true;
    }

    pub fn stop(&mut self) {
        if self.started {
            unsafe { ffi::Stop(self.index) };
            self.started = false;
        }
    }

    pub fn slave(&self, slave_index: u16) -> Slave {
        Slave::new(self.index, slave_index)
    }

    pub fn slave_count(&self) -> u16 {

        let mut total: u16 = 0;
        for g in 0..8u8 {
            total += unsafe { ffi::GetGroupSlaveCount(self.index, g) };
        }
        total
    }

    pub fn slaves(&self) -> Vec<Slave> {
        let count = self.slave_count();
        (1..=count).map(|i| Slave::new(self.index, i)).collect()
    }

    pub fn load_config_json(&self, json: &str) -> Result<()> {
        let c_json = CString::new(json)
            .map_err(|_| DarraError::InvalidParameter(obfstr::obfstr!("JSON 包含空字节").into()))?;
        let ret = unsafe {
            ffi::DarraCoreInvokeText(self.index, ffi::CORE_OP_23, c_json.as_ptr(), ffi::CORE_FLAG_01, 0, 0)
        };
        if ret >= 0 { Ok(()) } else { Err(DarraError::ConfigLoadFailed(ret)) }
    }

    pub fn auto_configure_sm(&self, slave_index: u16) -> Result<i32> {
        let ret = if slave_index == 0 {
            unsafe { ffi::DarraCoreInvoke(self.index, ffi::CORE_OP_24, 0, 0, 0) }
        } else {
            unsafe { ffi::DarraCoreInvoke(self.index, ffi::CORE_OP_25, slave_index as u32, 0, 0) }
        };
        if ret >= 0 { Ok(ret) } else { Err(DarraError::Other(format!("自动配置 SM 失败 (返回码: {})", ret))) }
    }

    pub fn clear_all_startup_parameters(&self) -> Result<()> {
        let ret = unsafe { ffi::ClearStartupParameters(self.index, 0) };
        if ret >= 0 { Ok(()) } else { Err(DarraError::Other("清除启动参数失败".into())) }
    }

    pub fn apply_startup_parameters_all(&self, transition: u8, timing: u8) -> Result<i32> {
        let ret = unsafe {
            ffi::DarraCoreInvoke(self.index, ffi::CORE_OP_26, 0, 1u32 << transition, 1u32 << timing)
        };
        if ret >= 0 { Ok(ret) } else { Err(DarraError::Other(format!("执行启动参数失败 (返回码: {})", ret))) }
    }

    pub fn set_dc_cycle_time(&self, time_ns: u32) {
        unsafe { ffi::SetMasterDCCycleTime(self.index, time_ns) };
    }

    pub fn configure_dc_all(&self, sync0_ns: u32, sync1_ns: u32) -> Result<i32> {
        let ret = unsafe { ffi::ConfigureDCAll(self.index, sync0_ns, sync1_ns) };
        if ret >= 0 { Ok(ret) } else { Err(DarraError::Other("DC 配置失败".into())) }
    }

    pub fn update_propagation_delays(&self) -> Result<i32> {
        let ret = unsafe { ffi::UpdatePropagationDelays(self.index) };
        if ret >= 0 { Ok(ret) } else { Err(DarraError::Other("传播延迟更新失败".into())) }
    }

    pub fn auto_calculate_dc_shift(&self) -> Result<i32> {
        let ret = unsafe { ffi::AutoCalculateDCShift(self.index) };
        if ret >= 0 { Ok(ret) } else { Err(DarraError::Other("DC 偏移计算失败".into())) }
    }

    pub fn set_dc_auto_shift_enabled(&self, enable: bool) {
        unsafe { ffi::SetDCAutoShiftEnabled(self.index, if enable { 1 } else { 0 }) };
    }

    pub fn dc_auto_shift_enabled(&self) -> bool {
        (unsafe { ffi::GetDCAutoShiftEnabled(self.index) }) != 0
    }

    pub fn set_sync_window_threshold(&self, threshold_ns: i32) {
        unsafe { ffi::SetSyncWindowThreshold(self.index, threshold_ns) };
    }

    pub fn sync_window_threshold(&self) -> i32 {
        unsafe { ffi::GetSyncWindowThreshold(self.index) }
    }

    pub fn master_dc_time(&self) -> u64 {
        let t = unsafe { ffi::GetMasterDCTime(self.index) };
        if t < 0 { 0 } else { t as u64 }
    }

    pub fn reference_clock_slave_index(&self) -> i32 {
        unsafe { ffi::GetReferenceClockSlaveIndex(self.index) as i32 }
    }

    pub fn max_sync_difference(&self) -> i32 {
        unsafe { ffi::GetMaxSyncDifference(self.index) }
    }

    pub fn is_all_slaves_in_sync(&self) -> bool {
        (unsafe { ffi::IsAllSlavesInSync(self.index) }) != 0
    }

    pub fn enable_continuous_measurement(&self, enable: bool, interval_sec: u32) {
        unsafe { ffi::EnableContinuousMeasurement(self.index, if enable { 1 } else { 0 }, interval_sec) };
    }

    pub fn enable_drift_compensation(&self, enable: bool, threshold_ns: i32, gain: i32) {
        unsafe { ffi::EnableDriftCompensation(self.index, if enable { 1 } else { 0 }, threshold_ns, gain) };
    }

    pub fn max_propagation_delay(&self) -> i32 {
        unsafe { ffi::GetMaxPropagationDelay(self.index) }
    }

    pub fn set_cycle_time(&self, time_ns: u32) {
        unsafe { ffi::SetMasterLoopCycleTime(self.index, time_ns) };
    }

    pub fn set_cpu_affinity(&self, cpu_core: i32) -> bool {
        (unsafe { ffi::SetMasterCpuAffinity(self.index, cpu_core) }) != 0
    }

    pub fn set_pdo_thread_cpu_affinity(&self, cpu_core: i32) -> bool {
        (unsafe { ffi::SetPDOThreadCpuAffinity(self.index, cpu_core) }) != 0
    }

    pub fn pdo_thread_cpu_affinity(&self) -> i32 {
        unsafe { ffi::GetPDOThreadCpuAffinity(self.index) }
    }

    pub fn available_cpu_cores() -> i32 {
        unsafe { ffi::GetAvailableCpuCores() }
    }

    pub fn apply_realtime_optimizations() -> bool {
        (unsafe { ffi::ApplyRealtimeOptimizations() }) != 0
    }

    pub fn remove_realtime_optimizations() -> bool {
        (unsafe { ffi::RemoveRealtimeOptimizations() }) != 0
    }

    #[allow(dead_code)]
    pub(crate) fn realtime_optimizations_status() -> bool {
        (unsafe { ffi::GetRealtimeOptimizationsStatus() }) != 0
    }

    pub(crate) fn timing_mode(&self) -> u32 {
        unsafe { ffi::GetTimingMode(self.index) }
    }

    pub fn set_group_cycle_divider(&self, group: u8, divider: u8) -> bool {
        (unsafe { ffi::SetGroupCycleDivider(self.index, group, divider) }) != 0
    }

    pub fn set_group_enabled(&self, group: u8, enabled: bool) -> bool {
        (unsafe { ffi::SetGroupEnabled(self.index, group, if enabled { 1 } else { 0 }) }) != 0
    }

    pub fn get_group_enabled(&self, group: u8) -> bool {
        (unsafe { ffi::GetGroupEnabled(self.index, group) }) != 0
    }

    pub fn active_group_count(&self) -> u8 {
        unsafe { ffi::GetActiveGroupCount(self.index) }
    }

    pub fn group_expected_wkc(&self, group: u8) -> u16 {
        unsafe { ffi::GetGroupExpectedWKC(self.index, group) }
    }

    pub fn group_slave_count(&self, group: u8) -> u16 {
        unsafe { ffi::GetGroupSlaveCount(self.index, group) }
    }

    pub fn set_redundancy_mode(mode: i32) {
        unsafe { ffi::SetRedProcessdata(mode) };
    }

    pub fn redundancy_mode() -> i32 {
        unsafe { ffi::GetRedProcessdata() }
    }

    pub fn enable_redundancy(&self, enable: bool) -> Result<()> {
        if unsafe { ffi::EnableRedundancy(self.index, if enable { 1 } else { 0 }) } != 0 {
            Ok(())
        } else {
            Err(DarraError::RedundancyFailed)
        }
    }

    pub fn redundancy_status_raw(&self) -> *const std::ffi::c_void {
        unsafe { ffi::GetRedundancyStatus(self.index) }
    }

    pub fn force_redundancy_failover(&self) -> Result<()> {
        if unsafe { ffi::ForceRedundancyFailover(self.index) } != 0 {
            Ok(())
        } else {
            Err(DarraError::RedundancyFailed)
        }
    }

    pub fn check_redundancy_health(&self) -> bool {
        (unsafe { ffi::CheckRedundancyHealth(self.index) }) != 0
    }

    pub fn detailed_diagnostics_raw(&self) -> *const std::ffi::c_void {
        unsafe { ffi::GetDetailedDiagnostics(self.index) }
    }

    pub fn reset_diagnostics(&self) {
        unsafe { ffi::ResetDiagnostics(self.index) };
    }

    pub fn diagnostics_pointer(&self) -> *const std::ffi::c_void {
        unsafe { ffi::GetDiagnosticsPointer(self.index) }
    }

    pub fn summary_pointer(&self) -> *const std::ffi::c_void {
        unsafe { ffi::GetSummaryPointer(self.index) }
    }

    pub fn set_diagnostics_enabled(&self, enable: bool) {
        unsafe { ffi::SetDiagnosticsEnabled(self.index, if enable { 1 } else { 0 }) };
    }

    pub fn diagnostics_enabled(&self) -> bool {
        (unsafe { ffi::GetDiagnosticsEnabled(self.index) }) != 0
    }

    pub fn communication_stats_raw(&self) -> *const std::ffi::c_void {
        unsafe { ffi::GetCommunicationStats(self.index) }
    }

    pub fn reset_communication_stats(&self) {
        unsafe { ffi::ResetCommunicationStats(self.index) };
    }

    pub fn realtime_stats(&self) -> Option<crate::data::structures::RealtimeStats> {
        let mut stats = crate::data::structures::RealtimeStats::default();
        let rc = unsafe {
            ffi::GetRealtimeStats(
                self.index,
                &mut stats as *mut _ as *mut std::ffi::c_void,
            )
        };
        if rc != 0 { Some(stats) } else { None }
    }

    pub fn expected_wkc(&self) -> u16 {
        unsafe { ffi::GetExpectedWKC(self.index) }
    }

    pub fn set_expected_wkc(&self, expected_wkc: u16) {
        unsafe { ffi::SetExpectedWKC(self.index, expected_wkc) };
    }

    pub fn primary_wkc(&self) -> u16 {
        unsafe { ffi::GetPrimaryWKC() }
    }

    pub fn secondary_wkc(&self) -> u16 {
        unsafe { ffi::GetSecondaryWKC() }
    }

    pub fn slave_link_quality(&self, slave_index: u16) -> i16 {
        unsafe { ffi::GetSlaveLinkQuality(self.index, slave_index) }
    }

    pub fn record_pdo_cycle_start(&self) {
        unsafe { ffi::RecordPDOCycleStart(self.index) };
    }

    pub fn record_wkc(&self, wkc: u16) {
        unsafe { ffi::RecordWKC(self.index, wkc) };
    }

    pub fn update_diagnostics_snapshot(&self) {
        unsafe { ffi::UpdateDiagnosticsSnapshot(self.index) };
    }

    pub fn reset_slave_port_error_counters(&self, slave_index: u16) -> bool {
        (unsafe { ffi::ResetSlavePortErrorCounters(self.index, slave_index) }) != 0
    }

    pub fn read_slave_port_error_counters(&self, slave_index: u16) -> Option<([u8; 4], [u8; 4], [u8; 4])> {
        let mut rx_error = [0u8; 4];
        let mut invalid_frame = [0u8; 4];
        let mut lost_link = [0u8; 4];
        let ok = unsafe {
            ffi::ReadSlavePortErrorCounters(
                self.index, slave_index,
                rx_error.as_mut_ptr(), invalid_frame.as_mut_ptr(), lost_link.as_mut_ptr(),
            )
        };
        if ok != 0 { Some((rx_error, invalid_frame, lost_link)) } else { None }
    }

    pub fn read_all_slave_port_error_counters(&self) -> i32 {
        unsafe { ffi::ReadAllSlavePortErrorCounters(self.index) }
    }

    pub fn slave_port_error_stats(&self, slave_index: u16) -> *const std::ffi::c_void {
        unsafe { ffi::GetSlavePortErrorStats(self.index, slave_index) }
    }

    pub fn update_diagnostics_with_esc_errors(&self) {
        unsafe { ffi::UpdateDiagnosticsWithESCErrors(self.index) };
    }

    pub fn break_points(&self, max_results: u16) -> Vec<(u16, u8, u8)> {
        let mut slaves = vec![0u16; max_results as usize];
        let mut ports = vec![0u8; max_results as usize];
        let mut types = vec![0u8; max_results as usize];
        let count = unsafe {
            ffi::GetBreakPoints(
                self.index,
                slaves.as_mut_ptr(), ports.as_mut_ptr(), types.as_mut_ptr(),
                max_results,
            )
        };
        let n = count.max(0) as usize;
        (0..n).map(|i| (slaves[i], ports[i], types[i])).collect()
    }

    pub fn write_slave_output(&self, slave_index: u16, data: &[u8]) {
        unsafe { ffi::WriteSlaveOutput(self.index, slave_index, data.as_ptr(), data.len() as u32) };
    }

    pub fn write_slave_output_byte(&self, slave_index: u16, offset: u32, value: u8) {
        unsafe { ffi::WriteSlaveOutputByte(self.index, slave_index, offset, value) };
    }

    pub fn set_mutex_protection(&self, enable: bool) {
        unsafe { ffi::SetMutexProtection(self.index, if enable { 1 } else { 0 }) };
    }

    pub fn mutex_protection(&self) -> bool {
        (unsafe { ffi::GetMutexProtection(self.index) }) != 0
    }

    pub fn set_pdo_logging(enable: bool) {
        unsafe { ffi::SetPDOLogging(if enable { 1 } else { 0 }) };
    }

    pub fn set_mailbox_logging(enable: bool) {
        unsafe { ffi::SetMailboxLogging(if enable { 1 } else { 0 }) };
    }

    pub fn set_debug_logging(enable: bool) {
        unsafe { ffi::SetDebugLogging(if enable { 1 } else { 0 }) };
    }

    pub fn close_debug_log() {
        unsafe { ffi::CloseDebugLog() };
    }

    pub fn register_pdo_frame_loss_callback(callback: ffi::PDOFrameLossCallback) {
        unsafe { ffi::RegisterPDOFrameLossCallback(callback) };
    }

    pub fn register_preop_reconfig_callback(callback: ffi::SlavePreOpReconfigCallback) {
        unsafe { ffi::RegisterSlavePreOpReconfigCallback(callback) };
    }

    pub fn set_crash_callback(callback: ffi::CrashNotifyCallback) {
        unsafe { ffi::SetCrashCallback(callback) };
    }

    pub fn set_dc_sync_lost_callback(callback: ffi::DCSyncLostCallback) {
        unsafe { ffi::SetDCSyncLostCallback(callback) };
    }

    pub fn dll_version() -> Option<(u16, u16, u16, u16)> {
        let ptr = unsafe { ffi::GetDllVersionInfo() };
        if ptr.is_null() { return None; }

        let info = unsafe { std::ptr::read_unaligned(ptr) };
        Some((info.major, info.minor, info.patch, info.build))
    }

    pub fn lock_iomap(&self) {
        unsafe { ffi::LockIOmap(self.index) };
    }

    pub fn unlock_iomap(&self) {
        unsafe { ffi::UnlockIOmap(self.index) };
    }

    pub fn iomap_guard(&self) -> IomapGuard<'_> {
        self.lock_iomap();
        IomapGuard { master: self }
    }

    #[allow(dead_code)]
    pub(crate) fn is_wdk_available(&self) -> bool {
        (unsafe { ffi::IsWdkAvailable(self.index) }) != 0
    }

    #[allow(dead_code)]
    pub(crate) fn set_wdk_mode(&self, enable: bool) -> Result<()> {
        if unsafe { ffi::SetWdkMode(self.index, if enable { 1 } else { 0 }) } != 0 {
            Ok(())
        } else {
            Err(DarraError::WdkFailed("设置 WDK 模式失败".into()))
        }
    }

    #[allow(dead_code)]
    pub(crate) fn wdk_mode(&self) -> bool {
        (unsafe { ffi::GetWdkMode(self.index) }) != 0
    }

    #[allow(dead_code)]
    pub(crate) fn start_wdk_rt(&self, cycle_us: u32, cpu_index: u32) -> Result<()> {
        if unsafe { ffi::StartWdkRT(self.index, cycle_us, cpu_index) } != 0 {
            Ok(())
        } else {
            Err(DarraError::WdkFailed("启动 WDK RT 失败".into()))
        }
    }

    #[allow(dead_code)]
    pub(crate) fn stop_wdk_rt(&self) -> Result<()> {
        if unsafe { ffi::StopWdkRT(self.index) } != 0 {
            Ok(())
        } else {
            Err(DarraError::WdkFailed("停止 WDK RT 失败".into()))
        }
    }

    pub fn set_udp_mode(&self, enable: bool) -> Result<()> {
        if unsafe { ffi::SetUdpMode(self.index, if enable { 1 } else { 0 }) } != 0 {
            Ok(())
        } else {
            Err(DarraError::UdpFailed)
        }
    }

    pub fn udp_mode(&self) -> bool {
        (unsafe { ffi::GetUdpMode(self.index) }) != 0
    }

    pub fn is_udp_available(&self) -> bool {
        (unsafe { ffi::IsUdpAvailable(self.index) }) != 0
    }

    pub fn topology(&self) -> Vec<TopologyNode> {
        let mut buf = vec![TopologyNode {
            slave_index: 0, config_addr: 0, parent_index: 0,
            entry_port: 0, active_ports: 0, topology: 0, port_type: 0,
        }; 256];
        let count = unsafe { ffi::GetTopology(self.index, buf.as_mut_ptr(), 256) };
        if count > 0 {
            buf.truncate(count as usize);
            buf
        } else {
            Vec::new()
        }
    }

    pub fn topology_build(&self) -> Vec<TopologyNode> {
        let mut buf = vec![TopologyNode {
            slave_index: 0, config_addr: 0, parent_index: 0,
            entry_port: 0, active_ports: 0, topology: 0, port_type: 0,
        }; 256];
        let count = unsafe { ffi::TopologyBuild(self.index, buf.as_mut_ptr(), 256) };
        if count > 0 {
            buf.truncate(count as usize);
            buf
        } else {
            Vec::new()
        }
    }

    pub fn topology_get_children(&self, parent_index: u16) -> Vec<u16> {
        let mut buf = vec![0u16; 64];
        let count = unsafe { ffi::TopologyGetChildren(self.index, parent_index, buf.as_mut_ptr(), 64) };
        if count > 0 { buf.truncate(count as usize); buf }
        else { Vec::new() }
    }

    pub fn topology_get_roots(&self) -> Vec<u16> {
        let mut buf = vec![0u16; 64];
        let count = unsafe { ffi::TopologyGetRoots(self.index, buf.as_mut_ptr(), 64) };
        if count > 0 { buf.truncate(count as usize); buf }
        else { Vec::new() }
    }

    pub fn verify_license() -> Result<bool> {
        let ret = unsafe { ffi::VerifyLicense() };
        Ok(ret != 0)
    }

    pub fn is_license_valid() -> bool {
        unsafe { ffi::IsLicenseValid() != 0 }
    }

    pub fn invalidate_license() {
        unsafe { ffi::InvalidateLicense() };
    }

    pub fn serial_number() -> String {
        let ptr = unsafe { ffi::GetSerialNumber() };
        if ptr.is_null() { return String::new(); }
        unsafe { CStr::from_ptr(ptr) }.to_string_lossy().into_owned()
    }

    pub fn device_name() -> String {
        let ptr = unsafe { ffi::GetDeviceName() };
        if ptr.is_null() { return String::new(); }
        unsafe { CStr::from_ptr(ptr) }.to_string_lossy().into_owned()
    }

    pub fn user_email() -> String {
        let ptr = unsafe { ffi::GetUserEmail() };
        if ptr.is_null() { return String::new(); }
        unsafe { CStr::from_ptr(ptr) }.to_string_lossy().into_owned()
    }

    pub fn windows_product_key() -> String {
        let ptr = unsafe { ffi::GetWindowsProductKey() };
        if ptr.is_null() { return String::new(); }
        unsafe { CStr::from_ptr(ptr) }.to_string_lossy().into_owned()
    }

    pub fn driver_list() -> String {
        let ptr = unsafe { ffi::GetDriverList() };
        if ptr.is_null() { return String::new(); }
        unsafe { CStr::from_ptr(ptr) }.to_string_lossy().into_owned()
    }

    pub fn max_master_instances() -> i32 {
        unsafe { ffi::GetMaxMasterInstances() }
    }

    #[allow(dead_code)]
    pub(crate) fn dump_slave_struct_offsets() {
        unsafe { ffi::DumpSlaveStructOffsets() };
    }

    pub fn set_all_slave_watchdog(&self, timeout_ms: u32) {
        unsafe { ffi::SetAllSlaveWatchdog(self.index, timeout_ms) };
    }

    pub fn set_all_slave_pdi_watchdog(&self, timeout_ms: u32) {
        unsafe { ffi::SetAllSlavePdiWatchdog(self.index, timeout_ms) };
    }

    pub fn slave_needs_startup_reconfig(&self, slave_index: u16) -> bool {
        unsafe { ffi::GetSlaveNeedsStartupReconfig(self.index, slave_index) != 0 }
    }

    pub fn clear_slave_startup_reconfig(&self, slave_index: u16) {
        unsafe { ffi::ClearSlaveNeedsStartupReconfig(self.index, slave_index) };
    }

    pub fn pdo_frame_loss_stats(&self, group: u8) -> (u32, u32, u32) {
        let mut total: u32 = 0;
        let mut consecutive: u32 = 0;
        let mut max_consecutive: u32 = 0;
        unsafe {
            ffi::GetPDOFrameLossStats(
                self.index, group,
                &mut total, &mut consecutive, &mut max_consecutive,
            );
        }
        (total, consecutive, max_consecutive)
    }

    pub fn reset_pdo_frame_loss_stats(&self, group: u8) {
        unsafe { ffi::ResetPDOFrameLossStats(self.index, group) };
    }

    pub fn validate_timer_accuracy(expected_usec: u32, tolerance_usec: u32) -> bool {
        unsafe { ffi::DarraValidateTimerAccuracy(expected_usec, tolerance_usec) == 0 }
    }

    pub fn set_pdo_monitoring(enable: bool) {
        unsafe { ffi::EnablePDOMonitoring(if enable { 1 } else { 0 }) };
    }

    pub fn is_pdo_monitoring_enabled() -> bool {
        unsafe { ffi::IsPDOMonitoringEnabled() != 0 }
    }

    pub fn pdo_stats_raw(&self, slave_index: u16) -> Option<NonNull<std::ffi::c_void>> {
        NonNull::new(unsafe { ffi::GetPDOStats(self.index, slave_index) as *mut std::ffi::c_void })
    }

    pub fn reset_pdo_stats(&self, slave_index: u16) {
        unsafe { ffi::ResetPDOStats(self.index, slave_index) };
    }

    pub fn master_identity(&self) -> Result<MasterIdentity> {
        let mut identity = MasterIdentity {
            vendor_id: 0, product_code: 0, revision_no: 0, serial_no: 0,
            device_name: [0; 64], hw_version: [0; 32], sw_version: [0; 32],
        };
        if unsafe { ffi::GetMasterIdentity(self.index, &mut identity) } != 0 {
            Ok(identity)
        } else {
            Err(DarraError::DiagnosticsFailed)
        }
    }

    pub fn master_diag_data(&self) -> Result<MasterDiagData> {
        let mut diag = MasterDiagData {
            cyclic_lost_frames: 0, acyclic_lost_frames: 0,
            cyclic_frames_per_sec: 0, acyclic_frames_per_sec: 0,
            master_state: 0,
        };
        if unsafe { ffi::GetMasterDiagData(self.index, &mut diag) } != 0 {
            Ok(diag)
        } else {
            Err(DarraError::DiagnosticsFailed)
        }
    }

    pub fn ring_mode(&self) -> i32 {
        unsafe { ffi::GetRingMode(self.index) }
    }

    pub fn secondary_link_status(&self) -> bool {
        unsafe { ffi::GetSecondaryLinkStatus(self.index) != 0 }
    }

    pub fn validate_config(&self) -> Result<i32> {
        let ret = unsafe { ffi::ec_validate_config(self.index) };
        if ret >= 0 { Ok(ret) } else { Err(DarraError::Other(format!("配置验证失败 (返回码: {})", ret))) }
    }

    pub fn verify_all_slave_identities(
        &self,
        expected: &[SlaveIdentity],
        check_revision: bool,
        check_serial: bool,
    ) -> Result<u64> {
        let mut mismatch_mask: u64 = 0;
        let ret = unsafe {
            ffi::VerifyAllSlaveIdentities(
                self.index,
                expected.as_ptr(),
                expected.len() as u32,
                if check_revision { 1 } else { 0 },
                if check_serial { 1 } else { 0 },
                &mut mismatch_mask,
            )
        };
        if ret >= 0 {
            Ok(mismatch_mask)
        } else {
            Err(DarraError::Other(format!("从站身份验证失败 (返回码: {})", ret)))
        }
    }

    pub fn export_perf_csv(&self, filepath: &str) -> Result<()> {
        let c_path = CString::new(filepath)
            .map_err(|_| DarraError::InvalidParameter(obfstr::obfstr!("路径包含空字节").into()))?;
        let ret = unsafe { ffi::ec_perf_export_csv(self.index, c_path.as_ptr()) };
        if ret >= 0 { Ok(()) } else { Err(DarraError::Other(format!("CSV 导出失败 (返回码: {})", ret))) }
    }

    pub fn aoe_start_notification_listener(&self) -> Result<()> {
        if unsafe { ffi::AOEStartNotificationListener(self.index) } != 0 {
            Ok(())
        } else {
            Err(DarraError::AoeFailed)
        }
    }

    pub fn aoe_stop_notification_listener() -> Result<()> {
        if unsafe { ffi::AOEStopNotificationListener() } != 0 {
            Ok(())
        } else {
            Err(DarraError::AoeFailed)
        }
    }

    pub fn aoe_is_notification_listening() -> bool {
        unsafe { ffi::AOEIsNotificationListening() != 0 }
    }

    pub fn abort_scan() {
        unsafe { ffi::AbortScan() };
    }

    pub fn reset_scan_abort() {
        unsafe { ffi::ResetScanAbort() };
    }

    pub fn emergency_close_nics() {
        unsafe { ffi::EmergencyCloseNics() };
    }

    pub fn emergency_cleanup() {

        unsafe { ffi::EmergencyCloseNics() };
    }

    pub fn diagnostics_info(&self) -> crate::master::diagnostics::MasterDiagnosticsInfo<'_> {
        crate::master::diagnostics::MasterDiagnosticsInfo::new(self)
    }

    pub fn events(&self) -> crate::master::events::MasterEvents {
        crate::master::events::MasterEvents::new(self.index)
    }

    pub fn acknowledge_slave_replacement(&self, slave_num: u16) -> Result<bool> {
        if slave_num == 0 {
            return Err(DarraError::InvalidParameter("slave_num 不能为 0".into()));
        }

        Ok(unsafe { ffi::AcknowledgeSlaveReplacement(self.index, slave_num) != 0 })
    }

    pub fn slave_topology(&self) -> crate::slave::topology::SlaveTopology {
        crate::slave::topology::SlaveTopology::build(self.index)
    }

    pub fn rebuild_topology(&self) -> crate::slave::topology::SlaveTopology {
        crate::slave::topology::SlaveTopology::build(self.index)
    }

    pub fn active_instance_count() -> i32 {

        unsafe { ffi::GetMaxMasterInstances() }
    }

    pub fn max_instance_count() -> i32 {
        unsafe { ffi::GetMaxMasterInstances() }
    }

    pub fn reset_all_sync_window_stats(&self) {
        unsafe { ffi::ResetSlaveSyncWindowStats(self.index, 0) };
    }

    pub fn config(&self) -> crate::master::config::MasterConfig<'_> {
        crate::master::config::MasterConfig::new(self)
    }

    pub fn master_od(&self) -> crate::master::master_od::MasterObjectDictionary<'_> {
        crate::master::master_od::MasterObjectDictionary::new(self)
    }

    pub fn mailbox_gateway(&self) -> crate::master::mailbox_gateway::MailboxGatewayService {
        crate::master::mailbox_gateway::MailboxGatewayService::new(self.index)
    }

    pub fn execute_with_state_management<F>(
        &self,
        slave_index: u16,
        target_state: EcState,
        operation: F,
        timeout_ms: i32,
    ) -> Result<()>
    where
        F: FnOnce(&Slave) -> Result<()>,
    {
        let slave = self.slave(slave_index);
        let current_state = slave.state().unwrap_or(EcState::None);

        let target_raw = match target_state {
            EcState::Init => 0x01,
            EcState::PreOp => 0x02,
            EcState::Boot => 0x03,
            EcState::SafeOp => 0x04,
            EcState::Operational => 0x08,
            _ => return Err(DarraError::InvalidParameter(obfstr::obfstr!("无效的目标状态").into())),
        };

        if current_state != target_state {
            let ret = unsafe {
                ffi::SetSlaveStateWithTimeout(self.index, slave_index, target_raw as c_int, timeout_ms as u32)
            };
            if ret == 0 {
                return Err(DarraError::StateChangeFailed(target_raw));
            }
        }

        let result = operation(&slave);

        if current_state != target_state {
            let current_raw = match current_state {
                EcState::Init => 0x01,
                EcState::PreOp => 0x02,
                EcState::Boot => 0x03,
                EcState::SafeOp => 0x04,
                EcState::Operational => 0x08,
                _ => 0x01,
            };
            unsafe {
                ffi::SetSlaveStateWithTimeout(self.index, slave_index, current_raw as c_int, timeout_ms as u32);
            }
        }

        result
    }

    pub fn dll_checksum() -> Option<String> {

        None
    }
}

impl Drop for EtherCATMaster {
    fn drop(&mut self) {
        if self.owned {

            #[cfg(feature = "async-tokio")]
            crate::master::async_isolation::mark_shutdown(self.index);
            if self.started {
                unsafe { ffi::Stop(self.index) };
            }
            unsafe { ffi::Dispose(self.index) };
        }

        #[cfg(feature = "async-tokio")]
        crate::master::async_isolation::release_state(self.index);

        crate::master::events::clear_master_callbacks(self.index);
    }
}

impl std::fmt::Display for EtherCATMaster {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        write!(f, "EtherCATMaster[{}] {} slaves", self.index, self.slave_count())
    }
}

pub struct SlaveIterator {
    master_index: u16,
    current: u16,
    total: u16,
}

impl Iterator for SlaveIterator {
    type Item = Slave;

    fn next(&mut self) -> Option<Self::Item> {
        if self.current > self.total {
            return None;
        }
        let slave = Slave::new(self.master_index, self.current);
        self.current += 1;
        Some(slave)
    }

    fn size_hint(&self) -> (usize, Option<usize>) {

        let remaining = if self.current > self.total {
            0
        } else {
            (self.total - self.current + 1) as usize
        };
        (remaining, Some(remaining))
    }
}

impl EtherCATMaster {

    pub fn iter(&self) -> SlaveIterator {
        SlaveIterator {
            master_index: self.index,
            current: 1,
            total: self.slave_count(),
        }
    }
}

impl<'a> IntoIterator for &'a EtherCATMaster {
    type Item = Slave;
    type IntoIter = SlaveIterator;

    fn into_iter(self) -> Self::IntoIter {
        self.iter()
    }
}

pub struct IomapGuard<'a> {
    master: &'a EtherCATMaster,
}

impl<'a> Drop for IomapGuard<'a> {
    fn drop(&mut self) {
        self.master.unlock_iomap();
    }
}

pub struct SlaveGroupAccessor<'a> {
    master: &'a EtherCATMaster,
}

impl<'a> SlaveGroupAccessor<'a> {

    pub fn new(master: &'a EtherCATMaster) -> Self {
        Self { master }
    }

    pub fn count(&self) -> usize {
        self.master.active_group_count() as usize
    }

    pub fn slaves(&self, group: u8) -> Vec<Slave> {
        let group_count = unsafe { ffi::GetGroupSlaveCount(self.master.index, group) };
        if group_count == 0 {
            return Vec::new();
        }

        let total = self.master.slave_count();
        let mut result = Vec::new();
        for i in 1..=total {
            let slave = Slave::new(self.master.index, i);
            if slave.group() == group {
                result.push(slave);
            }
        }
        result
    }

    pub fn divider(&self, group: u8) -> u8 {
        unsafe { ffi::GetGroupCycleDivider(self.master.index, group) }
    }

    pub fn set_divider(&self, group: u8, div: u8) {
        if div > 0 {
            unsafe { ffi::SetGroupCycleDivider(self.master.index, group, div) };
        }
    }

    pub fn group_slave_count(&self, group: u8) -> u16 {
        unsafe { ffi::GetGroupSlaveCount(self.master.index, group) }
    }

    pub fn group_expected_wkc(&self, group: u8) -> u16 {
        unsafe { ffi::GetGroupExpectedWKC(self.master.index, group) }
    }
}

pub struct SlaveGroupIter<'a> {
    accessor: &'a SlaveGroupAccessor<'a>,
    current_group: u8,
}

impl<'a> Iterator for SlaveGroupIter<'a> {
    type Item = u8;

    fn next(&mut self) -> Option<Self::Item> {
        while self.current_group < 8 {
            let group = self.current_group;
            self.current_group += 1;
            if unsafe { ffi::GetGroupSlaveCount(self.accessor.master.index, group) } > 0 {
                return Some(group);
            }
        }
        None
    }
}

impl<'a> IntoIterator for &'a SlaveGroupAccessor<'a> {
    type Item = u8;
    type IntoIter = SlaveGroupIter<'a>;

    fn into_iter(self) -> Self::IntoIter {
        SlaveGroupIter {
            accessor: self,
            current_group: 0,
        }
    }
}

impl EtherCATMaster {

    pub fn group_accessor(&self) -> SlaveGroupAccessor<'_> {
        SlaveGroupAccessor::new(self)
    }
}

pub struct BuildResult {

    pub master: EtherCATMaster,

    pub slave_count: usize,

    pub success: bool,
}

impl Deref for BuildResult {
    type Target = EtherCATMaster;

    fn deref(&self) -> &Self::Target {
        &self.master
    }
}

impl std::fmt::Display for BuildResult {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        write!(f, "BuildResult(success={}, slaves={})", self.success, self.slave_count)
    }
}

impl std::fmt::Debug for BuildResult {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        f.debug_struct("BuildResult")
            .field("success", &self.success)
            .field("slave_count", &self.slave_count)
            .field("master_index", &self.master.index)
            .finish()
    }
}

#[derive(Debug, Clone)]
pub struct ValidationResult {

    pub is_valid: bool,

    pub errors: Vec<String>,
}

pub struct MasterBuilder {

    pending_network: Option<String>,

    pending_redundant: Option<String>,

    pending_eni_path: Option<String>,

    pending_esi_paths: Vec<String>,

    pending_auto_startup: bool,

    configuration_set: bool,
}

impl MasterBuilder {

    pub fn new() -> Self {
        Self {
            pending_network: None,
            pending_redundant: None,
            pending_eni_path: None,
            pending_esi_paths: Vec::new(),
            pending_auto_startup: false,
            configuration_set: false,
        }
    }

    pub fn set_eni(mut self, path: &str) -> Self {
        self.pending_eni_path = Some(path.to_string());
        self.configuration_set = true;
        self
    }

    pub fn set_esi_file(mut self, path: &str) -> Self {
        if !path.is_empty() {
            self.pending_esi_paths.push(path.to_string());
        }
        self
    }

    pub fn set_esi_files(mut self, path: &str) -> Self {
        if !path.is_empty() {
            self.pending_esi_paths.push(path.to_string());
        }
        self
    }

    pub fn set_network(mut self, primary: &str, redundant: Option<&str>) -> Self {
        self.pending_network = Some(primary.to_string());
        self.pending_redundant = redundant.map(|s| s.to_string());
        self.configuration_set = true;
        self
    }

    pub fn enable_auto_startup(mut self) -> Self {
        self.pending_auto_startup = true;
        self
    }

    pub fn validate(&self) -> ValidationResult {
        let mut errors = Vec::new();

        if !self.configuration_set {
            errors.push("未设置网口或 ENI 配置, 主站无法初始化".into());
        }

        if self.pending_eni_path.is_none() && self.pending_network.is_none() {
            errors.push("未设置 ENI 配置文件路径或网口名称".into());
        }

        if let Some(ref path) = self.pending_eni_path {
            if path.trim().is_empty() {
                errors.push("ENI 配置文件路径不能为空".into());
            }
        }

        if let Some(ref primary) = self.pending_network {
            if primary.trim().is_empty() {
                errors.push("主网口名称不能为空".into());
            }
        }

        ValidationResult {
            is_valid: errors.is_empty(),
            errors,
        }
    }

    pub fn build(self) -> Result<BuildResult> {

        if !self.configuration_set {
            return Err(DarraError::Other(
                "未设置网口或 ENI 配置, 主站无法初始化".into()
            ));
        }

        crate::statics::driver_version::log_compatibility();

        let index = unsafe { ffi::Initialize() };
        if index == 0xFFFF {
            return Err(DarraError::AlreadyInitialized);
        }
        let mut master = EtherCATMaster {
            index,
            started: false,
            owned: true,
        };

        for _esi_path in &self.pending_esi_paths {

        }

        if let Some(ref eni_path) = self.pending_eni_path {

            let deni_content = std::fs::read_to_string(eni_path)
                .map_err(|e| DarraError::Other(format!("读 DENI 文件失败 {}: {}", eni_path, e)))?;
            let c_content = CString::new(deni_content)
                .map_err(|_| DarraError::InvalidParameter(obfstr::obfstr!("DENI 内容包含空字节").into()))?;
            let ret = unsafe {
                ffi::DarraCoreInvokeText(index, ffi::CORE_OP_23, c_content.as_ptr(), ffi::CORE_FLAG_01, 0, 0)
            };
            if ret < 0 {

                master.owned = false;
                unsafe { ffi::Dispose(index) };
                return Err(DarraError::ConfigLoadFailed(ret));
            }
        }

        if let Some(ref primary) = self.pending_network {

            let c_adapter = CString::new(primary.as_str())
                .map_err(|_| DarraError::InvalidParameter(obfstr::obfstr!("主网口名称包含空字节").into()))?;
            let redundant_str = self.pending_redundant.as_deref().unwrap_or("");
            let c_redundant = CString::new(redundant_str)
                .map_err(|_| DarraError::InvalidParameter(obfstr::obfstr!("冗余网口名称包含空字节").into()))?;
            let ret = unsafe { ffi::SetNetwork(index, c_adapter.as_ptr(), c_redundant.as_ptr()) };
            if ret <= 0 {
                master.owned = false;
                unsafe { ffi::Dispose(index) };
                return Err(DarraError::NetworkFailed(ret));
            }
        }

        let slave_count = master.slave_count() as usize;

        if self.pending_auto_startup && slave_count > 0 {

            let ret = unsafe { ffi::DarraCoreInvoke(index, ffi::CORE_OP_24, 0, 0, 0) };
            if ret < 0 {
                master.owned = false;
                unsafe { ffi::Dispose(index) };
                return Err(DarraError::Other(format!("AutoStartup native protocol action failed: {}", ret)));
            }
        }

        unsafe { ffi::ApplyRealtimeOptimizations() };

        Ok(BuildResult {
            master,
            slave_count,
            success: slave_count > 0,
        })
    }
}

impl Default for MasterBuilder {
    fn default() -> Self {
        Self::new()
    }
}

impl EtherCATMaster {

    pub fn get_multi_slave_sdo_list(&self, slave_indices: &[u16]) -> Vec<Option<crate::slave::coe::OdList>> {
        use std::os::raw::c_int;

        let count = slave_indices.len() as c_int;
        if count == 0 {
            return Vec::new();
        }

        let mut results: Vec<*const std::ffi::c_void> = vec![std::ptr::null(); count as usize];
        let ret = unsafe {
            ffi::GetMultiSlaveSDOList(
                self.index,
                slave_indices.as_ptr(),
                count,
                results.as_mut_ptr(),
            )
        };

        let mut output = Vec::with_capacity(count as usize);
        if ret <= 0 {

            for _ in 0..count {
                output.push(None);
            }
            return output;
        }

        for i in 0..count as usize {
            if results[i].is_null() {
                output.push(None);
            } else {

                match crate::slave::coe::OdList::from_raw_ptr(
                    self.index, slave_indices[i], results[i],
                ) {
                    Ok(od) => output.push(Some(od)),
                    Err(_) => output.push(None),
                }
            }
        }

        unsafe { ffi::FreeMultiSlaveSDOList(results.as_mut_ptr(), count) };
        output
    }

    pub fn deconstruct(&self) -> (bool, u16, u16) {
        (self.owned, self.slave_count(), self.index)
    }

    pub fn pdo_lost_frames(&self, group: u8) -> u32 {
        let mut total: u32 = 0;
        let mut consecutive: u32 = 0;
        let mut max_consecutive: u32 = 0;
        unsafe {
            ffi::GetPDOFrameLossStats(self.index, group,
                                       &mut total, &mut consecutive, &mut max_consecutive);
        }
        total
    }

    pub fn pdo_consecutive_lost(&self, group: u8) -> u32 {
        let mut total: u32 = 0;
        let mut consecutive: u32 = 0;
        let mut max_consecutive: u32 = 0;
        unsafe {
            ffi::GetPDOFrameLossStats(self.index, group,
                                       &mut total, &mut consecutive, &mut max_consecutive);
        }
        consecutive
    }

    pub fn pdo_max_consecutive_lost(&self, group: u8) -> u32 {
        let mut total: u32 = 0;
        let mut consecutive: u32 = 0;
        let mut max_consecutive: u32 = 0;
        unsafe {
            ffi::GetPDOFrameLossStats(self.index, group,
                                       &mut total, &mut consecutive, &mut max_consecutive);
        }
        max_consecutive
    }

    pub fn esi_load_directory(&self, dir: &str) -> Result<i32> {
        let c_dir = CString::new(dir)
            .map_err(|_| DarraError::InvalidParameter(obfstr::obfstr!("ESI dir 含空字节").into()))?;
        let n = unsafe { ffi::EcEsi_LoadDirectory(c_dir.as_ptr()) };
        Ok(n)
    }

    pub fn esi_load_file(&self, path: &str) -> Result<i32> {
        let c_path = CString::new(path)
            .map_err(|_| DarraError::InvalidParameter(obfstr::obfstr!("ESI 路径含空字节").into()))?;
        let n = unsafe { ffi::EcEsi_LoadFile(c_path.as_ptr()) };
        Ok(n)
    }

    pub fn esi_clear(&self) {
        unsafe { ffi::EcEsi_Clear() }
    }

    pub fn esi_loaded_count(&self) -> i32 {
        unsafe { ffi::EcEsi_GetLoadedCount() }
    }

    pub fn esi_auto_match_all(&self) -> i32 {
        unsafe { ffi::EcEsi_AutoMatchAll(self.index) }
    }

    pub fn esi_bind_to_slave(&self, slave_index: u16, path: &str) -> Result<i32> {
        let c_path = CString::new(path)
            .map_err(|_| DarraError::InvalidParameter(obfstr::obfstr!("ESI 路径含空字节").into()))?;
        let n = unsafe { ffi::EcEsi_BindToSlave(self.index, slave_index, c_path.as_ptr()) };
        Ok(n)
    }

    pub fn esi_register_startup_parameters(&self, slave_index: u16) -> i32 {
        unsafe { ffi::EcEsi_RegisterStartupParameters(self.index, slave_index) }
    }

    pub fn esi_apply_all_slaves(&self) -> i32 {
        unsafe { ffi::EcEsi_ApplyAllSlaves(self.index) }
    }

    pub fn set_slave_esi_file(&self, slave_index: u16, name: &str) -> Result<i32> {
        let c_name = CString::new(name)
            .map_err(|_| DarraError::InvalidParameter(obfstr::obfstr!("ESI 文件名含空字节").into()))?;
        let n = unsafe { ffi::SetSlaveEsiFile(self.index, slave_index, c_name.as_ptr()) };
        Ok(n)
    }
}

#[cfg(feature = "async-tokio")]
impl EtherCATMaster {

    #[inline]
    pub(crate) fn started_flag(&self) -> bool {
        self.started
    }

    #[inline]
    pub(crate) fn set_started_flag(&mut self, started: bool) {
        self.started = started;
    }

    #[inline]
    pub(crate) fn mark_disposed(&mut self) {
        self.owned = false;
        self.started = false;
    }

    pub(crate) fn set_state_at(index: u16, state: EcState, was_started: bool) -> Result<bool> {

        let per_step_slave_count = {
            let mut total: i32 = 0;
            for g in 0..8u8 {
                total += unsafe { ffi::GetGroupSlaveCount(index, g) } as i32;
            }
            if total <= 0 { 1 } else { total }
        };
        let transition_timeout_ms: u32 = (per_step_slave_count * 2000).clamp(4000, 30000) as u32;

        let mut started = was_started;
        for attempt in 0..3 {
            let attempt_sw = std::time::Instant::now();
            let ok = unsafe {
                ffi::SetStateSequence(index, state as c_int, transition_timeout_ms)
            } != 0;
            let elapsed_ms = attempt_sw.elapsed().as_millis() as u32;
            if ok {
                if matches!(state, EcState::SafeOp | EcState::Operational) && !started {
                    unsafe { ffi::Start(index) };
                    started = true;
                }
                return Ok(started);
            }

            if elapsed_ms >= transition_timeout_ms {
                return Err(DarraError::StateChangeFailed(state as u8));
            }
            if attempt < 2 {
                std::thread::sleep(std::time::Duration::from_millis(1500));
            }
        }

        if state == EcState::Operational {
            match Self::op_demote_grace_wait(index, started) {
                Some(Ok(())) => return Ok(true),
                Some(Err(e)) => return Err(e),
                None => {}
            }
        }

        Err(DarraError::StateChangeFailed(state as u8))
    }

    pub(crate) fn dispose_at(index: u16, was_started: bool) {
        if was_started {
            unsafe { ffi::Stop(index) };
        }
        unsafe { ffi::Dispose(index) };
    }
}
