///|
/// 传输层协议
pub(all) enum Proto {
  Tcp
  Udp
  Icmp
  Icmpv6
  Other
} derive(Eq, Hash)

///|
/// 包方向(Local = 本机到本机,如回环)
pub(all) enum Direction {
  In
  Out
  Local
}

///|
/// IP 地址(v4 = 4 字节,v6 = 16 字节)
pub struct IpAddr {
  v4 : Bool
  bytes : Bytes
} derive(Eq, Hash, Compare)

///|
/// 构造 IP 地址
pub fn IpAddr::new(v4 : Bool, bytes : Bytes) -> IpAddr {
  { v4, bytes }
}

///|
/// 五元组(连接跟踪的 key)
pub struct FiveTuple {
  src_ip : IpAddr
  dst_ip : IpAddr
  src_port : Int
  dst_port : Int
  proto : Proto
} derive(Eq, Hash)

///|
/// 构造五元组
pub fn FiveTuple::new(
  src_ip : IpAddr,
  dst_ip : IpAddr,
  src_port : Int,
  dst_port : Int,
  proto : Proto,
) -> FiveTuple {
  { src_ip, dst_ip, src_port, dst_port, proto }
}

///|
/// 解析结果:时间戳 + 五元组 + 方向 + 载荷长度(供流量统计)
pub struct ParsedPacket {
  ts_sec : Int64
  ts_usec : Int
  tuple : FiveTuple
  direction : Direction
  payload_len : Int
  total_len : Int
}

///|
/// 构造解析结果
pub fn ParsedPacket::new(
  ts_sec : Int64,
  ts_usec : Int,
  tuple : FiveTuple,
  direction : Direction,
  payload_len : Int,
  total_len : Int,
) -> ParsedPacket {
  { ts_sec, ts_usec, tuple, direction, payload_len, total_len }
}

///|
pub fn Proto::to_string(self : Proto) -> String {
  match self {
    Tcp => "tcp"
    Udp => "udp"
    Icmp => "icmp"
    Icmpv6 => "icmpv6"
    Other => "other"
  }
}

///|
pub fn Direction::to_string(self : Direction) -> String {
  match self {
    In => "in"
    Out => "out"
    Local => "local"
  }
}

///|
pub fn IpAddr::to_string(self : IpAddr) -> String {
  let b = self.bytes
  if self.v4 {
    "\{b[0].to_int()}.\{b[1].to_int()}.\{b[2].to_int()}.\{b[3].to_int()}"
  } else {
    // IPv6:8 组,组内省略前导零(不压缩 :: 段)
    // 每组 4 位 hex,省略前导零(全零组保留 "0")
    let parts : Array[String] = []
    for i in 0..<8 {
      let g = b[i * 2].to_hex() + b[i * 2 + 1].to_hex()
      parts.push(
        if g == "0000" {
          "0"
        } else {
          g.trim_start(chars="0").to_owned()
        },
      )
    }
    parts.join(":")
  }
}

///|
pub fn FiveTuple::to_string(self : FiveTuple) -> String {
  "\{self.src_ip.to_string()}:\{self.src_port} -> \{self.dst_ip.to_string()}:\{self.dst_port} \{self.proto.to_string()}"
}

///|
/// 本机 IP 集合查找
fn contains_ip(ips : FixedArray[IpAddr], ip : IpAddr) -> Bool {
  ips.iter().any(fn(a) { a == ip })
}

///|
/// 方向判定:src 本机 + dst 外部 → Out;反 → In;都本机 → Local
pub fn direction(
  src : IpAddr,
  dst : IpAddr,
  local_ips : FixedArray[IpAddr],
) -> Direction {
  match (contains_ip(local_ips, src), contains_ip(local_ips, dst)) {
    (true, true) => Local
    (true, false) => Out
    _ => In
  }
}