//! `netstat -rn -f inet` 解析。
//!
//! netstat 输出非常嘈杂（含大量 ARP 缓存主机路由 `UHLWI`），
//! 我们只关心两类：
//! - **默认路由**：`Destination == default`，gateway 是网关 IP，netif 是网卡。
//! - **直连网段**：Flags 含 `S`（网络路由）且不含 `H`（非主机），
//!   且 gateway 形如 `link#N`（on-link）。这覆盖 `UCS`/`UCSI`/`UmCS` 等。
//!
//! 网络路由 vs 主机路由的判定基于 BSD `netstat` 的 Flags：
//! - `U` = Up，`G` = Gateway，`H` = Host（主机路由），`S` = Static/网络
//!   `C` = Clone，`L` = Link-layer，`W` = Was cloned，`I` = Ifscope，`m` = Multicast。
//! 主机路由（含 `H`，如 `UHLWI`）一律忽略；网络路由（含 `S` 不含 `H`）保留。

use std::net::Ipv4Addr;

use crate::error::AppResult;
use crate::net::route::{netmask_to_prefix_len, prefix_len_to_netmask};

/// 一条 netstat 路由条目（已分类）。
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct NetstatRoute {
    /// CIDR 目标网段。default 用 `0.0.0.0/0`。
    pub dest: Ipv4Addr,
    pub prefix_len: u8,
    /// 网关 IP。on-link 直连网段为 None。
    pub gateway: Option<Ipv4Addr>,
    /// 出口网卡，如 `en1`。
    pub interface: String,
    /// 是否默认路由。
    pub is_default: bool,
}

impl NetstatRoute {
    pub fn is_default_route(&self) -> bool {
        self.is_default
    }
}

/// 解析 netstat 输出，返回默认路由 + 直连网段（已去噪）。
pub fn parse_netstat(raw: &str) -> AppResult<Vec<NetstatRoute>> {
    let mut out = Vec::new();
    for line in raw.lines() {
        let line = line.trim();
        // 跳过表头与空行
        if line.is_empty()
            || line.starts_with("Routing tables")
            || line.starts_with("Internet:")
            || line.starts_with("Destination")
        {
            continue;
        }

        let parts: Vec<&str> = line.split_whitespace().collect();
        // 期望至少：Destination Gateway Flags Netif [Expire]
        if parts.len() < 4 {
            continue;
        }
        let dest_field = parts[0];
        let gateway_field = parts[1];
        let flags_field = parts[2];
        let netif = parts[3];

        // 只关心 IPv4 真实网卡（en*/lo*/utun* 等），跳过奇怪的
        // —— 但不过滤 netif，保持通用。

        // default 路由
        if dest_field == "default" {
            if let Ok(gw) = gateway_field.parse::<Ipv4Addr>() {
                out.push(NetstatRoute {
                    dest: Ipv4Addr::UNSPECIFIED,
                    prefix_len: 0,
                    gateway: Some(gw),
                    interface: netif.to_string(),
                    is_default: true,
                });
            }
            continue;
        }

        // 直连网段：必须含 S 且不含 H。
        // gateway 形如 link#N 表示 on-link（直连）。
        if !flags_field.contains('S') || flags_field.contains('H') {
            continue;
        }
        // 解析 dest（可能是 `192.168.108/22` 或 `172.30` 这种缩写形式）
        let (dest, prefix_len) = match parse_netstat_dest(dest_field) {
            Some(v) => v,
            None => continue,
        };
        // 跳过 /32「伪网络路由」：本质是主机地址条目（如网卡自身 IP / 网关 IP）。
        // /32 即使 flags 含 S，语义上也是单机，在 TUI 里属于噪声。
        if prefix_len == 32 {
            continue;
        }
        // 跳过保留/特殊网段：loopback、link-local、multicast、broadcast。
        if is_reserved_network(dest, prefix_len) {
            continue;
        }
        // gateway：link#N → None（直连）；否则尝试解析为 IP
        let gateway = if gateway_field.starts_with("link#") {
            None
        } else {
            gateway_field.parse::<Ipv4Addr>().ok()
        };

        out.push(NetstatRoute {
            dest,
            prefix_len,
            gateway,
            interface: netif.to_string(),
            is_default: false,
        });
    }

    Ok(out)
}

/// 解析 netstat 的 Destination 字段。
///
/// netstat 用 BSD 风格缩写：
/// - `192.168.108/22` → `192.168.108.0/22`
/// - `172.30` → `172.30.0.0/16`（按出现的前导字节推断）
/// - `127` → `127.0.0.0/8`
/// - `224.0.0/4` → `224.0.0.0/4`
/// - `10` → `10.0.0.0/8`
///
/// 简化策略：若含 `/`，按 CIDR 解析（dest 部分补齐到 4 段）；
/// 若不含 `/`，按完整 IPv4 或前缀缩写处理。
fn parse_netstat_dest(field: &str) -> Option<(Ipv4Addr, u8)> {
    if let Some((addr_str, plen_str)) = field.split_once('/') {
        let plen: u8 = plen_str.parse().ok()?;
        if plen > 32 {
            return None;
        }
        let octets: Vec<u8> = addr_str.split('.').filter_map(|s| s.parse().ok()).collect();
        if octets.is_empty() || octets.len() > 4 {
            return None;
        }
        let mut full = [0u8; 4];
        for (i, &o) in octets.iter().enumerate() {
            full[i] = o;
        }
        // 若只给了部分字节，按给的字节数推断默认前缀（每段 8 位）
        // 例如 `192.168.108/22` 给了 3 段，但显式 /22 优先。
        return Some((Ipv4Addr::from(full), plen));
    }

    // 无 '/'：可能是完整 IP 或缩写
    let octets: Vec<u8> = field.split('.').filter_map(|s| s.parse().ok()).collect();
    if octets.is_empty() || octets.len() > 4 {
        return None;
    }
    let mut full = [0u8; 4];
    for (i, &o) in octets.iter().enumerate() {
        full[i] = o;
    }
    // 无显式前缀时，按给出的字节数推断（`10`→/8，`172.30`→/16，`192.168.1`→/24）
    let plen = (octets.len() * 8) as u8;
    Some((Ipv4Addr::from(full), plen))
}

