-- Compact, two-line network throughput widget.  It samples the interface used
-- by the default route so virtual and physical interfaces are not double-counted.
local command = [[
iface=$(ip route show default 2>/dev/null | awk '$1 == "default" { for (i = 1; i <= NF; i++) if ($i == "dev") { print $(i + 1); exit } }')

if [ -z "$iface" ]; then
  for path in /sys/class/net/*; do
    candidate=${path##*/}
    [ "$candidate" = "lo" ] && continue
    [ "$(cat "$path/carrier" 2>/dev/null)" = "1" ] || continue
    iface=$candidate
    break
  done
fi

[ -n "$iface" ] || exit 1
awk -v iface="$iface" '$1 ~ ("^" iface ":") { sub(":", "", $1); print iface "\t" $2 "\t" $10; exit }' /proc/net/dev
]]

local previous = nil
local request_in_flight = false
-- 82px accommodates the longest fixed field ("1023 KiB/s") at 10px while
-- removing the excess side padding from the original 112px capsule.
local label_width = 82

local function formatRate(bytes_per_second)
  local units = { "B/s", "KiB/s", "MiB/s", "GiB/s" }
  local value = bytes_per_second
  local unit_index = 1

  while value >= 1024 and unit_index < #units do
    value = value / 1024
    unit_index = unit_index + 1
  end

  if unit_index == 1 then
    return string.format("%d %s", math.floor(value + 0.5), units[unit_index])
  end

  if value >= 100 then
    return string.format("%.0f %s", value, units[unit_index])
  end

  return string.format("%.1f %s", value, units[unit_index])
end

local function renderLines(download, upload)
  -- The explicit minimum width and fixed ten-character value field keep the
  -- capsule width stable while inheriting the bar font used by other modules.
  barWidget.render(ui.column({ gap = 0, align = "center", minWidth = label_width }, {
    ui.label({
      text = string.format("↓ %10s", download),
      maxLines = 1,
      fontSize = 10,
    }),
    ui.label({
      text = string.format("↑ %10s", upload),
      maxLines = 1,
      fontSize = 10,
    }),
  }))
end

function update()
  noctalia.setUpdateInterval(2000)

  if request_in_flight then
    return
  end

  request_in_flight = true
  noctalia.runAsync(command, function(result)
    request_in_flight = false

    if result.exitCode ~= 0 then
      previous = nil
      renderLines("—", "—")
      barWidget.setTooltip("Network throughput unavailable: no active interface")
      return
    end

    local iface, received, sent = string.match(
      result.stdout,
      "^([^\t]+)\t(%d+)\t(%d+)"
    )
    received = tonumber(received)
    sent = tonumber(sent)

    if iface == nil or received == nil or sent == nil then
      previous = nil
      renderLines("—", "—")
      barWidget.setTooltip("Network throughput unavailable")
      return
    end

    local now = os.time()
    if previous == nil or previous.iface ~= iface or now <= previous.time then
      previous = { iface = iface, received = received, sent = sent, time = now }
      renderLines("Sampling…", "Sampling…")
      barWidget.setTooltip("Sampling network throughput on " .. iface)
      return
    end

    local elapsed = now - previous.time
    local download = math.max(0, (received - previous.received) / elapsed)
    local upload = math.max(0, (sent - previous.sent) / elapsed)
    previous = { iface = iface, received = received, sent = sent, time = now }

    renderLines(formatRate(download), formatRate(upload))
    barWidget.setTooltip(
      string.format(
        "%s · Download %s · Upload %s",
        iface,
        formatRate(download),
        formatRate(upload)
      )
    )
  end)
end
