#!/bin/bash
#
# Dune Weaver Autohotspot
#
# Runs on boot to decide between WiFi client mode and hotspot mode.
# If a known WiFi network is found, connect to it.
# If not, create a "Dune Weaver" hotspot so users can configure WiFi via the app.
#
# Requires: NetworkManager (Pi Trixie), dnsmasq (for DNS redirect in hotspot mode)
#

set -euo pipefail

HOTSPOT_CON_NAME="DuneWeaver-Hotspot"
MODE_FILE="/tmp/dw-wifi-mode"
DNSMASQ_CONF="/etc/dune-weaver/dnsmasq-hotspot.conf"
DNSMASQ_PID="/run/dune-weaver-dnsmasq.pid"
SCAN_TIMEOUT=30
SCAN_INTERVAL=5
IFACE="wlan0"

log() {
    echo "[autohotspot] $*"
    logger -t autohotspot "$*"
}

# Wait for NetworkManager to be ready
wait_for_nm() {
    local waited=0
    while [ $waited -lt 10 ]; do
        if nmcli general status &>/dev/null; then
            return 0
        fi
        sleep 1
        waited=$((waited + 1))
    done
    log "ERROR: NetworkManager not ready after 10s"
    return 1
}

# Get list of saved WiFi connection names
get_saved_wifi() {
    nmcli -t -f NAME,TYPE con show | grep ':.*wireless' | cut -d: -f1 | grep -v "^${HOTSPOT_CON_NAME}$" || true
}

# Scan for available networks and check if any match saved connections
check_for_known_wifi() {
    # Trigger a fresh scan
    nmcli dev wifi rescan ifname "$IFACE" 2>/dev/null || true
    sleep 2

    # Get available SSIDs
    local available
    available=$(nmcli -t -f SSID dev wifi list ifname "$IFACE" 2>/dev/null | sort -u | grep -v '^$' || true)

    if [ -z "$available" ]; then
        return 1
    fi

    # Get saved connections
    local saved
    saved=$(get_saved_wifi)

    if [ -z "$saved" ]; then
        return 1
    fi

    # Check if any saved connection matches an available network
    while IFS= read -r saved_name; do
        # Get the SSID associated with this saved connection
        local saved_ssid
        saved_ssid=$(nmcli -t -f connection.id,802-11-wireless.ssid con show "$saved_name" 2>/dev/null | grep '802-11-wireless.ssid' | cut -d: -f2 || true)

        # If we couldn't get the SSID from connection details, use the connection name as SSID
        if [ -z "$saved_ssid" ]; then
            saved_ssid="$saved_name"
        fi

        if echo "$available" | grep -qxF "$saved_ssid"; then
            echo "$saved_name"
            return 0
        fi
    done <<< "$saved"

    return 1
}

# Activate client mode with a known connection
activate_client_mode() {
    local con_name="$1"
    log "Found known network, activating connection: $con_name"

    # Deactivate hotspot if it's active
    nmcli con down "$HOTSPOT_CON_NAME" 2>/dev/null || true

    # Stop DNS redirect if running
    stop_dns_redirect

    # Connect
    if nmcli con up "$con_name" 2>/dev/null; then
        local ip
        ip=$(nmcli -t -f IP4.ADDRESS dev show "$IFACE" 2>/dev/null | head -1 | cut -d: -f2 | cut -d/ -f1 || echo "unknown")
        log "Client mode active. Connected to '$con_name', IP: $ip"
        echo "client" > "$MODE_FILE"
        return 0
    else
        log "Failed to connect to '$con_name'"
        return 1
    fi
}

# Activate hotspot mode
activate_hotspot_mode() {
    log "No known WiFi found. Activating hotspot mode..."

    # Make sure we're not connected to anything
    nmcli dev disconnect "$IFACE" 2>/dev/null || true

    # Activate the hotspot profile
    if nmcli con up "$HOTSPOT_CON_NAME" 2>/dev/null; then
        log "Hotspot active. SSID: $(nmcli -t -f 802-11-wireless.ssid con show "$HOTSPOT_CON_NAME" 2>/dev/null | cut -d: -f2)"

        # Start DNS redirect for captive portal
        start_dns_redirect

        echo "hotspot" > "$MODE_FILE"
        return 0
    else
        log "ERROR: Failed to activate hotspot"
        return 1
    fi
}

# Start dnsmasq for DNS redirect (captive portal detection)
start_dns_redirect() {
    if [ ! -f "$DNSMASQ_CONF" ]; then
        log "WARNING: dnsmasq config not found at $DNSMASQ_CONF"
        return 1
    fi

    # Kill any existing dnsmasq instance we started
    stop_dns_redirect

    # Start dnsmasq with our config (DNS-only, no DHCP — NM handles DHCP)
    # Use port 53 and bind to hotspot interface
    dnsmasq --conf-file="$DNSMASQ_CONF" \
             --interface="$IFACE" \
             --bind-interfaces \
             --pid-file="$DNSMASQ_PID" \
             --log-facility=/var/log/dune-weaver-dns.log \
             2>/dev/null

    log "DNS redirect started (captive portal mode)"
}

# Stop our dnsmasq instance
stop_dns_redirect() {
    if [ -f "$DNSMASQ_PID" ]; then
        local pid
        pid=$(cat "$DNSMASQ_PID" 2>/dev/null || true)
        if [ -n "$pid" ] && kill -0 "$pid" 2>/dev/null; then
            kill "$pid" 2>/dev/null || true
        fi
        rm -f "$DNSMASQ_PID"
    fi
}

# Main logic
main() {
    log "Starting autohotspot check..."

    # Wait for NetworkManager
    if ! wait_for_nm; then
        log "NetworkManager not available, exiting"
        exit 1
    fi

    # Check if hotspot profile exists
    if ! nmcli con show "$HOTSPOT_CON_NAME" &>/dev/null; then
        log "Hotspot profile '$HOTSPOT_CON_NAME' not found. Run 'dw wifi setup' first."
        echo "client" > "$MODE_FILE"
        exit 0
    fi

    # Scan for known WiFi with timeout
    local elapsed=0
    while [ $elapsed -lt $SCAN_TIMEOUT ]; do
        local match
        if match=$(check_for_known_wifi); then
            activate_client_mode "$match"
            exit 0
        fi

        log "No known WiFi found yet, retrying... (${elapsed}s/${SCAN_TIMEOUT}s)"
        sleep $SCAN_INTERVAL
        elapsed=$((elapsed + SCAN_INTERVAL))
    done

    # No known WiFi found after timeout — go to hotspot mode
    activate_hotspot_mode
}

main "$@"
