#!/usr/bin/env bash
#
# Installeur DenyGrid ↔ MikroTik connector — Debian / Ubuntu.
#
# Détecte automatiquement le mode :
#   • ROOT  (lancé en root, via sudo OU `su -` si pas de sudo) → install système,
#            service systemd + utilisateur dédié 'denygrid'.
#   • USER  (lancé sans privilèges)                            → install dans $HOME,
#            dépendances via venv/pip, service systemd --user (repli cron @reboot).
#
# Usage :
#   sudo ./install.sh            # ou, sans sudo :  su -  puis  ./install.sh
#   ./install.sh                 # en utilisateur simple (sans aucun root)
#   ./install.sh --user          # forcer le mode utilisateur même en root
#   ./install.sh --no-config     # ne pas générer de config (copie l'exemple)
#   ./install.sh --uninstall     # désinstaller
#
set -euo pipefail

SVC_NAME="denygrid-mikrotik"
SRC_DIR="$(cd "$(dirname "$0")" && pwd)"

c()  { printf '\033[1;36m%s\033[0m\n' "$*"; }
ok() { printf '\033[1;32m✓ %s\033[0m\n' "$*"; }
warn(){ printf '\033[1;33m! %s\033[0m\n' "$*"; }
err(){ printf '\033[1;31m✗ %s\033[0m\n' "$*" >&2; }

# Base de téléchargement (surchargeable) — utilisée quand on lance via `curl | bash`
DG_BASE="${DG_BASE:-https://denygrid.com/client/mikrotik-connector}"

# Télécharge une URL vers un fichier (curl ou wget)
dl() {
    if command -v curl >/dev/null 2>&1; then curl -fsSL "$1" -o "$2"
    elif command -v wget >/dev/null 2>&1; then wget -qO "$2" "$1"
    else return 1; fi
}

# Récupère un fichier : on privilégie TOUJOURS la dernière version du serveur
# (le connecteur doit matcher le serveur), repli sur la copie locale si le
# téléchargement échoue (install hors-ligne depuis un dossier extrait).
fetch() {
    local f="$1" mode="${2:-0644}" dest
    dest="$INSTALL_DIR/$f"
    if dl "$DG_BASE/$f" "$dest"; then
        chmod "$mode" "$dest"
    elif [ -f "$SRC_DIR/$f" ]; then
        install -m "$mode" "$SRC_DIR/$f" "$dest"
    else
        err "Impossible d'obtenir $f (ni via $DG_BASE, ni localement)"; exit 1
    fi
}

# URL de l'API DenyGrid par défaut, dérivée du domaine de téléchargement
default_api_url() { printf '%s' "$DG_BASE" | sed 's#/client/.*#/api#'; }

# Écrit une config de base (sans routeur)
write_base_config() {  # <fichier> <url> <cle>
    F="$1" U="$2" K="$3" python3 - <<'PY'
import json, os
json.dump({
    "denygrid_url": os.environ["U"].rstrip("/"),
    "enrollment_key": os.environ["K"].strip(),
    "verify_tls": True, "poll_interval": 60, "log_level": "INFO",
    "routers": [],
}, open(os.environ["F"], "w"), indent=2)
PY
}

# Demande les infos d'un routeur et l'ajoute au tableau "routers" de la config
prompt_router() {  # <fichier_config>
    local F="$1"
    read -rp "    Nom (alias)          : " R_NAME || true
    read -rp "    Hôte / IP            : " R_HOST || true
    read -rp "    Port API [8729]      : " R_PORT || true; R_PORT="${R_PORT:-8729}"
    read -rp "    Utilisateur RouterOS : " R_USER || true
    read -rsp "    Mot de passe         : " R_PASS || true; echo
    read -rp "    Vérifier TLS ? [o/N] : " R_VTLS || true
    case "${R_VTLS:-}" in [oOyY]*) R_VTLS=true ;; *) R_VTLS=false ;; esac
    NAME="$R_NAME" HOST="$R_HOST" PORT="$R_PORT" RUSER="$R_USER" PASS="$R_PASS" VTLS="$R_VTLS" \
    python3 - "$F" <<'PY'
import json, os, sys
f = sys.argv[1]
cfg = json.load(open(f))
cfg.setdefault("routers", []).append({
    "name": os.environ["NAME"], "host": os.environ["HOST"],
    "api_port": int(os.environ["PORT"] or 443), "username": os.environ["RUSER"],
    "password": os.environ["PASS"], "verify_tls": os.environ["VTLS"] == "true",
})
json.dump(cfg, open(f, "w"), indent=2)
PY
    ok "routeur '${R_NAME:-?}' ajouté"
}

