#!/usr/bin/env bash
# =============================================================================
#  netbird-fix.sh v3  ·  Datacloud (Antel) - correccion de configuracion
#  macOS + Linux · Soporta NetBird >= 0.52 (profiles) y versiones legacy.
#
#  ALCANCE
#     Este script SOLO corrige el archivo de configuracion del profile.
#     NO inicia sesion: el login SSO lo hace el usuario con 'netbird up'.
#
#  USO
#     sudo ./netbird-fix.sh                 # diagnostica y corrige el profile activo
#     sudo ./netbird-fix.sh --check         # solo diagnostico, no modifica nada
#     sudo ./netbird-fix.sh --profile NAME  # opera sobre un profile puntual
#     sudo ./netbird-fix.sh --user NAME     # profile de otro usuario (si no hay SUDO_USER)
#     sudo ./netbird-fix.sh --reset         # borra el profile y re-enrola de cero
#     sudo ./netbird-fix.sh --bundle        # bundle de debug para soporte
#
#  NOTAS
#   * Desde 0.52 la config NO esta en /etc/netbird/config.json: cada profile es
#     un <id>.json en el state dir (/var/lib/netbird, override con NB_STATE_DIR).
#   * El CLI resuelve el profile del USUARIO que invoca. Correr 'sudo netbird
#     status' devuelve NeedsLogin aunque estes conectado. Por eso este script
#     usa root solo para el servicio y delega el resto a $SUDO_USER.
#   * Siempre deja un backup <config>.json.bak-<fecha> antes de tocar nada.
#     Ese backup contiene la clave privada del peer: borralo cuando termines.
#   * --reset genera clave nueva -> peer NUEVO -> re-aprobacion del admin.
# =============================================================================
set -uo pipefail

SCRIPT_VERSION="3.0"

MGMT_URL="https://acceso.data.antelcloud.uy:443"
MGMT_HOST="acceso.data.antelcloud.uy"
SSO_HOST="sso.data.antelcloud.uy"
WG_PORT="51820"
WG_MTU="1280"
IP_PREFIX="100.66."
MODE="repair"
WANT_PROFILE=""
WANT_USER=""
ASSUME_YES=0

# ----------------------------------------------------------------- salida ---
if [ -t 1 ]; then
  C_R=$'\033[31m'; C_G=$'\033[32m'; C_Y=$'\033[33m'; C_B=$'\033[36m'; C_D=$'\033[2m'; C_0=$'\033[0m'
else C_R=""; C_G=""; C_Y=""; C_B=""; C_D=""; C_0=""; fi
info(){ printf '%s[i]%s  %s\n'  "$C_B" "$C_0" "$*"; }
ok()  { printf '%s[OK]%s %s\n'  "$C_G" "$C_0" "$*"; }
warn(){ printf '%s[!]%s  %s\n'  "$C_Y" "$C_0" "$*"; }
err() { printf '%s[X]%s  %s\n'  "$C_R" "$C_0" "$*" >&2; }
dim() { printf '%s     %s%s\n'  "$C_D" "$*" "$C_0"; }
hdr() { printf '\n%s=== %s ===%s\n' "$C_B" "$*" "$C_0"; }

usage(){
  cat <<'EOF'
netbird-fix.sh - corrige la configuracion del cliente NetBird (Datacloud/Antel)

  sudo ./netbird-fix.sh                 diagnostica y corrige el profile activo
  sudo ./netbird-fix.sh --check         solo diagnostico, no modifica nada
  sudo ./netbird-fix.sh --profile NAME  opera sobre un profile puntual
  sudo ./netbird-fix.sh --user NAME     profile de otro usuario (si no hay SUDO_USER)
  sudo ./netbird-fix.sh --reset         borra el profile y re-enrola de cero
  sudo ./netbird-fix.sh --bundle        bundle de debug para soporte
  sudo ./netbird-fix.sh -m URL          usa otra Management URL
  sudo ./netbird-fix.sh --yes           no pregunta en --reset

El script solo corrige configuracion. El login SSO lo hace el usuario despues,
sin sudo, con:  netbird up
EOF
  exit 0
}

