#!/usr/bin/env bash
#
# bt-netconfig - apply Ethernet configuration via NetworkManager.
#
# Usage:
#   bt-netconfig <iface> dhcp
#   bt-netconfig <iface> static <address> <prefix> [gateway] [dns_csv]
#
# Intended to be invoked through sudo by the (unprivileged) web configurator.
# Do NOT use ip/ifconfig directly — NetworkManager will undo manual changes.
set -euo pipefail

err() { echo "bt-netconfig: $*" >&2; exit 1; }

[ "$#" -ge 2 ] || err "usage: bt-netconfig <iface> <dhcp|static> ..."

IFACE="$1"
MODE="$2"
PROFILE="buttontask-$IFACE"

[[ "$IFACE" =~ ^[A-Za-z0-9_.:-]{1,32}$ ]] || err "invalid interface name"
command -v nmcli >/dev/null 2>&1 || err "nmcli not found"

# Ensure NM manages this interface (manual ip addr fights with NM).
nmcli device set "$IFACE" managed yes 2>/dev/null || true

# Use a dedicated profile per interface so we never fight "Wired connection 1".
if ! nmcli -t -f NAME connection show | grep -Fxq "$PROFILE"; then
    nmcli connection add type ethernet ifname "$IFACE" con-name "$PROFILE" \
        connection.autoconnect yes >/dev/null
fi
CON="$PROFILE"

# Disable autoconnect on other ethernet profiles for this interface.
disable_other_profiles() {
    local iface="$1" con="$2" name bound typ
    while IFS= read -r name; do
        [ -z "$name" ] && continue
        [ "$name" = "$con" ] && continue
        typ="$(nmcli -g connection.type connection show "$name" 2>/dev/null || true)"
        [ "$typ" = "802-3-ethernet" ] || continue
        bound="$(nmcli -g connection.interface-name connection show "$name" 2>/dev/null || true)"
        if [ -n "$bound" ] && [ "$bound" != "--" ] && [ "$bound" != "$iface" ]; then
            continue
        fi
        nmcli connection modify "$name" connection.autoconnect no 2>/dev/null || true
    done < <(nmcli -t -f NAME connection show 2>/dev/null || true)
}

disable_other_profiles "$IFACE" "$CON"

nmcli connection modify "$CON" \
    connection.interface-name "$IFACE" \
    connection.autoconnect yes \
    connection.autoconnect-priority 100

case "$MODE" in
    dhcp)
        nmcli connection modify "$CON" \
            ipv4.method auto \
            ipv4.addresses "" \
            ipv4.gateway "" \
            ipv4.dns "" \
            ipv4.ignore-auto-dns no \
            ipv4.never-default no
        ;;
    static)
        [ "$#" -ge 4 ] || err "static requires <address> <prefix>"
        ADDR="$3"
        PREFIX="$4"
        GW="${5:-}"
        DNS="${6:-}"
        [[ "$PREFIX" =~ ^[0-9]{1,2}$ ]] && [ "$PREFIX" -ge 1 ] && [ "$PREFIX" -le 32 ] \
            || err "invalid prefix"
        if [ -n "$GW" ]; then
            nmcli connection modify "$CON" \
                ipv4.method manual \
                ipv4.addresses "${ADDR}/${PREFIX}" \
                ipv4.gateway "$GW" \
                ipv4.dns "$DNS" \
                ipv4.ignore-auto-dns yes \
                ipv4.never-default no
        else
            nmcli connection modify "$CON" \
                ipv4.method manual \
                ipv4.addresses "${ADDR}/${PREFIX}" \
                ipv4.gateway "" \
                ipv4.dns "$DNS" \
                ipv4.ignore-auto-dns yes \
                ipv4.never-default yes
        fi
        ;;
    *)
        err "mode must be dhcp or static"
        ;;
esac

# Drop the active profile so the new settings apply cleanly.
nmcli device disconnect "$IFACE" 2>/dev/null || true
nmcli connection down "$CON" 2>/dev/null || true

if ! nmcli connection up "$CON" ifname "$IFACE" 2>/dev/null; then
    nmcli connection up "$CON" >/dev/null
fi

# Brief settle, then report what NM actually applied.
sleep 1
APPLIED="$(nmcli -t -f IP4.ADDRESS device show "$IFACE" 2>/dev/null \
    | sed 's/^IP4.ADDRESS://' | head -n1 | tr '\n' ' ')"
echo "applied $MODE on $IFACE ($CON)${APPLIED:+ ip=$APPLIED}"