# --- options ---
FORCE_USER=0; NO_CONFIG=0; UNINSTALL=0; ADD_ROUTER=0
for a in "$@"; do
    case "$a" in
        --user) FORCE_USER=1 ;;
        --no-config) NO_CONFIG=1 ;;
        --uninstall) UNINSTALL=1 ;;
        --add-router) ADD_ROUTER=1 ;;
    esac
done

# --- détection du mode ---
if [ "$(id -u)" -eq 0 ] && [ "$FORCE_USER" -eq 0 ]; then
    MODE="root"
    INSTALL_DIR="/opt/denygrid-mikrotik"
    SVC_USER="denygrid"
    UNIT_DIR="/etc/systemd/system"
    SCTL="systemctl"
else
    MODE="user"
    INSTALL_DIR="$HOME/denygrid-mikrotik"
    SVC_USER="$(id -un)"
    UNIT_DIR="$HOME/.config/systemd/user"
    SCTL="systemctl --user"
fi
CONFIG="$INSTALL_DIR/config.json"
STATE="$INSTALL_DIR/state.json"
PYTHON="$(command -v python3 || true)"

# --------------------------------------------------------------------------- #
#  Désinstallation
# --------------------------------------------------------------------------- #
if [ "$UNINSTALL" -eq 1 ]; then
    c "== Désinstallation (mode $MODE) =="
    $SCTL disable --now "$SVC_NAME" 2>/dev/null || true
    rm -f "$UNIT_DIR/${SVC_NAME}.service"; $SCTL daemon-reload 2>/dev/null || true
    ( crontab -l 2>/dev/null | grep -v "denygrid_mikrotik.py" | crontab - ) 2>/dev/null || true
    rm -f "$INSTALL_DIR"/denygrid_mikrotik.py "$INSTALL_DIR"/config.example.json \
          "$INSTALL_DIR"/requirements.txt "$STATE"
    ok "Service et fichiers retirés (config conservée : $CONFIG)."
    exit 0
fi

# --------------------------------------------------------------------------- #
#  Ajout de routeur(s) à une installation existante
# --------------------------------------------------------------------------- #
if [ "$ADD_ROUTER" -eq 1 ]; then
    c "== Ajout de routeur(s) (mode $MODE) =="
    [ -f "$CONFIG" ] || { err "config introuvable : $CONFIG — lancez d'abord l'installation."; exit 1; }
    prompt_router "$CONFIG"
    while true; do
        read -rp "  Ajouter un autre routeur ? [o/N] : " ANS || true
        case "${ANS:-}" in [oOyY]*) prompt_router "$CONFIG" ;; *) break ;; esac
    done
    chmod 600 "$CONFIG"
    [ "$MODE" = "root" ] && chown "$SVC_USER:$SVC_USER" "$CONFIG" 2>/dev/null || true
    if $SCTL restart "$SVC_NAME" 2>/dev/null; then ok "service redémarré"
    else warn "redémarrez le service : $SCTL restart $SVC_NAME"; fi
    NB=$(python3 -c "import json;print(len(json.load(open('$CONFIG'))['routers']))" 2>/dev/null || echo '?')
    ok "Terminé — $NB routeur(s) configuré(s)."
    exit 0
fi

c "== Installeur DenyGrid ↔ MikroTik connector — mode $MODE =="
[ -n "$PYTHON" ] || { err "python3 introuvable. Installez-le (apt install python3)."; exit 1; }
mkdir -p "$INSTALL_DIR"

# Utilisateur système dédié (mode root uniquement)
if [ "$MODE" = "root" ]; then
    NOLOGIN="$(command -v nologin || echo /usr/sbin/nologin)"
    if id "$SVC_USER" >/dev/null 2>&1; then
        ok "utilisateur système '$SVC_USER' présent"
    elif useradd --system --home-dir "$INSTALL_DIR" --shell "$NOLOGIN" "$SVC_USER" 2>/tmp/dg_useradd.err; then
        ok "utilisateur système '$SVC_USER' créé"
    else
        warn "impossible de créer '$SVC_USER' ($(head -1 /tmp/dg_useradd.err 2>/dev/null)) — le service tournera en root"
        SVC_USER="root"
    fi
    rm -f /tmp/dg_useradd.err
fi

# --------------------------------------------------------------------------- #
#  1. Dépendance 'requests'
# --------------------------------------------------------------------------- #
c "1/5 Dépendances Python (requests + librouteros)…"
if python3 -c "import requests, librouteros" 2>/dev/null; then
    ok "déjà présentes (système)"