while [ $# -gt 0 ]; do
  case "$1" in
    --check)   MODE="check" ;;
    --reset)   MODE="reset" ;;
    --bundle)  MODE="bundle" ;;
    --yes|-y)  ASSUME_YES=1 ;;
    --profile) WANT_PROFILE="${2:-}"; shift ;;
    --user)    WANT_USER="${2:-}"; shift ;;
    -m|--mgmt) MGMT_URL="${2:-}"; shift
               MGMT_HOST="$(printf '%s' "$MGMT_URL" | sed -E 's#^https?://##; s#[:/].*$##')" ;;
    -h|--help) usage ;;
    *) err "opcion desconocida: $1"; exit 2 ;;
  esac; shift
done

[ "$(id -u)" -ne 0 ] && { err "Correlo con sudo:  sudo $0"; exit 1; }

# ------------------------------------------------- contexto de usuario real --
RUN_USER="${WANT_USER:-${SUDO_USER:-root}}"
if [ "$RUN_USER" = "root" ]; then
  warn "Sin SUDO_USER: voy a mirar el profile de root."
  dim  "Si el profile es de un usuario comun, corre:  sudo $0 --user <usuario>"
fi
if ! id "$RUN_USER" >/dev/null 2>&1; then err "El usuario '$RUN_USER' no existe."; exit 1; fi
USER_HOME="$(eval echo "~$RUN_USER" 2>/dev/null)"; [ -d "$USER_HOME" ] || USER_HOME="/root"

OS="$(uname -s)"
case "$OS" in
  Darwin) PLAT="macOS"; WG_IFACE="utun100" ;;
  Linux)  PLAT="Linux"; WG_IFACE="wt0" ;;
  *) err "SO no soportado: $OS"; exit 1 ;;
esac

NB=""
for c in "$(command -v netbird 2>/dev/null || true)" \
         /usr/bin/netbird /usr/local/bin/netbird /opt/homebrew/bin/netbird \
         /Applications/NetBird.app/Contents/MacOS/netbird; do
  [ -n "$c" ] && [ -x "$c" ] && { NB="$c"; break; }
done
[ -z "$NB" ] && { err "No encontre el binario 'netbird'."; dim "https://app.netbird.io/install"; exit 1; }

# nbu = netbird en el contexto del usuario real (los profiles son per-user)
nbu(){
  if [ "$RUN_USER" != "root" ]; then sudo -H -u "$RUN_USER" "$NB" "$@"
  else "$NB" "$@"; fi
}

has_cmd(){ command -v "$1" >/dev/null 2>&1; }
HAS_PROFILES=0; "$NB" profile --help >/dev/null 2>&1 && HAS_PROFILES=1

# ------------------------------------------- descubrimiento del state dir ----
STATE_DIRS=()
[ -n "${NB_STATE_DIR:-}" ] && STATE_DIRS+=("$NB_STATE_DIR")
STATE_DIRS+=(/var/lib/netbird /usr/local/var/lib/netbird /opt/homebrew/var/lib/netbird
             "$USER_HOME/.config/netbird" /etc/netbird)

find_json(){ # find_json <nombre> -> primera coincidencia en los state dirs
  local n="$1" d f
  for d in "${STATE_DIRS[@]}"; do
    [ -d "$d" ] || continue
    f="$(find "$d" -maxdepth 3 -type f -name "$n" 2>/dev/null | head -1)"
    [ -n "$f" ] && { printf '%s' "$f"; return 0; }
  done
  return 1
}
list_profile_files(){
  local d
  for d in "${STATE_DIRS[@]}"; do
    [ -d "$d" ] || continue
    find "$d" -maxdepth 3 -type f -name '*.json' 2>/dev/null \
      | grep -vE '\.state\.json$|/active_profile\.json$|/service\.json$|/profiles\.json$'
  done | sort -u
}

# ------------------------------------------------ profile activo + config ---
# La columna ACTIVE ('v') hace que la fila del profile activo tenga 3 campos;
# las inactivas tienen 2. Por eso NF>=3 identifica al activo.
PROF_ID=""; PROF_NAME=""; CFG=""; PLIST=""
if [ "$HAS_PROFILES" -eq 1 ]; then
  PLIST="$(nbu profile list --show-id 2>/dev/null)"
  if [ -n "$WANT_PROFILE" ]; then
    LINE="$(printf '%s\n' "$PLIST" | awk -v w="$WANT_PROFILE" 'NR>1 && ($1==w || $2==w){print $1"|"$2; exit}')"
    [ -z "$LINE" ] && { err "No existe el profile '$WANT_PROFILE'."; printf '%s\n' "$PLIST" | sed 's/^/     /'; exit 1; }
  else
    LINE="$(printf '%s\n' "$PLIST" | awk 'NR>1 && NF>=3 {print $1"|"$2; exit}')"
  fi
  PROF_ID="${LINE%%|*}"; PROF_NAME="${LINE##*|}"
  [ -n "$PROF_ID" ] && CFG="$(find_json "${PROF_ID}.json" || true)"
