//! `From` / `Into` 类型转换语法糖
//!
//! 在不修改主类型的前提下, 为 SDK 数据类型增加跨边界的 `From` / `Into` 实现,
//! 让常见组合操作 (取从站身份、把 raw 状态转枚举、把网络信息转字符串) 写起来
//! 像 Rust 标准库那样自然.
//!
//! # 示例
//!
//! ```no_run
//! use darra_ethercat::sugar::prelude::*;
//! use darra_ethercat::{EtherCATMaster, SlaveIdentity, EcState};
//!
//! let m = EtherCATMaster::new().unwrap();
//! let s = m.slave(1);
//!
//! // 1. Slave -> SlaveIdentity (vendor_id / product_code / revision_no / serial_no)
//! let id: SlaveIdentity = (&s).into();
//!
//! // 2. u8 -> EcState (从 raw byte 直接拿枚举, 出错回落到 None)
//! let st: EcState = 0x08u8.into();
//! assert_eq!(st, EcState::Operational);
//!
//! // 3. EcState -> u8 (写回 DLL 接口时方便)
//! let raw: u8 = EcState::PreOp.into();
//! assert_eq!(raw, 0x02);
//! ```

use crate::data::error::{EcState, LinkState, RedundancyState, CiA402State, CiA402Mode};
use crate::slave::core::Slave;
use crate::utils::ffi::SlaveIdentity;

// ============================================================
// Slave -> SlaveIdentity
// ============================================================

impl From<&Slave> for SlaveIdentity {
    /// 从 [`Slave`] 句柄抽取 [`SlaveIdentity`] (vendor / product / rev / serial)
    fn from(s: &Slave) -> Self {
        SlaveIdentity {
            vendor_id: s.vendor_id(),
            product_code: s.product_id(),
            revision_no: s.rev_id(),
            serial_no: 0, // SDK 当前未暴露 serial; 留 0 与 C 默认一致
        }
    }
}

impl From<Slave> for SlaveIdentity {
    fn from(s: Slave) -> Self {
        (&s).into()
    }
}

// ============================================================
// EcState  <->  u8
// ============================================================

impl From<u8> for EcState {
    /// 从 raw u8 状态字 (低 4 位) 转 [`EcState`]; 未知值映射为 `None`
    fn from(v: u8) -> Self {
        EcState::from_raw(v).unwrap_or(EcState::None)
    }
}

impl From<EcState> for u8 {
    /// 把 [`EcState`] 转为 EtherCAT 协议层的状态字节
    fn from(s: EcState) -> u8 {
        s as u8
    }
}

impl From<EcState> for i32 {
    /// 把 [`EcState`] 转为 DLL 通道用的 i32
    fn from(s: EcState) -> i32 {
        (s as u8) as i32
    }
}

// ============================================================
// LinkState <-> u8
// ============================================================

impl From<u8> for LinkState {
    fn from(v: u8) -> Self {
        LinkState::from_raw(v)
    }
}

impl From<LinkState> for u8 {
    fn from(s: LinkState) -> u8 {
        s as u8
    }
}

// ============================================================
// RedundancyState <-> i32
// ============================================================

impl From<i32> for RedundancyState {
    fn from(v: i32) -> Self {
        RedundancyState::from_raw(v)
    }
}

impl From<RedundancyState> for i32 {
    fn from(s: RedundancyState) -> i32 {
        s as i32
    }
}

// ============================================================
// CiA402State <-> i32
// ============================================================

impl From<i32> for CiA402State {
    fn from(v: i32) -> Self {
        CiA402State::from_raw(v)
    }
}

impl From<CiA402State> for i32 {
    fn from(s: CiA402State) -> i32 {
        s as i32
    }
}

// ============================================================
// CiA402Mode <-> i8
// ============================================================

impl From<CiA402Mode> for i8 {
    fn from(m: CiA402Mode) -> i8 {
        m as i8
    }
}

impl From<CiA402Mode> for i32 {
    fn from(m: CiA402Mode) -> i32 {
        (m as i8) as i32
    }
}

// ============================================================
// EcState -> &'static str (便捷日志/格式化)
// ============================================================

impl From<EcState> for &'static str {
    fn from(s: EcState) -> &'static str {
        match s {
            EcState::None => "None",
            EcState::Init => "Init",
            EcState::PreOp => "PreOp",
            EcState::Boot => "Boot",
            EcState::SafeOp => "SafeOp",
            EcState::Operational => "OP",
        }
    }
}

impl From<LinkState> for &'static str {
    fn from(s: LinkState) -> &'static str {
        match s {
            LinkState::Disconnected => "Disconnected",
            LinkState::Connected => "Connected",
            LinkState::Redundancy => "Redundancy",
            LinkState::PrimaryOnly => "PrimaryOnly",
            LinkState::SecondaryOnly => "SecondaryOnly",
        }
    }
}

impl From<RedundancyState> for &'static str {
    fn from(s: RedundancyState) -> &'static str {
        match s {
            RedundancyState::None => "None",
            RedundancyState::Primary => "PrimaryOnly",
            RedundancyState::Secondary => "SecondaryOnly",
            RedundancyState::Both => "Both",
        }
    }
}