else
    # librouteros n'est pas packagé en apt → venv (uniforme root/user, évite PEP 668).
    if [ "$MODE" = "root" ]; then
        export DEBIAN_FRONTEND=noninteractive
        apt-get update -qq >/dev/null 2>&1 || true
        apt-get install -y python3-venv python3-pip >/dev/null 2>&1 || true
    fi
    if python3 -m venv "$INSTALL_DIR/venv" 2>/dev/null; then
        "$INSTALL_DIR/venv/bin/pip" install -q --upgrade pip >/dev/null 2>&1 || true
        "$INSTALL_DIR/venv/bin/pip" install -q requests librouteros
        PYTHON="$INSTALL_DIR/venv/bin/python3"
        ok "installées dans un venv ($INSTALL_DIR/venv)"
    elif python3 -m pip install --user requests librouteros >/dev/null 2>&1 \
      || python3 -m pip install --user --break-system-packages requests librouteros >/dev/null 2>&1; then
        ok "installées via pip --user"
    else
        err "Impossible d'installer requests+librouteros."
        echo "  Demandez à un admin :  apt install python3-venv"
        exit 1
    fi
fi

# --------------------------------------------------------------------------- #
#  2. Fichiers
# --------------------------------------------------------------------------- #
c "2/5 Récupération des fichiers dans $INSTALL_DIR…"
fetch denygrid_mikrotik.py 0755
fetch config.example.json  0644
dl "$DG_BASE/requirements.txt" "$INSTALL_DIR/requirements.txt" 2>/dev/null || true
CONN_VER=$("$PYTHON" -c "import re,sys;print(re.search(r'VERSION\s*=\s*\"([^\"]+)\"',open('$INSTALL_DIR/denygrid_mikrotik.py').read()).group(1))" 2>/dev/null || echo '?')
ok "fichiers en place (connecteur v$CONN_VER)"

# --------------------------------------------------------------------------- #
#  3. Configuration
# --------------------------------------------------------------------------- #
c "3/5 Configuration…"
API_URL="$(default_api_url)"     # https://denygrid.com/api (dérivé du domaine)
if [ -f "$CONFIG" ]; then
    ok "config.json existant conservé"
elif [ "$NO_CONFIG" -eq 1 ] || [ ! -t 0 ]; then
    # Non-interactif (curl | bash) : URL par défaut + clé DG_KEY, routeurs à ajouter après.
    write_base_config "$CONFIG" "${DG_URL:-$API_URL}" "${DG_KEY:-}"
    warn "config.json généré (URL=${DG_URL:-$API_URL})."
    warn "Ajoutez votre premier routeur : ./install.sh --add-router"
else
    # Interactif : URL par défaut (pas de question), on demande la clé, puis le 1er routeur.
    # Si DG_KEY est fournie dans l'environnement (commande copiée depuis la page
    # Profil DenyGrid, qui la pré-remplit), on ne la redemande pas.
    echo "  API DenyGrid : $API_URL"
    if [ -n "${DG_KEY:-}" ]; then
        DG_KEY_IN="$DG_KEY"
        ok "Clé d'enrôlement fournie via DG_KEY"
    else
        read -rp "  Clé d'enrôlement / API (page Profil DenyGrid) : " DG_KEY_IN || true
    fi
    write_base_config "$CONFIG" "$API_URL" "${DG_KEY_IN:-}"
    echo "  → Ajout de votre premier routeur :"
    prompt_router "$CONFIG"
    while true; do
        read -rp "  Ajouter un autre routeur ? [o/N] : " ANS || true
        case "${ANS:-}" in [oOyY]*) prompt_router "$CONFIG" ;; *) break ;; esac
    done
    ok "config.json généré"
fi
chmod 600 "$CONFIG"
[ "$MODE" = "root" ] && chown -R "$SVC_USER:$SVC_USER" "$INSTALL_DIR"
python3 -c "import json; json.load(open('$CONFIG'))" 2>/dev/null || { err "config.json invalide (JSON)."; exit 1; }

# --------------------------------------------------------------------------- #
#  4. Service (systemd système, systemd --user, ou repli cron)
# --------------------------------------------------------------------------- #
c "4/5 Service…"
UNIT="$UNIT_DIR/${SVC_NAME}.service"
mkdir -p "$UNIT_DIR"

if [ "$MODE" = "root" ]; then
    cat > "$UNIT" <<EOF
