///|
fn parse_timeout_arg(
  args : Array[String],
  index : Int,
  default_value : Int,
) -> Int? {
  if args.length() <= index {
    Some(default_value)
  } else {
    try @string.parse_int(args[index][:]) catch {
      _ => {
        println("Invalid timeout. Expected a decimal integer.")
        return None
      }
    } noraise {
      value => Some(value)
    }
  }
}

///|
fn read_frame_u16_be(frame : Bytes, offset : Int) -> Int {
  (frame[offset].to_int() << 8) + frame[offset + 1].to_int()
}

///|
fn run_snmp_get(args : Array[String]) -> Unit {
  guard args.length() >= 1 else {
    println("snmp-get  [community] [timeout-ms]")
    println("  Example: snmp-get 192.168.3.10 public 3000")
    return
  }
  let device_ip = @frame.IPv4Address::from_text(args[0][:]) catch {
    err => {
      println("Invalid device IP: \{to_repr(err)}")
      return
    }
  }
  let community = if args.length() >= 2 { args[1] } else { "public" }
  let timeout_ms = match parse_timeout_arg(args, 2, 3000) {
    Some(value) => value
    None => return
  }
  println(
    provider_harness_helper_handoff_text(
      "snmp-get",
      "SNMP helper",
      "@udpnet.UdpSocket::open",
      [
        "device_ip=" + device_ip.to_text(),
        "community=" + community,
        "timeout_ms=" + timeout_ms.to_string(),
      ],
    ),
  )
}

///|
fn run_lldp_capture(args : Array[String]) -> Unit {
  guard args.length() >= 2 && args[0] == "--iface" else {
    println("lldp-capture --iface  [timeout-ms] [source-mac]")
    println(
      "  Example: lldp-capture --iface \"I226-V #2\" 35000 74:90:50:10:E9:07",
    )
    return
  }
  let timeout_ms = match parse_timeout_arg(args, 2, 35000) {
    Some(value) => value
    None => return
  }
  let expected_source = if args.length() >= 4 {
    Some(
      @frame.MacAddress::from_hex(args[3][:]) catch {
        err => {
          println("Invalid source MAC: \{to_repr(err)}")
          return
        }
      },
    )
  } else {
    None
  }
  let fields : Array[String] = [
    "interface=" + args[1],
    "timeout_ms=" + timeout_ms.to_string(),
  ]
  match expected_source {
    Some(mac) => fields.push("source_mac=" + mac.to_hex())
    None => ()
  }
  println(
    provider_harness_helper_handoff_text(
      "lldp-capture", "LLDP raw Ethernet helper", "@rawnet.RawSocket::open", fields,
    ),
  )
}

///|
fn run_dhcp_discover_live(args : Array[String]) -> Unit {
  guard args.length() >= 2 && args[0] == "--iface" else {
    println(
      "dhcp-discover-live --iface  [timeout-ms] [hostname] [xid] [bind-ip]",
    )
    println(
      "  Example: dhcp-discover-live --iface \"I226-V #2\" 5000 codex-profinet",
    )
    return
  }
  let timeout_ms = match parse_timeout_arg(args, 2, 5000) {
    Some(value) => value
    None => return
  }
  let hostname = if args.length() >= 4 { args[3] } else { "codex-profinet" }
  let xid_field = if args.length() >= 5 {
    match parse_number_arg(args[4], "xid") {
      Some(value) => "xid=" + value.to_string()
      None => return
    }
  } else {
    "xid=auto_from_provider_harness"
  }
  let bind_ip = if args.length() >= 6 {
    @frame.IPv4Address::from_text(args[5][:]) catch {
      err => {
        println("Invalid bind IP: \{to_repr(err)}")
        return
      }
    }
  } else {
    @frame.IPv4Address::from_text("0.0.0.0") catch {
      err => {
        println("Invalid default bind IP: \{to_repr(err)}")
        return
      }
    }
  }
  println(
    provider_harness_helper_handoff_text(
      "dhcp-discover-live",
      "DHCP helper",
      "@rawnet.RawSocket::open + @udpnet.UdpSocket::open",
      [
        "interface=" + args[1],
        "timeout_ms=" + timeout_ms.to_string(),
        "hostname=" + hostname,
        xid_field,
        "bind_ip=" + bind_ip.to_text(),
      ],
    ),
  )
}