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

trap 'printf "Erreur: echec de la commande [%s] a la ligne %s.\n" "$BASH_COMMAND" "$LINENO" >&2' ERR

usage() {
  cat <<'EOF'
Usage:
  ./scripts/update-proxmox-lxc.sh \
    --proxmox-host 192.168.1.10 \
    --proxmox-user root@pam \
    --proxmox-password 'motdepasse' \
    --ctid 120

  ./scripts/update-proxmox-lxc.sh --local --ctid 120

Options principales:
  --proxmox-host        IP ou nom DNS du serveur Proxmox
  --proxmox-user        Utilisateur SSH Proxmox (defaut: root@pam)
  --proxmox-password    Mot de passe SSH Proxmox
  --ssh-port            Port SSH Proxmox (defaut: 22)
  --local               Execute directement sur l'hote Proxmox local
  --ctid                CTID du LXC a mettre a jour
  --hostname            Nom du LXC si le CTID n'est pas fourni (defaut: chesscubing-web)
  --branch              Branche Git a deployer (defaut: main)
  --ethan-repo-url      Depot Git de l'application Ethan
  --ethan-branch        Branche Git de l'application Ethan (defaut: main)
  --brice-repo-url      Depot Git de l'application Brice
  --brice-branch        Branche Git de l'application Brice (defaut: main)
  -h, --help            Affiche cette aide
EOF
}

die() {
  printf 'Erreur: %s\n' "$*" >&2
  exit 1
}

need_cmd() {
  command -v "$1" >/dev/null 2>&1 || die "La commande '$1' est requise."
}

PROXMOX_HOST=""
PROXMOX_USER="root@pam"
PROXMOX_PASSWORD="${PROXMOX_PASSWORD:-}"
PROXMOX_PORT="22"
LOCAL_MODE="0"

CTID=""
LXC_HOSTNAME="chesscubing-web"
REPO_BRANCH="main"
ETHAN_REPO_URL="https://git.jeannerot.fr/Mineloulou/Chesscubing.git"
ETHAN_REPO_BRANCH="main"
BRICE_REPO_URL="https://git.jeannerot.fr/Lescratcheur/ChessCubing.git"
BRICE_REPO_BRANCH="main"

while [[ $# -gt 0 ]]; do
  case "$1" in
    --proxmox-host)
      PROXMOX_HOST="${2:-}"
      shift 2
      ;;
    --proxmox-user)
      PROXMOX_USER="${2:-}"
      shift 2
      ;;
    --proxmox-password)
      PROXMOX_PASSWORD="${2:-}"
      shift 2
      ;;
    --ssh-port)
      PROXMOX_PORT="${2:-}"
      shift 2
      ;;
    --local)
      LOCAL_MODE="1"
      shift
      ;;
    --ctid)
      CTID="${2:-}"
      shift 2
      ;;
    --hostname)
      LXC_HOSTNAME="${2:-}"
      shift 2
      ;;
    --branch)
      REPO_BRANCH="${2:-}"
      shift 2
      ;;
    --ethan-repo-url)
      ETHAN_REPO_URL="${2:-}"
      shift 2
      ;;
    --ethan-branch)
      ETHAN_REPO_BRANCH="${2:-}"
      shift 2
      ;;
    --brice-repo-url)
      BRICE_REPO_URL="${2:-}"
      shift 2
      ;;
    --brice-branch)
      BRICE_REPO_BRANCH="${2:-}"
      shift 2
      ;;
    -h | --help)
      usage
      exit 0
      ;;
    *)
      die "Option inconnue: $1"
      ;;
  esac
done

if [[ "$LOCAL_MODE" != "1" && -z "$PROXMOX_HOST" ]]; then
  if command -v pct >/dev/null 2>&1 && command -v pveam >/dev/null 2>&1; then
    LOCAL_MODE="1"
  fi
fi

payload_script="$(mktemp)"
cleanup() {
  rm -f "$payload_script"
}
trap cleanup EXIT

cat >"$payload_script" <<'REMOTE'
set -Eeuo pipefail

trap 'printf "Erreur: echec de la commande [%s] a la ligne %s.\n" "$BASH_COMMAND" "$LINENO" >&2' ERR

ctid="$1"
lxc_hostname="$2"
repo_branch="$3"
ethan_repo_url="$4"
ethan_repo_branch="$5"
brice_repo_url="$6"
brice_repo_branch="$7"

die() {
  printf 'Erreur: %s\n' "$*" >&2
  exit 1
}

