#!/bin/bash

interface=$1
action=$2
connection_uuid=${CONNECTION_UUID:-}

minimum_signal=40
signal_margin=20
retry_seconds=600
settle_seconds=5
state_dir=/run/blob-wifi-band
field_separator=$'\x1f'

nm_get() {
  LC_ALL=C nmcli -g "$@" 2>/dev/null
}

frequency_band() {
  local mhz=${1%%[!0-9]*}
  [[ -n $mhz ]] || return 1

  if ((mhz >= 2400 && mhz < 2500)); then
    echo "2.4"
  elif ((mhz >= 4900 && mhz < 7125)); then
    echo "5"
  else
    return 1
  fi
}

should_run() {
  [[ $action == up && -n $interface && -n $connection_uuid ]] || return 1
  [[ $(nm_get GENERAL.TYPE device show "$interface") == wifi ]] || return 1
  [[ -z $(nm_get 802-11-wireless.band connection show "$connection_uuid") ]] || return 1
  [[ -z $(nm_get 802-11-wireless.bssid connection show "$connection_uuid") ]] || return 1
}

attempted_recently() {
  local marker="$state_dir/$connection_uuid"
  [[ -e $marker ]] || return 1
  (($(date +%s) - $(stat -c %Y "$marker") < retry_seconds))
}

mark_attempt() {
  mkdir -p "$state_dir"
  touch "$state_dir/$connection_uuid"
}

list_access_points() {
  nm_get IN-USE,FREQ,SIGNAL,BSSID,SSID device wifi list ifname "$interface" --rescan no |
    sed "s/\\\\:/$field_separator/g"
}

find_better_access_point() {
  local in_use frequency signal bssid ssid
  local current_ssid="" current_signal=0 current_band=""
  local best_bssid="" best_signal=0
  local access_points

  access_points=$(list_access_points)

  while IFS=: read -r in_use frequency signal bssid ssid; do
    [[ $in_use == "*" ]] || continue
    current_ssid=${ssid//$field_separator/:}
    current_signal=$signal
    current_band=$(frequency_band "$frequency")
  done <<<"$access_points"

  [[ $current_band == "2.4" && -n $current_ssid ]] || return 1

  while IFS=: read -r in_use frequency signal bssid ssid; do
    [[ ${ssid//$field_separator/:} == "$current_ssid" ]] || continue
    [[ $(frequency_band "$frequency") == "5" ]] || continue
    ((signal > best_signal)) || continue
    best_signal=$signal
    best_bssid=${bssid//$field_separator/:}
  done <<<"$access_points"

  [[ -n $best_bssid ]] || return 1
  ((best_signal >= minimum_signal)) || return 1
  ((best_signal + signal_margin >= current_signal)) || return 1

  echo "$best_bssid"
}

switch_to_faster_band() {
  local target_bssid

  nmcli device wifi rescan ifname "$interface" &>/dev/null
  sleep "$settle_seconds"

  [[ $(nm_get GENERAL.CONNECTION device show "$interface") == "$(nm_get connection.id connection show "$connection_uuid")" ]] || return 0

  target_bssid=$(find_better_access_point) || return 0

  mark_attempt
  nmcli connection up uuid "$connection_uuid" ifname "$interface" ap "$target_bssid" &>/dev/null
}

should_run || exit 0
attempted_recently && exit 0

if [[ -z ${BLOB_WIFI_BAND_DETACHED:-} ]]; then
  BLOB_WIFI_BAND_DETACHED=1 setsid -f "$0" "$@" &>/dev/null
  exit 0
fi

switch_to_faster_band