/// 直连网段：由「网卡 IP + 掩码」计算出的网络地址 + 前缀。
/// 用于 getinfo 推算（与 netstat 的直连网段互相印证）。
pub fn network_address(ip: Ipv4Addr, mask: Ipv4Addr) -> AppResult<(Ipv4Addr, u8)> {
    let plen = netmask_to_prefix_len(mask)?;
    let net = prefix_len_to_netmask(plen); // 规范化掩码
    let bits = u32::from(ip) & u32::from(net);
    Ok((Ipv4Addr::from(bits), plen))
}

/// 是否属于系统保留/特殊网段，TUI 里不展示这些直连网段：
/// - `127.0.0.0/8`（loopback）
/// - `169.254.0.0/16`（link-local）
/// - `224.0.0.0/4`（multicast）
/// - `255.255.255.255/32`（limited broadcast）
fn is_reserved_network(dest: Ipv4Addr, _prefix_len: u8) -> bool {
    let o = dest.octets();
    o[0] == 127 // loopback
        || (o[0] == 169 && o[1] == 254) // link-local
        || (o[0] >= 224 && o[0] <= 239) // multicast 224.0.0.0/4
        || (o[0] == 255 && o[1] == 255 && o[2] == 255 && o[3] == 255) // broadcast
}

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

    #[test]
    fn parse_dest_with_slash() {
        assert_eq!(
            parse_netstat_dest("192.168.108/22"),
            Some((Ipv4Addr::new(192, 168, 108, 0), 22))
        );
        assert_eq!(
            parse_netstat_dest("224.0.0/4"),
            Some((Ipv4Addr::new(224, 0, 0, 0), 4))
        );
    }

    #[test]
    fn parse_dest_shorthand() {
        assert_eq!(
            parse_netstat_dest("10"),
            Some((Ipv4Addr::new(10, 0, 0, 0), 8))
        );
        assert_eq!(
            parse_netstat_dest("172.30"),
            Some((Ipv4Addr::new(172, 30, 0, 0), 16))
        );
        assert_eq!(
            parse_netstat_dest("127"),
            Some((Ipv4Addr::new(127, 0, 0, 0), 8))
        );
    }

    #[test]
    fn network_address_compute() {
        let (net, plen) = network_address(
            Ipv4Addr::new(192, 168, 108, 120),
            Ipv4Addr::new(255, 255, 252, 0),
        )
        .unwrap();
        assert_eq!(net, Ipv4Addr::new(192, 168, 108, 0));
        assert_eq!(plen, 22);
    }

    #[test]
    fn parse_default_routes() {
        let raw = "Routing tables\n\nInternet:\nDestination        Gateway            Flags               Netif Expire\ndefault            192.168.110.1      UGScg                 en1\ndefault            172.30.80.254      UGScIg                en0\n";
        let v = parse_netstat(raw).unwrap();
        assert_eq!(v.len(), 2);
        assert!(v[0].is_default);
        assert_eq!(v[0].gateway, Some(Ipv4Addr::new(192, 168, 110, 1)));
        assert_eq!(v[0].interface, "en1");
        assert_eq!(v[1].interface, "en0");
    }

    #[test]
    fn parse_direct_network_skips_host_routes() {
        let raw = "Destination     Gateway       Flags     Netif\n\
192.168.108/22  link#16       UCS       en1\n\
192.168.108.8   a:60:14:bf    UHLWI     en1\n\
172.30          link#7        UCSI      en0\n\
172.30.80.90    e0:be:3:22    UHLWI     en0\n";
        let v = parse_netstat(raw).unwrap();
        // 只保留 2 条直连网段，主机路由被过滤
        assert_eq!(v.len(), 2);
        assert_eq!(v[0].dest, Ipv4Addr::new(192, 168, 108, 0));
        assert_eq!(v[0].prefix_len, 22);
        assert_eq!(v[0].interface, "en1");
        assert_eq!(v[1].dest, Ipv4Addr::new(172, 30, 0, 0));
        assert_eq!(v[1].prefix_len, 16);
        assert_eq!(v[1].gateway, None); // link# → on-link
    }

    #[test]
    fn parse_skips_header_lines() {
        let raw = "Routing tables\n\nInternet:\nDestination        Gateway            Flags               Netif Expire\n";
        let v = parse_netstat(raw).unwrap();
        assert!(v.is_empty());
    }

    #[test]
    fn parse_skips_reserved_and_slash32() {
        let raw = "Destination     Gateway       Flags     Netif\n\
127              127.0.0.1     UCS       lo0\n\
169.254          link#16       UCS       en1\n\
224.0.0/4        link#16       UmCS      en1\n\
192.168.108/22   link#16       UCS       en1\n\
192.168.108.120/32 link#16     UCS       en1\n\
255.255.255.255/32 link#16     UCS       en1\n";
        let v = parse_netstat(raw).unwrap();
        // 只剩 192.168.108/22 这一条直连网段
        assert_eq!(v.len(), 1);
        assert_eq!(v[0].dest, Ipv4Addr::new(192, 168, 108, 0));
        assert_eq!(v[0].prefix_len, 22);
    }
}
