//! 网络服务（对应 networksetup 列表里的一项）。
//!
//! 数据来源：`networksetup -listnetworkserviceorder`。
//! 解析逻辑见 [`parse_services`]，已用真实输出做 fixture 单测。

use crate::error::{AppError, AppResult};

/// 一个网络服务。
///
/// `order` 越小优先级越高（networksetup 输出里 `(1)` 是最高优先级）。
/// 被禁用的服务输出里会带 `(*)`，`enabled=false`。
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct NetworkService {
    /// 优先级序号（从 1 开始；0 表示无序号/已禁用且无序号）。
    pub order: u32,
    /// 显示名，例如 `"Wi-Fi"`、`"长沙 28F以太网"`。
    pub name: String,
    /// 硬件端口名，例如 `"Ethernet"`、`"AX88179A"`。
    pub hardware_port: String,
    /// 设备名（网卡），例如 `en0`、`en8`。
    pub device: String,
    /// 是否启用（没有 `*` 标记）。
    pub enabled: bool,
}

impl NetworkService {
    // 字段 `device` 是 public，直接访问 `s.device` 即可，无需 getter。
}

/// 解析 `networksetup -listnetworkserviceorder` 的完整输出。
///
/// 输入示例（真实样例）：
/// ```text
/// An asterisk (*) denotes that a network service is disabled.
/// (1) Wi-Fi
/// (Hardware Port: Wi-Fi, Device: en1)
/// (*) Ethernet
/// (Hardware Port: Ethernet, Device: en0)
/// ```
///
/// 规则：
/// - 首行是说明文字，跳过。
/// - 以 `(` 开头且紧跟数字或 `*` 的行是服务行。
/// - 下一行 `(Hardware Port: X, Device: enY)` 是硬件信息。
/// - 服务名可以包含空格、中文等。
pub fn parse_services(raw: &str) -> AppResult<Vec<NetworkService>> {
    let mut lines = raw.lines().peekable();
    let mut out = Vec::new();

    while let Some(line) = lines.next() {
        let trimmed = line.trim();
        // 服务行形如 "(1) Wi-Fi" 或 "(*) Ethernet"
        if !trimmed.starts_with('(') {
            continue;
        }
        // 拆出 "(...)" 中的标记
        let close = trimmed
            .find(')')
            .ok_or_else(|| AppError::Parse(format!("缺少右括号: {trimmed:?}")))?;
        let tag = &trimmed[1..close]; // "1" 或 "*"
        let rest = trimmed[close + 1..].trim(); // 服务名

        let (enabled, order) = if tag == "*" {
            (false, 0)
        } else {
            let o: u32 = tag
                .parse()
                .map_err(|_| AppError::Parse(format!("非法序号: {tag:?}")))?;
            (true, o)
        };

        // 紧接着应该是 "(Hardware Port: X, Device: enY)"
        let hw_line = lines
            .next()
            .ok_or_else(|| AppError::Parse(format!("缺少 Hardware Port 行（服务 {rest:?}）")))?
            .trim();
        let (hardware_port, device) = parse_hardware_line(hw_line)?;

        out.push(NetworkService {
            order,
            name: rest.to_string(),
            hardware_port,
            device,
            enabled,
        });
    }

    Ok(out)
}

/// 解析 `(Hardware Port: Ethernet, Device: en0)` 这一行。
fn parse_hardware_line(line: &str) -> AppResult<(String, String)> {
    // 去掉外层括号
    let inner = line
        .strip_prefix('(')
        .and_then(|s| s.strip_suffix(')'))
        .ok_or_else(|| AppError::Parse(format!("非法 Hardware Port 行: {line:?}")))?;
    // 拆 "Hardware Port: X, Device: Y" —— 注意 X 可能含逗号？实测不会，按 ", Device: " 分割
    let key_dev = ", Device: ";
    let dev_idx = inner
        .rfind(key_dev)
        .ok_or_else(|| AppError::Parse(format!("未找到 Device 字段: {line:?}")))?;
    let hp_part = &inner[..dev_idx]; // "Hardware Port: Ethernet"
    let dev_part = &inner[dev_idx + key_dev.len()..]; // "en0"

    let hardware_port = hp_part
        .strip_prefix("Hardware Port: ")
        .ok_or_else(|| AppError::Parse(format!("未找到 Hardware Port 前缀: {line:?}")))?;

    Ok((hardware_port.to_string(), dev_part.to_string()))
}

#[cfg(test)]
mod tests {
    use super::*;

    // 真实样例（来自你机器的 listnetworkserviceorder）。
    const FIXTURE: &str = "An asterisk (*) denotes that a network service is disabled.
(1) Wi-Fi
(Hardware Port: Wi-Fi, Device: en1)
(*) Ethernet
(Hardware Port: Ethernet, Device: en0)
(*) 长沙 28F以太网
(Hardware Port: Ethernet, Device: en0)
(*) Ethernet 安全内网
(Hardware Port: Ethernet, Device: en0)
(2) 麒麟北京内网 11 楼
(Hardware Port: Ethernet, Device: en0)
(3) AX88179A
(Hardware Port: AX88179A, Device: en8)
(4) AX88179B
(Hardware Port: AX88179B, Device: en10)
";

    #[test]
    fn parse_real_fixture() {
        let svcs = parse_services(FIXTURE).unwrap();
        assert_eq!(svcs.len(), 7);

        let wifi = &svcs[0];
        assert_eq!(wifi.name, "Wi-Fi");
        assert_eq!(wifi.order, 1);
        assert_eq!(wifi.device, "en1");
        assert!(wifi.enabled);

        let eth = &svcs[1];
        assert_eq!(eth.name, "Ethernet");
        assert_eq!(eth.order, 0); // 禁用
        assert!(!eth.enabled);

        // 中文名
        assert_eq!(svcs[2].name, "长沙 28F以太网");
        assert!(!svcs[2].enabled);

        // 带空格和数字
        assert_eq!(svcs[4].name, "麒麟北京内网 11 楼");
        assert_eq!(svcs[4].order, 2);

        assert_eq!(svcs[5].device, "en8");
        assert_eq!(svcs[6].device, "en10");
    }

    #[test]
    fn parse_skips_header() {
        let s = "An asterisk (*) denotes that a network service is disabled.\n(1) Wi-Fi\n(Hardware Port: Wi-Fi, Device: en1)\n";
        let v = parse_services(s).unwrap();
        assert_eq!(v.len(), 1);
        assert_eq!(v[0].name, "Wi-Fi");
    }
}
