#!/usr/bin/env bash
# BGRTX LIFELINE DNS · pure BASH · KateRTX desk · closed path
# NO python · NO dig@9.9.9.9 · NO pkill -f
# Resolve: getent + resolvectl (OS stub only)
# Serve: cache refresh loop · file cache · not public :53
set -euo pipefail

ROOT="$(cd "$(dirname "$0")/../.." && pwd)"
OUT="$ROOT/out/lifeline"
mkdir -p "$OUT"
LOG="$OUT/lifeline.log"
PIDF="$OUT/lifeline.pid"
CACHE="$OUT/dns_cache.tsv"
KNOW="$OUT/know_all.txt"
HOPS="$OUT/hops_clean.txt"
STATE="$OUT/lifeline_state.txt"

PIN_NAMES=(
  biggrinrtx.com
  www.biggrinrtx.com
  gravatar.com
  api.x.ai
  github.com
  x.com
)

log() {
  local line="[$(date -Iseconds 2>/dev/null || date)] $*"
  printf '%s\n' "$line" | tee -a "$LOG" >/dev/null
  printf '%s\n' "$line"
}

bgf() { echo $(( ($1 - $2) | 1 )); }

# resolve one name via OS only · getent first · resolvectl second
resolve_one() {
  local name="$1" addrs="" a line
  # getent hosts
  while read -r a _; do
    case "$a" in
      [0-9]*.[0-9]*.[0-9]*.[0-9]*) addrs="$addrs $a" ;;
    esac
  done < <(getent hosts "$name" 2>/dev/null || true)
  # getent ahosts
  if [[ -z "${addrs// }" ]]; then
    while read -r a rest; do
      case "$a" in
        [0-9]*.[0-9]*.[0-9]*.[0-9]*) addrs="$addrs $a" ;;
      esac
    done < <(getent ahosts "$name" 2>/dev/null || true)
  fi
  # resolvectl query (system stub · not forced public dig)
  if [[ -z "${addrs// }" ]] && command -v resolvectl >/dev/null 2>&1; then
    while read -r line; do
      case "$line" in
        *": "[0-9]*.[0-9]*.[0-9]*.[0-9]*)
          a="${line##*: }"
          a="${a%% *}"
          addrs="$addrs $a"
          ;;
      esac
    done < <(resolvectl query "$name" 2>/dev/null || true)
  fi
  # uniq
  addrs=$(echo $addrs | tr ' ' '\n' | awk 'NF && !s[$0]++' | tr '\n' ' ')
  echo "${addrs% }"
}

cache_put() {
  local name="$1" addrs="$2" ts
  ts=$(date +%s)
  # remove old lines for name
  if [[ -f "$CACHE" ]]; then
    awk -v n="$name" -F'\t' '$1!=n {print}' "$CACHE" >"$CACHE.tmp" 2>/dev/null || true
    mv -f "$CACHE.tmp" "$CACHE"
  fi
  printf '%s\t%s\t%s\n' "$name" "$ts" "$addrs" >>"$CACHE"
}

cache_get() {
  local name="$1" max_age="${2:-300}" now line ts addrs
  now=$(date +%s)
  [[ -f "$CACHE" ]] || return 1
  while IFS=$'\t' read -r n ts addrs; do
    [[ "$n" == "$name" ]] || continue
    if (( now - ts <= max_age )); then
      echo "$addrs"
      return 0
    fi
  done <"$CACHE"
  return 1
}

cmd_resolve() {
  local name="${1:-biggrinrtx.com}" addrs t0 t1 ms
  if addrs=$(cache_get "$name" 300); then
    log "HIT  $name → $addrs"
    echo "name=$name"
    echo "addrs=$addrs"
    echo "cache=HIT"
    return 0
  fi
  t0=$(date +%s%N)
  addrs=$(resolve_one "$name")
  t1=$(date +%s%N)
  ms=$(( (t1 - t0) / 1000000 ))
  if [[ -n "$addrs" ]]; then
    cache_put "$name" "$addrs"
    log "MISS $name → $addrs ms=$ms via=getent/resolvectl"
    echo "name=$name"
    echo "addrs=$addrs"
    echo "ms=$ms"
    echo "cache=MISS"
    echo "via=OS"
    # know
    echo "$name $addrs $(date -Iseconds)" >>"$KNOW"
  else
    log "FAIL $name"
    echo "name=$name"
    echo "addrs="
    echo "ok=0"
    return 1
  fi
}

