#!/usr/bin/env bash
#
# One-off recovery: re-apply internet (filter) rules for every host that is
# supposed to have internet (internet_access = true), straight from the kea DB.
# Use after a reboot flushed iptables and the app:iptables:restore patch is not
# deployed yet. Does NOT restore PAT forwardings (see deploy/ for the patch).
#
# Run as the user allowed to sudo bin/hub-allow (the web user, usually www-data).

set -euo pipefail

APP_DIR="${APP_DIR:-/var/www/html}"
ALLOW_SCRIPT="${ALLOW_SCRIPT:-sudo ${APP_DIR}/bin/hub-allow}"

# Resolve KEA_DATABASE_URL: prefer the environment, else read it from
# .env.local then .env (Symfony precedence).
db_url="${KEA_DATABASE_URL:-}"
if [[ -z "$db_url" ]]; then
    for f in "$APP_DIR/.env.local" "$APP_DIR/.env"; do
        if [[ -f "$f" ]]; then
            line="$(grep -E '^KEA_DATABASE_URL=' "$f" | tail -n1 || true)"
            if [[ -n "$line" ]]; then
                db_url="${line#KEA_DATABASE_URL=}"
                db_url="${db_url%\"}"; db_url="${db_url#\"}"   # strip quotes
                break
            fi
        fi
    done
fi
if [[ -z "$db_url" ]]; then
    echo "ERROR: KEA_DATABASE_URL not set and not found in .env(.local)" >&2
    exit 1
fi

# Strip Doctrine-only query params (serverVersion, charset, ...) that libpq/psql
# rejects. Everything after '?' is dropped; psql uses sane defaults.
db_url="${db_url%%\?*}"

# SQL that turns each internet-enabled host's bytea MAC into a hub-allow command.
sql="
SELECT '${ALLOW_SCRIPT} '
    || regexp_replace(encode(dhcp_identifier, 'hex'), '(..)(?!\$)', '\1:', 'g')
FROM hosts
WHERE internet_access = true
  AND dhcp_identifier IS NOT NULL;"

if ! output="$(psql "$db_url" -tAc "$sql")"; then
    echo "ERROR: psql query failed (see message above)." >&2
    exit 1
fi

commands=()
while IFS= read -r line; do
    [[ -n "$line" ]] && commands+=("$line")
done <<< "$output"

count="${#commands[@]}"
if [[ "$count" -eq 0 ]]; then
    echo "No hosts with internet_access = true. Nothing to do."
    exit 0
fi

echo "About to re-apply internet access to ${count} host(s):"
printf '  %s\n' "${commands[@]}"
echo
read -r -p "Proceed? [y/N] " answer
if [[ ! "$answer" =~ ^[Yy]$ ]]; then
    echo "Aborted."
    exit 0
fi

ok=0; fail=0
for cmd in "${commands[@]}"; do
    # hub-allow does `iptables -C ... || iptables -A ...`; the -C check writes a
    # harmless "Bad rule" line to stderr whenever the ACCEPT rule isn't present
    # yet (the normal post-reboot case) before -A adds it. Capture output and
    # only surface it when the command actually failed (non-zero exit).
    # Note: use $((...)) assignment, not ((var++)), which returns a non-zero
    # exit status when the pre-increment value is 0 and trips `set -e`.
    if out="$(eval "$cmd" 2>&1)"; then
        ok=$((ok + 1))
    else
        fail=$((fail + 1))
        echo "FAILED: $cmd" >&2
        [[ -n "$out" ]] && echo "  $out" >&2
    fi
done

echo "Done. ${ok} applied, ${fail} failed."
[[ "$fail" -eq 0 ]]
