#!/usr/bin/env bash
set -euo pipefail

# ===== Config produit =====
VPS_PROVISION_URL="https://provision.remialessandri.com/api/v1/provision"
WG_INTERFACE="wg0"
WG_CONF_DIR="/etc/wireguard"
WG_CONF_FILE="${WG_CONF_DIR}/${WG_INTERFACE}.conf"

ENV_FILE="/opt/hub/state/env/core.env"
COMPOSE_DIR="/opt/hub/core/compose/core"
COMPOSE_FILE="${COMPOSE_DIR}/docker-compose.yml"

KEY_DIR="/opt/hub/state/wireguard"
PRIVATE_KEY_FILE="${KEY_DIR}/client.key"
PUBLIC_KEY_FILE="${KEY_DIR}/client.pub"

# ===== Helpers UI =====
red()    { echo -e "\033[0;31m$*\033[0m"; }
green()  { echo -e "\033[0;32m$*\033[0m"; }
yellow() { echo -e "\033[1;33m$*\033[0m"; }

need_root() {
  if [ "${EUID:-$(id -u)}" -ne 0 ]; then
    red "[ERREUR] Ce script doit être lancé en root (sudo)."
    exit 1
  fi
}

need_cmd() {
  command -v "$1" >/dev/null 2>&1
}

soft_install_deps() {
  local missing=()
  for c in wg curl jq systemctl docker ip grep awk sed tee; do
    need_cmd "$c" || missing+=("$c")
  done

  if [ "${#missing[@]}" -eq 0 ]; then
    return 0
  fi

  yellow "-> Dépendances manquantes détectées: ${missing[*]}"
  yellow "-> Tentative d'installation (soft). Si ça échoue, lancez d'abord install.sh."

  export DEBIAN_FRONTEND=noninteractive
  apt-get update -qq >/dev/null 2>&1 || true
  apt-get install -y -qq \
    wireguard wireguard-tools curl jq docker.io docker-compose-plugin \
    iproute2 grep gawk sed coreutils >/dev/null 2>&1 || true

  for c in wg curl jq systemctl docker ip grep awk sed tee; do
    if ! need_cmd "$c"; then
      red "[ERREUR] Commande toujours manquante après tentative d'installation: $c"
      red "        -> Lancez d'abord votre install.sh (socle Core), puis relancez wg_provision.sh."
      exit 1
    fi
  done
}

upsert_env() {
  local key="$1"
  local value="$2"

  if [ ! -f "$ENV_FILE" ]; then
    red "[ERREUR] Fichier core.env introuvable: $ENV_FILE"
    exit 1
  fi

  if grep -qE "^${key}=" "$ENV_FILE"; then
    sed -i "s|^${key}=.*|${key}=${value}|" "$ENV_FILE"
  else
    echo "${key}=${value}" >> "$ENV_FILE"
  fi
}

wait_for_wg_handshake() {
  local i
  for i in {1..15}; do
    if wg show "$WG_INTERFACE" 2>/dev/null | grep -q "latest handshake:"; then
      return 0
    fi
    sleep 1
  done
  return 1
}

# ===== Main =====
need_root

TOKEN="${1:-}"
if [ -z "$TOKEN" ]; then
  red "[ERREUR] Usage: sudo $0 <TOKEN_ONE_SHOT>"
  exit 1
fi

green "== HUB: Provisioning WireGuard (ZTP) =="

if [ ! -f "$ENV_FILE" ]; then
  red "[ERREUR] Fichier core.env introuvable: $ENV_FILE"
  red "        -> Avez-vous lancé l'installateur Core ?"
  exit 1
fi

if [ ! -d "$COMPOSE_DIR" ] || [ ! -f "$COMPOSE_FILE" ]; then
  red "[ERREUR] Dossier compose introuvable ou incomplet: $COMPOSE_DIR"
  red "        -> Vérifiez que le socle Core est bien installé."
  exit 1
fi

soft_install_deps

mkdir -p "$KEY_DIR"
chmod 700 "$KEY_DIR"