fi
# legacy y fallbacks: nunca elegir "el primero que aparezca" si hay varios
if [ -z "$CFG" ] && [ -f /etc/netbird/config.json ]; then CFG="/etc/netbird/config.json"; fi
if [ -z "$CFG" ]; then
  CANDIDATES="$(list_profile_files)"
  NCAND="$(printf '%s\n' "$CANDIDATES" | grep -c . )"
  if [ "$NCAND" -eq 1 ]; then CFG="$CANDIDATES"
  elif [ "$NCAND" -gt 1 ]; then
    err "No pude resolver el profile activo y hay $NCAND configs en disco:"
    printf '%s\n' "$CANDIDATES" | sed 's/^/       /'
    dim "Elegi una con:  sudo $0 --profile <NAME>   (o --user <usuario>)"
    exit 1
  fi
fi

# ------------------------------------------------------- lectura de config ---
cfg_str(){  [ -f "$CFG" ] && sed -nE "s/.*\"$1\"[[:space:]]*:[[:space:]]*\"([^\"]*)\".*/\1/p" "$CFG" | head -1; }
cfg_num(){  [ -f "$CFG" ] && sed -nE "s/.*\"$1\"[[:space:]]*:[[:space:]]*([0-9]+).*/\1/p" "$CFG" | head -1; }
cfg_bool(){ [ -f "$CFG" ] && sed -nE "s/.*\"$1\"[[:space:]]*:[[:space:]]*(true|false).*/\1/p" "$CFG" | head -1; }
cfg_mtu_key(){ [ -f "$CFG" ] && sed -nE 's/.*"([A-Za-z]*MTU)"[[:space:]]*:[[:space:]]*[0-9]+.*/\1/p' "$CFG" | head -1; }

# ManagementURL es un url.URL serializado: hay que leer Host/Scheme DENTRO de
# ese objeto, no el primer "Host" del archivo (AdminURL tiene el suyo).
cfg_mgmt_field(){ # cfg_mgmt_field Host|Scheme
  [ -f "$CFG" ] || return 1
  awk -v key="$1" '
    $0 ~ /"ManagementURL"[[:space:]]*:/ { inb=1 }
    inb && match($0, "\"" key "\"[[:space:]]*:[[:space:]]*\"[^\"]*\"") {
      s = substr($0, RSTART, RLENGTH)
      sub("^\"" key "\"[[:space:]]*:[[:space:]]*\"", "", s); sub("\"$", "", s)
      print s; exit
    }
    inb && /}/ { inb=0 }
  ' "$CFG"
}
norm_host(){ printf '%s' "$1" | sed -E 's/:443$//'; }

json_ok(){ # valida que el archivo siga siendo JSON parseable
  if has_cmd python3; then python3 -c 'import json,sys; json.load(open(sys.argv[1]))' "$1" >/dev/null 2>&1; return $?
  elif has_cmd jq; then jq -e . "$1" >/dev/null 2>&1; return $?
  fi
  return 0
}
has_validator(){ has_cmd python3 || has_cmd jq; }

# ------------------------------------------------------------- red/servicio --
tcp_check(){ # 0 = ok, 2 = TLS no confiable, 1 = inalcanzable
  local h="$1" p="$2" code errf rc
  if has_cmd curl; then
    errf="$(mktemp)"
    code="$(curl -sS --max-time 8 -o /dev/null -w '%{http_code}' "https://$h/" 2>"$errf")"
    rc=1
    if printf '%s' "$code" | grep -qE '^[1-5][0-9][0-9]$'; then rc=0
    elif grep -qiE 'certificate|self.signed|SSL' "$errf"; then rc=2; fi
    rm -f "$errf"
    return $rc
  fi
  (exec 3<>"/dev/tcp/$h/$p") 2>/dev/null && { exec 3>&-; return 0; }
  return 1
}
dns_check(){
  local h="$1"
  has_cmd dig      && { dig +short +time=3 "$h" | grep -qE '^[0-9]+\.'; return $?; }
  has_cmd host     && { host -W 3 "$h" >/dev/null 2>&1; return $?; }
  has_cmd nslookup && { nslookup "$h" >/dev/null 2>&1; return $?; }
  has_cmd getent   && { getent hosts "$h" >/dev/null 2>&1; return $?; }
  return 0
}

