#!/usr/bin/env bash

set -u

source /usr/bin/pwnlib

LOG_FILE="/var/log/pwnagotchi.log"
CRASH_LOG="/var/log/pwnagotchi_crashes.log"
WATCHDOG_LOG="/var/log/pwnagotchi-syswatchdog.log"
BOOT_GRACE_SECONDS=300
LOG_STALE_SECONDS=600
BETTERCAP_MAX_RESTARTS=3
CPU_TEMP_PAUSE_C=70
CPU_TEMP_RESUME_C=50
CPU_TEMP_HARD_REBOOT_C=85
CPU_HOT_PAUSE_MARKER="/run/pwnagotchi-syswatchdog-hot-pause"
BT_RECOVERY_MARKER="/run/pwnagotchi-syswatchdog-bt-recovery"
PIP_INSTALL_MAX_SECONDS=240
USB0_GATEWAY="10.42.0.1"
UPDATE_MAINTENANCE_MARKER="/run/pwnagotchi-automatic-updates-maintenance"

log() {
    logger -t pwnagotchi-syswatchdog "$1"
    echo "$(date -Is) $1" >> "$WATCHDOG_LOG"
}


reboot_with_reason() {
    reason="$1"
    log "CRITICAL: $reason -- rebooting"
    {
        echo "------------ SYSWATCHDOG REBOOT: $(date -Is) ------------"
        echo "reason: $reason"
        echo "--- systemctl status pwnagotchi ---"
        systemctl status pwnagotchi --no-pager -l 2>&1 | tail -30
        echo "--- systemctl status bettercap ---"
        systemctl status bettercap --no-pager -l 2>&1 | tail -30
        echo "--- dmesg tail ---"
        dmesg | tail -50
        echo
    } >> "$CRASH_LOG" 2>/dev/null
    touch /root/.pwnagotchi-auto 2>/dev/null
    sync
    reboot
}

pip_pid=$(pgrep -f 'pip3 install .*--no-build-isolation' | head -1)
if [ -n "$pip_pid" ]; then
    elapsed=$(ps -o etimes= -p "$pip_pid" 2>/dev/null | tr -d ' ')
    if [ -n "$elapsed" ] && [ "$elapsed" -ge "$PIP_INSTALL_MAX_SECONDS" ]; then
        reboot_with_reason "pip install (pid $pip_pid) running ${elapsed}s >= ${PIP_INSTALL_MAX_SECONDS}s -- confirmed recurring memory-pressure hang on this device"
    fi
fi

uptime_seconds=$(awk '{print int($1)}' /proc/uptime)
if [ "$uptime_seconds" -lt "$BOOT_GRACE_SECONDS" ]; then
    exit 0
fi

if ip link show usb0 >/dev/null 2>&1; then
    if ping -c 2 -W 2 -I usb0 "$USB0_GATEWAY" >/dev/null 2>&1; then
        ip route replace default via "$USB0_GATEWAY" dev usb0 metric 20 2>/dev/null
    elif ip route show default | grep -q "dev usb0"; then
        log "usb0 default route present but gateway $USB0_GATEWAY unreachable -- removing stale route"
        ip route del default via "$USB0_GATEWAY" dev usb0 metric 20 2>/dev/null
    fi
fi

if brcm_hard_failure; then
    recovered=0
    for _ in 1 2 3 4 5 6 7 8; do
        if brcm_chip_alive; then recovered=1; break; fi
        sleep 4
    done
    if [ "$recovered" = 1 ]; then
        if ! ip link show mon0 >/dev/null 2>&1; then
            start_monitor_interface >/dev/null 2>&1
            systemctl restart bettercap >/dev/null 2>&1
            log "brcmfmac crash: chip auto-recovered in place via WL_ON pwrseq -- rebuilt mon0 + restarted bettercap (restores injection+recon), no reboot"
        fi
    else
        if brcm_reboot_allowed; then
            reboot_with_reason "brcmfmac crash and the chip did NOT auto-recover in place within ~32s -- rebooting"
        else
            log "CRITICAL: brcmfmac crash, no in-place recovery, reboot budget exhausted -- staying up degraded so the device stays reachable."
        fi
    fi
    exit 0
fi

if ! check_bt; then
    if [ -f "$BT_RECOVERY_MARKER" ]; then
        log "CRITICAL: bluetooth hci0 still down after an earlier reload_bt attempt this boot -- reload didn't hold, leaving it down (no reboot)"
    else
        log "bluetooth hci0 hardware error detected -- attempting reload_bt (no reboot) ..."
        touch "$BT_RECOVERY_MARKER"
        if reload_bt; then
            log "reload_bt succeeded, hci0 back up"
        else
            log "CRITICAL: reload_bt failed outright -- leaving hci0 down (no reboot)"
        fi
    fi
fi

temp_millic=$(cat /sys/class/thermal/thermal_zone0/temp 2>/dev/null || echo 0)
temp_c=$(( temp_millic / 1000 ))

if [ "$temp_c" -ge "$CPU_TEMP_HARD_REBOOT_C" ]; then
    reboot_with_reason "CPU temp ${temp_c}C >= ${CPU_TEMP_HARD_REBOOT_C}C -- genuinely dangerous, rebooting"
    exit 0
fi

if [ -f "$CPU_HOT_PAUSE_MARKER" ]; then
    if [ "$temp_c" -le "$CPU_TEMP_RESUME_C" ]; then
        log "CPU cooled to ${temp_c}C (<= ${CPU_TEMP_RESUME_C}C) -- resuming"
        rm -f "$CPU_HOT_PAUSE_MARKER"
        systemctl start bettercap
        systemctl start pwnagotchi
    fi
    exit 0
fi

if [ "$temp_c" -ge "$CPU_TEMP_PAUSE_C" ]; then
    log "CPU temp ${temp_c}C >= ${CPU_TEMP_PAUSE_C}C -- pausing until it cools to ${CPU_TEMP_RESUME_C}C"
    touch "$CPU_HOT_PAUSE_MARKER"
    systemctl stop pwnagotchi
    /usr/local/bin/pwnagotchi --show-message "Im too hot... taking a break!" 2>/dev/null
    systemctl stop bettercap
    exit 0
fi

if [ ! -f "$UPDATE_MAINTENANCE_MARKER" ] && [ "$(systemctl is-active bettercap)" != "active" ]; then
    restarts=$(systemctl show bettercap -p NRestarts --value 2>/dev/null || echo 0)
    if [ "${restarts:-0}" -ge "$BETTERCAP_MAX_RESTARTS" ]; then
        reboot_with_reason "bettercap crash-looping (NRestarts=$restarts, currently inactive)"
        exit 0
    fi
fi

if [ ! -f "$UPDATE_MAINTENANCE_MARKER" ] && [ "$(systemctl is-active pwnagotchi)" = "active" ] && [ -f "$LOG_FILE" ]; then
    last_write=$(stat -c %Y "$LOG_FILE" 2>/dev/null || echo 0)
    now=$(date +%s)
    age=$(( now - last_write ))
    if [ "$age" -ge "$LOG_STALE_SECONDS" ]; then
        reboot_with_reason "pwnagotchi.log stale for ${age}s (threshold ${LOG_STALE_SECONDS}s)"
        exit 0
    fi
fi

exit 0