find_ctid_by_hostname() {
  local wanted="$1"
  local candidate=""
  local candidate_hostname=""

  while read -r candidate; do
    [[ -n "$candidate" ]] || continue
    candidate_hostname="$(pct config "$candidate" 2>/dev/null | awk -F ': ' '/^hostname:/ { print $2; exit }')"
    if [[ "$candidate_hostname" == "$wanted" ]]; then
      printf '%s\n' "$candidate"
      return 0
    fi
  done < <(pct list | awk 'NR > 1 { print $1 }')

  return 1
}

command -v pct >/dev/null 2>&1 || die "La commande 'pct' est absente sur Proxmox."

if [[ -z "$ctid" ]]; then
  ctid="$(find_ctid_by_hostname "$lxc_hostname" || true)"
fi

[[ -n "$ctid" ]] || die "Impossible de retrouver le LXC. Passe --ctid ou --hostname."

if ! pct status "$ctid" >/dev/null 2>&1; then
  die "Le conteneur $ctid est introuvable."
fi

detected_hostname="$(pct config "$ctid" 2>/dev/null | awk -F ': ' '/^hostname:/ { print $2; exit }')"
if [[ -n "$detected_hostname" ]]; then
  lxc_hostname="$detected_hostname"
fi

if ! pct status "$ctid" | grep -q "running"; then
  pct start "$ctid"
  sleep 5
fi

ct_exec() {
  pct exec "$ctid" -- bash -lc "$1"
}

ct_exec "cat > /usr/local/bin/update-chesscubing <<'SCRIPT'
#!/usr/bin/env bash
set -Eeuo pipefail

trap 'printf \"Erreur: echec de la commande [%s] a la ligne %s.\\n\" \"\$BASH_COMMAND\" \"\$LINENO\" >&2' ERR

main_repo_dir='/opt/chesscubing/repo'
ethan_repo_dir='/opt/chesscubing/ethan-repo'
brice_repo_dir='/opt/chesscubing/brice-repo'
publish_root='/opt/chesscubing/publish'
web_root='/var/www/chesscubing/current'
main_branch=\"\${1:-${repo_branch}}\"
ethan_repo_url='${ethan_repo_url}'
ethan_branch='${ethan_repo_branch}'
brice_repo_url='${brice_repo_url}'
brice_branch='${brice_repo_branch}'

ensure_dotnet_sdk() {
  if command -v dotnet >/dev/null 2>&1; then
    return 0
  fi

  apt-get update
  apt-get install -y ca-certificates curl gpg

  if [[ ! -f /etc/apt/sources.list.d/microsoft-prod.list ]]; then
    curl -fsSL https://packages.microsoft.com/config/debian/12/packages-microsoft-prod.deb -o /tmp/packages-microsoft-prod.deb
    dpkg -i /tmp/packages-microsoft-prod.deb
    rm -f /tmp/packages-microsoft-prod.deb
  fi

  apt-get update
  apt-get install -y dotnet-sdk-10.0
}