# OJO: 'netbird status' sale con codigo 1 tambien cuando el daemon esta vivo
# pero Management no conecta. Para saber si el daemon esta arriba hay que
# mirar el mensaje, no el exit code.
daemon_up(){
  local o; o="$(nbu status 2>&1)"
  printf '%s' "$o" | grep -qi 'failed to connect to daemon' && return 1
  return 0
}
svc_stop(){
  nbu down >/dev/null 2>&1 || true
  if [ "$PLAT" = "Linux" ]; then
    systemctl stop netbird >/dev/null 2>&1 || "$NB" service stop >/dev/null 2>&1 || true
  else
    "$NB" service stop >/dev/null 2>&1 || true
    for p in /Library/LaunchDaemons/*netbird*.plist; do [ -f "$p" ] && launchctl unload "$p" >/dev/null 2>&1; done
  fi
  sleep 2
}
svc_start(){
  if [ "$PLAT" = "Linux" ]; then
    systemctl start netbird >/dev/null 2>&1 || "$NB" service start >/dev/null 2>&1 || true
  else
    for p in /Library/LaunchDaemons/*netbird*.plist; do [ -f "$p" ] && launchctl load "$p" >/dev/null 2>&1; done
    "$NB" service start >/dev/null 2>&1 || true
  fi
  local i=0
  while [ $i -lt 20 ]; do daemon_up && return 0; sleep 1; i=$((i+1)); done
  return 1
}

# ------------------------------------------------------------- diagnostico ---
QUIET=0
q_ok()  { [ "$QUIET" -eq 1 ] || ok   "$@"; }
q_warn(){ [ "$QUIET" -eq 1 ] || warn "$@"; }
q_err() { [ "$QUIET" -eq 1 ] || err  "$@"; }

BAD=0
diagnose(){
  BAD=0
  if [ -z "$CFG" ] || [ ! -f "$CFG" ]; then
    q_warn "No encontre el archivo de config del profile."
    BAD=1; return 1
  fi
  local exp_host cur_host cur_scheme cur_if cur_port mtu_key cur_mtu k

  exp_host="$(printf '%s' "$MGMT_URL" | sed -E 's#^https?://##; s#/.*$##')"
  cur_host="$(cfg_mgmt_field Host || true)"
  if [ "$(norm_host "$cur_host")" = "$(norm_host "$exp_host")" ]; then
    q_ok "ManagementURL = ${cur_host}"
  else
    q_err "ManagementURL = '${cur_host:-vacio}'  (esperado: $exp_host)"; BAD=1
  fi

  cur_scheme="$(cfg_mgmt_field Scheme || true)"
  if [ "$cur_scheme" = "https" ]; then q_ok "ManagementURL scheme = https"
  else q_err "ManagementURL scheme = '${cur_scheme:-vacio}'  (esperado: https)"; BAD=1; fi

  if [ -z "$(cfg_str PreSharedKey)" ]; then q_ok "Pre-shared Key vacia (correcto)"
  else q_err "Pre-shared Key CARGADA - no corresponde en Datacloud"; BAD=1; fi

  cur_if="$(cfg_str WgIface)"
  if [ "$cur_if" = "$WG_IFACE" ]; then q_ok "Interface Name = $cur_if"
  else q_warn "Interface Name = '${cur_if:-?}'  (esperado: $WG_IFACE)"; BAD=1; fi

  cur_port="$(cfg_num WgPort)"
  if [ "$cur_port" = "$WG_PORT" ]; then q_ok "Interface Port = $cur_port"
  else q_warn "Interface Port = '${cur_port:-?}'  (esperado: $WG_PORT)"; BAD=1; fi

  mtu_key="$(cfg_mtu_key)"
  if [ -n "$mtu_key" ]; then
    cur_mtu="$(cfg_num "$mtu_key")"
    if [ "$cur_mtu" = "$WG_MTU" ]; then q_ok "MTU = $cur_mtu"
    else q_warn "MTU = '${cur_mtu:-?}'  (esperado: $WG_MTU)"; BAD=1; fi
  fi

  for k in RosenpassEnabled RosenpassPermissive; do
    [ "$(cfg_bool "$k")" = "true" ] && { q_err "$k = true (debe ser false)"; BAD=1; }
  done

  [ "$BAD" -eq 0 ] && q_ok "El profile esta bien armado."
  return "$BAD"
}

# -------------------------------------------------------------- correccion ---
patch_config(){ # reescribe $CFG in-place; 0 = ok, 1 = no se aplico
  local tmp tmp2 exp_host rc
  exp_host="$(printf '%s' "$MGMT_URL" | sed -E 's#^https?://##; s#/.*$##')"
  # mktemp crea con 0600: los temporales llevan la clave privada del peer
  tmp="$(mktemp)"  || return 1
  tmp2="$(mktemp)" || { rm -f "$tmp"; return 1; }

  # NetBird escribe el JSON indentado. Si viniera minificado, ManagementURL y
  # AdminURL caerian en la misma linea y el patch podria tocar el Host errado.
  if grep '"ManagementURL"' "$CFG" | head -1 | grep -q '"AdminURL"'; then
    err "La config esta minificada: no la puedo parchear con seguridad."
    dim "Corregila a mano o usa --reset."
    rm -f "$tmp" "$tmp2"; return 1
  fi

  # 1) ManagementURL: solo dentro de su propio objeto
  awk -v h="$exp_host" '
    $0 ~ /"ManagementURL"[[:space:]]*:/ { inb=1 }
    inb {
      if ($0 ~ /"Host"[[:space:]]*:/)   { sub(/"Host"[[:space:]]*:[[:space:]]*"[^"]*"/,   "\"Host\": \""   h "\"") }
      if ($0 ~ /"Scheme"[[:space:]]*:/) { sub(/"Scheme"[[:space:]]*:[[:space:]]*"[^"]*"/, "\"Scheme\": \"https\"") }
    }
    inb && /}/ { inb=0 }
    { print }
  ' "$CFG" > "$tmp" || { rm -f "$tmp" "$tmp2"; return 1; }

  # 2) resto de campos escalares
  sed -E \
    -e 's/"PreSharedKey"[[:space:]]*:[[:space:]]*"[^"]*"/"PreSharedKey": ""/' \
    -e 's/"(RosenpassEnabled|RosenpassPermissive)"[[:space:]]*:[[:space:]]*true/"\1": false/' \
    -e "s/\"WgPort\"[[:space:]]*:[[:space:]]*[0-9]+/\"WgPort\": ${WG_PORT}/" \
    -e "s/\"WgIface\"[[:space:]]*:[[:space:]]*\"[^\"]*\"/\"WgIface\": \"${WG_IFACE}\"/" \
    -e "s/\"([A-Za-z]*MTU)\"[[:space:]]*:[[:space:]]*[0-9]+/\"\1\": ${WG_MTU}/" \
    "$tmp" > "$tmp2" || { rm -f "$tmp" "$tmp2"; return 1; }

  if ! json_ok "$tmp2"; then
    err "El patch dejo un JSON invalido: no lo aplico."
    rm -f "$tmp" "$tmp2"; return 1
  fi
  # 'cat >' preserva duenio y permisos del archivo original
  cat "$tmp2" > "$CFG"; rc=$?
  rm -f "$tmp" "$tmp2"
  return $rc
}

next_steps(){
  hdr "Siguiente paso (lo hace el usuario, SIN sudo)"
  info "Iniciar sesion contra el SSO de Datacloud:"
  dim  "netbird up"
  dim  "El navegador abre https://$SSO_HOST -> boton 'Datacloud SSO'."
  dim  "Sin entorno grafico:  netbird up --no-browser   (o --qr)"
  dim  "Verificar despues con: netbird status"
  echo
  dim  "Si queda sin IP, el peer esta pendiente de aprobacion del administrador."
}

# =============================================================== DIAGNOSTICO =
hdr "Entorno"
info "Script      : netbird-fix v$SCRIPT_VERSION (solo configuracion)"
info "Plataforma  : $PLAT ($(uname -m))"
info "Binario     : $NB"
info "Version     : $("$NB" version 2>/dev/null | head -1)"
info "Usuario     : $RUN_USER"
if [ "$HAS_PROFILES" -eq 1 ]; then
  info "Profiles    : soportados"
  printf '%s\n' "$PLIST" | sed 's/^/     /'
  [ -n "$PROF_ID" ] && info "Profile obj.: $PROF_NAME ($PROF_ID)" || warn "No pude resolver el profile activo."
else
  info "Profiles    : no soportados (cliente legacy)"
fi
info "Config      : ${CFG:-<no encontrada>}"
has_validator || dim "Sin python3 ni jq: no puedo validar el JSON resultante (queda el backup)."

hdr "Conectividad a la plataforma"
PREFLIGHT_OK=1
for h in "$MGMT_HOST" "$SSO_HOST"; do
  dns_check "$h" && ok "DNS resuelve $h" || { err "DNS NO resuelve $h"; PREFLIGHT_OK=0; }
  tcp_check "$h" 443; case $? in
    0) ok "TLS/443 alcanzable en $h" ;;
    2) err "TLS rechazado en $h: cadena no confiable (CA privada o proxy que intercepta)"; PREFLIGHT_OK=0 ;;
    *) err "No llego a https://$h (firewall/proxy)"; PREFLIGHT_OK=0 ;;
  esac
done

hdr "Configuracion del profile"
diagnose
if [ "$BAD" -ne 0 ] && { [ -z "$CFG" ] || [ ! -f "$CFG" ]; }; then
  dim "Profiles detectados en disco:"; list_profile_files | sed 's/^/       /'
fi

hdr "Estado del daemon (como $RUN_USER)"
ST="$(nbu status -d 2>&1)"; printf '%s\n' "$ST" | sed 's/^/     /'
# Anclado a ^ : las lineas de los peers vienen indentadas y aparecen ANTES
CONNECTED=0; printf '%s\n' "$ST" | grep -qE '^Management: +Connected' && CONNECTED=1
DSTATUS="$(printf '%s\n' "$ST" | sed -nE 's/^Daemon status:[[:space:]]*([A-Za-z]+).*/\1/p' | head -1)"
NB_IP="$(printf '%s\n' "$ST" | sed -nE 's/^NetBird IP:[[:space:]]*([0-9.]+).*/\1/p' | head -1)"

session_verdict(){
  # 'Daemon status:' SOLO se imprime si falta login; conectado no aparece.
  if [ "$CONNECTED" -eq 1 ]; then
    ok "SESION: conectado."
    if [ -n "$NB_IP" ]; then
      case "$NB_IP" in
        ${IP_PREFIX}*) ok "IP asignada: $NB_IP (rango correcto)" ;;
        *) warn "IP asignada: $NB_IP - fuera de $IP_PREFIX, revisar tenant." ;;
      esac
    else
      warn "Sin IP asignada: peer pendiente de aprobacion del administrador."
    fi
    return
  fi
  if ! daemon_up; then
    err "SESION: el daemon no responde."
    dim "Linux: systemctl status netbird ; journalctl -u netbird -n 100 --no-pager"
    dim "macOS: sudo log show --predicate 'process == \"netbird\"' --last 10m"
    return
  fi
  case "$DSTATUS" in
    NeedsLogin|SessionExpired|LoginFailed)
      warn "SESION: falta iniciar sesion ($DSTATUS)."
      [ "$BAD" -eq 0 ] && dim "No es un problema de configuracion: alcanza con 'netbird up'." ;;
    Disconnected|Idle)
      warn "SESION: desconectado ($DSTATUS). Levantar con:  netbird up" ;;
    *)
      warn "SESION: Management no conectado${DSTATUS:+ (estado $DSTATUS)}." ;;
  esac
}