[Unit]
Description=DenyGrid ↔ MikroTik RouterOS connector
After=network-online.target
Wants=network-online.target

[Service]
Type=simple
User=$SVC_USER
Group=$SVC_USER
WorkingDirectory=$INSTALL_DIR
Environment=DENYGRID_MIKROTIK_CONFIG=$CONFIG
Environment=DENYGRID_MIKROTIK_STATE=$STATE
ExecStart=$PYTHON $INSTALL_DIR/denygrid_mikrotik.py
Restart=always
RestartSec=10
NoNewPrivileges=true
PrivateTmp=true
ProtectSystem=strict
ProtectHome=true
ReadWritePaths=$INSTALL_DIR

[Install]
WantedBy=multi-user.target
EOF
else
    cat > "$UNIT" <<EOF
[Unit]
Description=DenyGrid ↔ MikroTik RouterOS connector (user)
After=network-online.target

[Service]
Type=simple
WorkingDirectory=$INSTALL_DIR
Environment=DENYGRID_MIKROTIK_CONFIG=$CONFIG
Environment=DENYGRID_MIKROTIK_STATE=$STATE
ExecStart=$PYTHON $INSTALL_DIR/denygrid_mikrotik.py
Restart=always
RestartSec=10

[Install]
WantedBy=default.target
EOF
fi

SERVICE_OK=0
if $SCTL daemon-reload 2>/dev/null; then
    $SCTL enable "$SVC_NAME" >/dev/null 2>&1 || true
    SERVICE_OK=1
    ok "unit systemd installée ($UNIT)"
    if [ "$MODE" = "user" ]; then
        # Permet au service de tourner même sans session ouverte
        loginctl enable-linger "$SVC_USER" 2>/dev/null && ok "linger activé (tourne sans login)" \
            || warn "linger non activé (le service s'arrêtera à la déconnexion — voir repli cron ci-dessous)"
    fi
else
    warn "systemd indisponible → repli via cron @reboot"
    rm -f "$UNIT"
    LAUNCH="DENYGRID_MIKROTIK_CONFIG=$CONFIG DENYGRID_MIKROTIK_STATE=$STATE $PYTHON $INSTALL_DIR/denygrid_mikrotik.py >> $INSTALL_DIR/run.log 2>&1"
    ( crontab -l 2>/dev/null | grep -v "denygrid_mikrotik.py"; echo "@reboot $LAUNCH" ) | crontab - \
        && ok "entrée cron @reboot ajoutée" || warn "cron indisponible aussi — lancement manuel requis"
fi

# --------------------------------------------------------------------------- #
#  5. Démarrage (si config prête)
# --------------------------------------------------------------------------- #
c "5/5 Démarrage…"
READY="$(python3 - "$CONFIG" <<'PY'
import json,sys
c=json.load(open(sys.argv[1]))
print("yes" if (c.get("enrollment_key","").strip() and c.get("routers")) else "no")
PY
)"
if [ "$READY" != "yes" ]; then
    warn "Config incomplète (clé + ≥1 routeur) → service NON démarré. Éditez $CONFIG puis relancez le service."
elif [ "$SERVICE_OK" -eq 1 ]; then
    $SCTL restart "$SVC_NAME" 2>/dev/null || true
    sleep 1
    if $SCTL is-active --quiet "$SVC_NAME" 2>/dev/null; then ok "service démarré"
    else err "le service n'a pas démarré — voir: ${SCTL} status $SVC_NAME / journalctl"; fi
else
    # repli : lancer maintenant en tâche de fond
    nohup env DENYGRID_MIKROTIK_CONFIG="$CONFIG" DENYGRID_MIKROTIK_STATE="$STATE" \
        "$PYTHON" "$INSTALL_DIR/denygrid_mikrotik.py" >> "$INSTALL_DIR/run.log" 2>&1 &
    ok "lancé en tâche de fond (log: $INSTALL_DIR/run.log)"
fi

echo
c "== Terminé (mode $MODE) =="
echo "  Dossier : $INSTALL_DIR"
echo "  Config  : $CONFIG"
if [ "$SERVICE_OK" -eq 1 ]; then
    echo "  Logs    : $( [ "$MODE" = user ] && echo 'journalctl --user -u '"$SVC_NAME"' -f' || echo 'journalctl -u '"$SVC_NAME"' -f' )"
    echo "  Statut  : $SCTL status $SVC_NAME"
else
    echo "  Logs    : tail -f $INSTALL_DIR/run.log"
fi
echo "  Config routeur (user dédié + règle de ban) : voir README.md §2"