sync_git_repo() {
  local repo_dir=\"\$1\"
  local repo_url=\"\$2\"
  local branch=\"\$3\"
  local label=\"\$4\"

  if [[ -d \"\$repo_dir/.git\" ]]; then
    cd \"\$repo_dir\"

    if ! git diff --quiet || ! git diff --cached --quiet; then
      echo \"Le depot \${label} contient des modifications locales. Mise a jour annulee.\" >&2
      exit 1
    fi

    git fetch origin \"\$branch\"
    if git show-ref --verify --quiet \"refs/heads/\$branch\"; then
      git checkout \"\$branch\"
    else
      git checkout -b \"\$branch\" --track \"origin/\$branch\"
    fi
    git pull --ff-only origin \"\$branch\"
    return 0
  fi

  [[ -n \"\$repo_url\" ]] || {
    echo \"Le depot \${label} est absent et aucune URL n'a ete fournie.\" >&2
    exit 1
  }

  rm -rf \"\$repo_dir\"
  git clone --branch \"\$branch\" --single-branch \"\$repo_url\" \"\$repo_dir\"
}

publish_blazor_app() {
  local repo_dir=\"\$1\"
  local output_dir=\"\$2\"

  ensure_dotnet_sdk
  rm -rf \"\$output_dir\"
  dotnet publish \"\$repo_dir/ChessCubing.App/ChessCubing.App.csproj\" -c Release -o \"\$output_dir\"
}

publish_static_tree() {
  local source_dir=\"\$1\"
  local destination_dir=\"\$2\"

  install -d -m 0755 \"\$destination_dir\"

  rsync -a --delete \
    --include='*/' \
    --include='*.html' \
    --include='*.css' \
    --include='*.js' \
    --include='*.mjs' \
    --include='*.png' \
    --include='*.jpg' \
    --include='*.jpeg' \
    --include='*.svg' \
    --include='*.webp' \
    --include='*.ico' \
    --include='*.pdf' \
    --include='*.json' \
    --include='*.webmanifest' \
    --exclude='*' \
    \"\$source_dir/\" \"\$destination_dir/\"
}

ensure_browser_stub() {
  local destination_dir=\"\$1\"
  local stub_path=\"\$destination_dir/cordova.js\"

  if [[ ! -f \"\$stub_path\" ]]; then
    printf '%s\n' '// Browser stub for Cordova builds.' > \"\$stub_path\"
  fi
}

sync_git_repo \"\$main_repo_dir\" '' \"\$main_branch\" 'principal'
sync_git_repo \"\$ethan_repo_dir\" \"\$ethan_repo_url\" \"\$ethan_branch\" 'Ethan'
sync_git_repo \"\$brice_repo_dir\" \"\$brice_repo_url\" \"\$brice_branch\" 'Brice'

install -d -m 0755 \"\$web_root\" \"\$publish_root\"

publish_blazor_app \"\$main_repo_dir\" \"\$publish_root/main\"
rsync -a --delete \"\$publish_root/main/wwwroot/\" \"\$web_root/\"
publish_static_tree \"\$ethan_repo_dir\" \"\$web_root/ethan\"
publish_static_tree \"\$brice_repo_dir/www\" \"\$web_root/brice\"
ensure_browser_stub \"\$web_root/brice\"

chown -R www-data:www-data \"\$web_root\"

nginx -t
systemctl reload nginx
SCRIPT
chmod +x /usr/local/bin/update-chesscubing"

ct_exec "cat > /etc/nginx/sites-available/chesscubing.conf <<'NGINX'
server {
  listen 80;
  listen [::]:80;
  server_name _;

  root /var/www/chesscubing/current;
  index index.html;

  location = /ethan {
    return 301 \$scheme://\$http_host/ethan/;
  }

  location /ethan/ {
    try_files \$uri \$uri/ /ethan/index.html;
  }

  location = /brice {
    return 301 \$scheme://\$http_host/brice/;
  }

  location /brice/ {
    try_files \$uri \$uri/ /brice/index.html;
  }

  location / {
    try_files \$uri \$uri/ /index.html;
  }

  location ~* \.(?:css|js|json|mjs|png|jpg|jpeg|svg|webp|ico|pdf|webmanifest)$ {
    expires -1;
    add_header Cache-Control 'no-cache, no-store, must-revalidate';
  }
}
NGINX
rm -f /etc/nginx/sites-enabled/default
ln -sf /etc/nginx/sites-available/chesscubing.conf /etc/nginx/sites-enabled/chesscubing.conf"

pct exec "$ctid" -- /usr/local/bin/update-chesscubing "$repo_branch"

container_ip="$(pct exec "$ctid" -- bash -lc "hostname -I | awk '{print \$1}'" 2>/dev/null | tr -d '\r' || true)"

cat <<EOF

Mise a jour terminee.
- CTID: $ctid
- Nom du LXC: $lxc_hostname
- URL probable: http://${container_ip:-<ip_du_lxc>}
EOF
REMOTE

if [[ "$LOCAL_MODE" == "1" ]]; then
  printf 'Mise a jour du LXC ChessCubing en local sur cet hote Proxmox...\n'
  bash "$payload_script" \
    "$CTID" \
    "$LXC_HOSTNAME" \
    "$REPO_BRANCH" \
    "$ETHAN_REPO_URL" \
    "$ETHAN_REPO_BRANCH" \
    "$BRICE_REPO_URL" \
    "$BRICE_REPO_BRANCH"
  exit 0
fi

[[ -n "$PROXMOX_HOST" ]] || die "Merci de fournir --proxmox-host."
[[ -n "$PROXMOX_USER" ]] || die "Merci de fournir --proxmox-user."

if [[ -z "$PROXMOX_PASSWORD" ]]; then
  read -rsp "Mot de passe SSH pour ${PROXMOX_USER}@${PROXMOX_HOST}: " PROXMOX_PASSWORD
  echo
fi

need_cmd ssh
need_cmd sshpass

printf 'Mise a jour du LXC ChessCubing sur %s...\n' "$PROXMOX_HOST"

sshpass -p "$PROXMOX_PASSWORD" \
  ssh \
  -p "$PROXMOX_PORT" \
  -o StrictHostKeyChecking=accept-new \
  -o PreferredAuthentications=password \
  -o PubkeyAuthentication=no \
  "$PROXMOX_USER@$PROXMOX_HOST" \
  bash -s -- \
  "$CTID" \
  "$LXC_HOSTNAME" \
  "$REPO_BRANCH" \
  "$ETHAN_REPO_URL" \
  "$ETHAN_REPO_BRANCH" \
  "$BRICE_REPO_URL" \
  "$BRICE_REPO_BRANCH" < "$payload_script"