if [ ! -f "$PRIVATE_KEY_FILE" ] || [ ! -f "$PUBLIC_KEY_FILE" ]; then
  green "-> Génération des clés cryptographiques WireGuard..."
  umask 077
  wg genkey | tee "$PRIVATE_KEY_FILE" | wg pubkey > "$PUBLIC_KEY_FILE"
  chown root:root "$PRIVATE_KEY_FILE" "$PUBLIC_KEY_FILE"
  chmod 600 "$PRIVATE_KEY_FILE" "$PUBLIC_KEY_FILE"
else
  yellow "-> Clés existantes détectées, réutilisation."
fi

CLIENT_PUBKEY="$(tr -d '\r' < "$PUBLIC_KEY_FILE")"
if [ -z "$CLIENT_PUBKEY" ]; then
  red "[ERREUR] Clé publique vide ou illisible: $PUBLIC_KEY_FILE"
  exit 1
fi

green "-> Appel de l'API de provisioning VPS..."
RESP="$(curl --fail --silent --show-error \
  --connect-timeout 5 --max-time 15 \
  --retry 3 --retry-delay 1 --retry-all-errors \
  -X POST "$VPS_PROVISION_URL" \
  -H "Content-Type: application/json" \
  -d "{\"token\":\"${TOKEN}\",\"client_pubkey\":\"${CLIENT_PUBKEY}\"}")"

if [ -z "$RESP" ]; then
  red "[ERREUR] Réponse vide de l'API provisioning."
  exit 1
fi

if ! echo "$RESP" | jq -e '.wg_ip and .vps_pubkey and .endpoint and .allowed_ips' >/dev/null 2>&1; then
  red "[ERREUR] Réponse API invalide (JSON ou champs manquants)."
  red "Réponse brute:"
  echo "$RESP"
  exit 1
fi

WG_IP="$(echo "$RESP" | jq -r '.wg_ip' | tr -d '\r')"
VPS_PUBKEY="$(echo "$RESP" | jq -r '.vps_pubkey' | tr -d '\r')"
ENDPOINT="$(echo "$RESP" | jq -r '.endpoint' | tr -d '\r')"
ALLOWED_IPS="$(echo "$RESP" | jq -r '.allowed_ips' | tr -d '\r')"
KEEPALIVE="$(echo "$RESP" | jq -r '.keepalive // 25' | tr -d '\r')"

if [ -z "$WG_IP" ] || [ "$WG_IP" = "null" ] || \
   [ -z "$VPS_PUBKEY" ] || [ "$VPS_PUBKEY" = "null" ] || \
   [ -z "$ENDPOINT" ] || [ "$ENDPOINT" = "null" ] || \
   [ -z "$ALLOWED_IPS" ] || [ "$ALLOWED_IPS" = "null" ]; then
  red "[ERREUR] Champs API invalides malgré JSON valide."
  red "Réponse brute:"
  echo "$RESP"
  exit 1
fi

green "-> Écriture de la configuration WireGuard: $WG_CONF_FILE"
mkdir -p "$WG_CONF_DIR"
umask 077

if [ -f "$WG_CONF_FILE" ]; then
  cp "$WG_CONF_FILE" "${WG_CONF_FILE}.bak_$(date +%Y%m%d_%H%M%S)"
fi

cat > "$WG_CONF_FILE" <<EOF
[Interface]
Address = ${WG_IP}/24
PrivateKey = $(tr -d '\r' < "$PRIVATE_KEY_FILE")

[Peer]
PublicKey = ${VPS_PUBKEY}
Endpoint = ${ENDPOINT}
AllowedIPs = ${ALLOWED_IPS}
PersistentKeepalive = ${KEEPALIVE}
EOF

chown root:root "$WG_CONF_FILE"
chmod 600 "$WG_CONF_FILE"

green "-> Démarrage/restart du tunnel..."
systemctl enable "wg-quick@${WG_INTERFACE}" >/dev/null 2>&1 || true
systemctl restart "wg-quick@${WG_INTERFACE}"

if wait_for_wg_handshake; then
  green "-> Handshake WireGuard détecté."
else
  yellow "-> Aucun handshake détecté pour l'instant. Vérification à poursuivre."
fi

upsert_env "WG_IP" "$WG_IP"

green "== Provisioning WireGuard terminé =="