# ==================================================================== MODOS ==
case "$MODE" in
  check)
    hdr "Resultado"
    if [ "$BAD" -eq 0 ]; then ok "CONFIG: correcta, nada que corregir."
    else err "CONFIG: hay desvios. Corregir con:  sudo $0"; fi
    if [ "$PREFLIGHT_OK" -eq 1 ]; then ok "RED: acceso y sso alcanzables."
    else err "RED: no llegas a la plataforma. Resolver DNS/proxy/firewall primero."; fi
    session_verdict
    [ "$BAD" -eq 0 ] && exit 0 || exit 1 ;;

  bundle)
    hdr "Bundle de debug"
    if nbu debug --help >/dev/null 2>&1; then
      nbu debug bundle 2>&1 && ok "Mandale a soporte el .zip que aparece arriba."
    else
      OUT="/tmp/netbird-support-$(date +%Y%m%d-%H%M%S).txt"
      (umask 077
       { echo "== version =="; "$NB" version 2>&1
         echo; echo "== profiles =="; nbu profile list --show-id 2>&1
         echo; echo "== status -d =="; nbu status -d 2>&1
         echo; echo "== config (redactado) =="
         [ -f "$CFG" ] && sed -E 's/("PrivateKey"|"PreSharedKey")[[:space:]]*:[[:space:]]*"[^"]*"/\1: "REDACTED"/' "$CFG"
       } > "$OUT" 2>&1)
      chmod 600 "$OUT" 2>/dev/null
      ok "Reporte en $OUT"
    fi
    exit 0 ;;
