#!/usr/bin/env bash
set -euo pipefail

IFACE="${1:-}"
ACTION="${2:-}"

# Run only for wlan0 lifecycle changes where recovery decisions make sense.
case "$ACTION" in
    down|dhcp4-change|connectivity-change|reapply)
        ;;
    *)
        exit 0
        ;;
esac

if [[ "$IFACE" != "wlan0" ]]; then
    exit 0
fi

LOCK_DIR="/run/pins-wifi-recovery.lock"
STATE_FILE="/run/pins-wifi-recovery.failures"
WIFI_CONFIG_FILE="/opt/pinsdaemon/app/wifi_config.json"
WIFI_CONNECT_SCRIPT="/usr/local/bin/wifi-connect.sh"
MANUAL_CONNECT_LOCK_FILE="/run/pins-wifi-connect.lock"
LOG_TAG="pins-wifi-recovery"

MAX_RETRIES="${PINS_WIFI_RECOVERY_MAX_RETRIES:-3}"
BACKOFF_SECONDS="${PINS_WIFI_RECOVERY_BACKOFF_SECONDS:-5}"

log() {
    logger -t "$LOG_TAG" "$*"
}

if ! mkdir "$LOCK_DIR" 2>/dev/null; then
    exit 0
fi
trap 'rmdir "$LOCK_DIR" 2>/dev/null || true' EXIT

if [[ -f "$MANUAL_CONNECT_LOCK_FILE" ]]; then
    # Manual wifi-connect run is in progress; avoid competing NM operations.
    exit 0
fi

is_hotspot_active() {
    nmcli -t -f NAME,TYPE,DEVICE connection show --active 2>/dev/null \
        | awk -F: '$2=="802-11-wireless" && $3=="wlan0" {print $1}' \
        | grep -E '^(Hotspot|hotspot-ap|pins-)' >/dev/null 2>&1
}

is_wifi_client_connected() {
    nmcli -t -f DEVICE,TYPE,STATE device status 2>/dev/null \
        | grep -qE '^wlan0:wifi:connected$'
}

read_autoconnect_config() {
    python3 - "$WIFI_CONFIG_FILE" <<'PY'
import json
import os
import sys

path = sys.argv[1]

if not os.path.exists(path):
    print("0")
    print("")
    print("")
    raise SystemExit(0)

try:
    with open(path, "r", encoding="utf-8") as f:
        data = json.load(f)
except Exception:
    print("0")
    print("")
    print("")
    raise SystemExit(0)

auto_connect = bool(data.get("auto_connect", False))
ssid = data.get("ssid") if isinstance(data.get("ssid"), str) else ""
band = data.get("band") if isinstance(data.get("band"), str) else ""

print("1" if auto_connect and ssid.strip() else "0")
print(ssid.strip())
print(band.strip())
PY
}

normalize_band() {
    case "$1" in
        2.4GHz|bg)
            echo "bg"
            ;;
        5GHz|a)
            echo "a"
            ;;
        *)
            echo ""
            ;;
    esac
}

get_failures() {
    if [[ -f "$STATE_FILE" ]]; then
        cat "$STATE_FILE" 2>/dev/null || echo "0"
    else
        echo "0"
    fi
}

set_failures() {
    printf "%s\n" "$1" > "$STATE_FILE"
}

if is_hotspot_active; then
    set_failures 0
    exit 0
fi

if is_wifi_client_connected; then
    set_failures 0
    exit 0
fi

mapfile -t CFG < <(read_autoconnect_config)
AUTOCONNECT_ENABLED="${CFG[0]:-0}"
TARGET_SSID="${CFG[1]:-}"
TARGET_BAND="$(normalize_band "${CFG[2]:-}")"

if [[ "$AUTOCONNECT_ENABLED" != "1" ]]; then
    log "Wi-Fi disconnected and auto-connect disabled; enabling fallback hotspot"
    "$WIFI_CONNECT_SCRIPT" --hotspot >/dev/null 2>&1 || log "Failed to enable fallback hotspot"
    set_failures 0
    exit 0
fi

FAILURES="$(get_failures)"
if ! [[ "$FAILURES" =~ ^[0-9]+$ ]]; then
    FAILURES=0
fi
FAILURES=$((FAILURES + 1))
set_failures "$FAILURES"

if [[ "$FAILURES" -le "$MAX_RETRIES" ]]; then
    log "Wi-Fi disconnected; reconnect attempt ${FAILURES}/${MAX_RETRIES} to SSID '${TARGET_SSID}'"

    if [[ -n "$TARGET_BAND" ]]; then
        nmcli connection modify "$TARGET_SSID" 802-11-wireless.band "$TARGET_BAND" >/dev/null 2>&1 || true
    fi

    nmcli connection up "$TARGET_SSID" >/dev/null 2>&1 || true
    sleep "$BACKOFF_SECONDS"

    if is_wifi_client_connected; then
        log "Wi-Fi reconnect succeeded"
        set_failures 0
    fi

    exit 0
fi

log "Wi-Fi reconnect failed after ${MAX_RETRIES} attempts; enabling fallback hotspot"
"$WIFI_CONNECT_SCRIPT" --hotspot >/dev/null 2>&1 || log "Failed to enable fallback hotspot"
set_failures 0
exit 0