cmd_learn() {
  log "LEARN · bash · OS resolve · brand pins"
  local n c=0
  : >"$KNOW.tmp"
  for n in "${PIN_NAMES[@]}"; do
    if cmd_resolve "$n" >/dev/null; then
      c=$((c + 1))
      echo "OK $n" | tee -a "$KNOW.tmp"
    else
      echo "FAIL $n" | tee -a "$KNOW.tmp"
    fi
  done
  {
    echo "LIFELINE KNOW · bash · $(date -Iseconds)"
    echo "law=BGS→BGF→SPV free · no python · no dig@9.9.9.9 · no /usr force"
    echo "pins_ok=$c / ${#PIN_NAMES[@]}"
    echo "know_all=$([[ $c -ge 5 ]] && echo true || echo false)"
    cat "$KNOW.tmp"
  } >"$KNOW"
  rm -f "$KNOW.tmp"
  cmd_hops >/dev/null
  log "LEARN done · pins_ok=$c know_all=$([[ $c -ge 5 ]] && echo true || echo false)"
  cat "$KNOW"
}

cmd_hops() {
  local addrs
  addrs=$(cache_get biggrinrtx.com 600 || resolve_one biggrinrtx.com)
  [[ -n "$addrs" ]] && cache_put biggrinrtx.com "$addrs"
  {
    echo "HOPS CLEAN · bash · $(date -Iseconds)"
    echo "0 desk            Desktop/x lifeline cache file"
    echo "1 os_stub         getent / resolvectl (127.0.0.53 path)"
    echo "2 system_up       OS configured servers · NOT forced 9.9.9.9"
    echo "3 edge_A          $addrs"
    echo "4 site            WordPress.com Atomic · biggrinrtx.com"
    echo "banned            dig@9.9.9.9 · python lifeline · pkill -f · public :53"
  } | tee "$HOPS"
  log "hops clean · a=$addrs"
}

cmd_status() {
  {
    echo "LIFELINE STATUS · bash"
    echo "root=$ROOT"
    echo "out=$OUT"
    echo "pidfile=$PIDF"
    if [[ -f "$PIDF" ]]; then
      local p
      p=$(cat "$PIDF")
      if [[ -d "/proc/$p" ]]; then
        echo "serve=alive pid=$p"
      else
        echo "serve=dead pidfile_stale=$p"
      fi
    else
      echo "serve=stopped"
    fi
    echo "cache_lines=$(wc -l <"$CACHE" 2>/dev/null || echo 0)"
    echo "--- know ---"
    cat "$KNOW" 2>/dev/null || echo "(none)"
    echo "--- hops ---"
    cat "$HOPS" 2>/dev/null || echo "(none)"
  } | tee "$STATE"
}

# serve = forever refresh pin cache · file-based · no UDP python
cmd_serve() {
  set +e
  if [[ -f "$PIDF" ]]; then
    local p
    p=$(cat "$PIDF" 2>/dev/null)
    if [[ -n "$p" && -d "/proc/$p" ]]; then
      echo "already pid=$p"
      exit 0
    fi
    rm -f "$PIDF"
  fi
  echo $$ >"$PIDF"
  log "LIFELINE SERVE start pid=$$ · bash cache loop · closed desk"
  trap 'log "serve stop"; rm -f "$PIDF"; exit 0' TERM INT HUP
  cmd_learn
  while true; do
    for n in "${PIN_NAMES[@]}"; do
      addrs=$(resolve_one "$n")
      if [[ -n "$addrs" ]]; then
        cache_put "$n" "$addrs"
      fi
    done
    echo "LIVE $(date -Iseconds 2>/dev/null || date) pid=$$" >"$OUT/ALWAYS_DNS"
    sleep "${LIFELINE_SLEEP:-30}" || sleep 30
  done
}

cmd_stop() {
  if [[ ! -f "$PIDF" ]]; then
    echo "no pidfile"
    return 0
  fi
  local p
  p=$(cat "$PIDF")
  if [[ -d "/proc/$p" ]]; then
    kill -TERM "$p" 2>/dev/null || true
    sleep 0.2
    if [[ -d "/proc/$p" ]]; then
      kill -KILL "$p" 2>/dev/null || true
    fi
    echo "stopped $p"
  else
    echo "already dead $p"
  fi
  rm -f "$PIDF"
}

cmd="${1:-status}"
shift || true
case "$cmd" in
  resolve|lookup|get) cmd_resolve "${1:-biggrinrtx.com}" ;;
  learn|know) cmd_learn ;;
  hops|clean-hops) cmd_hops ;;
  status|st) cmd_status ;;
  serve|run|start)
    # background via nohup from krtx-dns · if interactive run foreground
    if [[ -t 0 ]]; then
      cmd_serve
    else
      cmd_serve
    fi
    ;;
  stop) cmd_stop ;;
  *)
    echo "lifeline.sh resolve|learn|hops|status|serve|stop"
    exit 2
    ;;
esac