esac

# ================================================================ CORRECCION =
if [ "$MODE" = "reset" ]; then
  hdr "Reset del profile"
  if [ -z "$CFG" ] || [ ! -f "$CFG" ]; then err "No hay config para borrar."; exit 1; fi
  warn "Se borra la identidad del peer -> clave nueva -> re-aprobacion del admin."
  dim  "Archivo: $CFG"
  if [ "$ASSUME_YES" -ne 1 ]; then
    printf '     Escribi BORRAR para confirmar: '; read -r ANSWER
    [ "$ANSWER" = "BORRAR" ] || { info "Cancelado."; exit 0; }
  fi
  info "Parando servicio..."; svc_stop
  BK="${CFG}.bak-$(date +%Y%m%d-%H%M%S)"; cp -p "$CFG" "$BK" && ok "Backup en $BK"
  rm -f "$CFG" "${CFG%.json}.state.json"
  ok "Profile eliminado del disco."
  info "Arrancando servicio..."
  svc_start && ok "Daemon arriba." || { err "El daemon no levanto."; exit 1; }
  next_steps
  exit 0
fi

hdr "Correccion de la configuracion"
if [ -z "$CFG" ] || [ ! -f "$CFG" ]; then
  err "No hay archivo de config para corregir."
  dim "Si el cliente nunca se enrolo, corre directamente:  netbird up"
  dim "Si el profile es de otro usuario:  sudo $0 --user <usuario>"
  exit 1
fi
if [ "$BAD" -eq 0 ]; then
  ok "La config ya esta correcta: no toco nada ni reinicio el servicio."
  session_verdict
  [ "$CONNECTED" -eq 1 ] || next_steps
  exit 0
fi

info "Parando servicio (para que el daemon no pise el archivo)..."
svc_stop; ok "Servicio detenido."

BK="${CFG}.bak-$(date +%Y%m%d-%H%M%S)"
cp -p "$CFG" "$BK" && ok "Backup en $BK"

info "Normalizando campos del profile..."
if patch_config; then
  ok "Config reescrita."
else
  err "No pude aplicar la correccion. La config quedo como estaba."
  dim "Backup intacto en $BK"
  svc_start >/dev/null 2>&1
  exit 1
fi

if [ "$PLAT" = "Linux" ] && ip link show "$WG_IFACE" >/dev/null 2>&1; then
  ip link delete "$WG_IFACE" >/dev/null 2>&1 && ok "Interfaz huerfana $WG_IFACE eliminada."
fi

info "Arrancando servicio..."
if svc_start; then ok "Daemon arriba."; else
  err "El daemon no levanto."
  dim "Linux: journalctl -u netbird -n 100 --no-pager"
  dim "macOS: sudo log show --predicate 'process == \"netbird\"' --last 10m"
  exit 1
fi

hdr "Verificacion (releo el archivo de disco)"
diagnose
if [ "$BAD" -eq 0 ]; then
  ok "Configuracion corregida."
  next_steps
  exit 0
else
  err "Quedaron desvios que no pude corregir automaticamente."
  dim "Revisa a mano: $CFG   (backup: $BK)"
  dim "Ultimo recurso: sudo $0 --reset   (requiere re-aprobacion del admin)"
  dim "Para soporte:   sudo $0 --bundle"
  exit 1
fi
