#!/usr/bin/env bash
# ============================================================================
# FoxPlan on-premise — préparation du déploiement Docker Compose
# ----------------------------------------------------------------------------
# Idempotent : relançable à volonté. Ne remplace jamais un fichier existant
# (certificat, .env), sauf la configuration Traefik qu'il régénère.
#
#   ./install.sh              prépare tout selon .env
#   ./install.sh --start      prépare puis démarre la pile
# ============================================================================
set -euo pipefail
cd "$(dirname "$0")"

say()  { printf '\033[1;34m==>\033[0m %s\n' "$*"; }
warn() { printf '\033[1;33m /!\\\033[0m %s\n' "$*"; }
die()  { printf '\033[1;31m ERREUR\033[0m %s\n' "$*" >&2; exit 1; }

# --- 1. Fichier .env ---------------------------------------------------------
if [ ! -f .env ]; then
  [ -f env.example ] || die "ni .env ni env.example — téléchargez env.example."
  cp env.example .env
  say ".env créé depuis env.example — renseignez DOMAIN et FOXPLAN_REGISTRY, puis relancez."
  exit 0
fi

set -a; . ./.env; set +a

: "${DOMAIN:?DOMAIN doit être renseigné dans .env}"
: "${FOXPLAN_REGISTRY:?FOXPLAN_REGISTRY doit être renseigné dans .env (fourni avec votre souscription)}"
TLS_MODE="${TLS_MODE:-selfsigned}"

mkdir -p traefik/dynamic traefik/certs traefik/acme traefik/ca

# --- 2. Certificat par défaut ------------------------------------------------
# Toujours présent : c'est lui que Traefik sert tant qu'aucun autre certificat
# ne s'applique — y compris si ACME échoue. Le site répond donc en HTTPS dès le
# premier démarrage, sans attendre quoi que ce soit.
if [ -f traefik/certs/tls.crt ] && [ -f traefik/certs/tls.key ]; then
  say "Certificat existant conservé : traefik/certs/tls.crt"
else
  say "Génération d'un certificat auto-signé pour $DOMAIN (valable 825 jours)"
  openssl req -x509 -newkey rsa:2048 -nodes -days 825 \
    -keyout traefik/certs/tls.key -out traefik/certs/tls.crt \
    -subj "/CN=$DOMAIN" -addext "subjectAltName=DNS:$DOMAIN" 2>/dev/null
  warn "Auto-signé : les navigateurs afficheront un avertissement tant qu'il n'est"
  warn "pas remplacé (TLS_MODE=acme) ou écrasé par le vôtre (TLS_MODE=static)."
fi
chmod 600 traefik/certs/tls.key
touch traefik/acme/acme.json && chmod 600 traefik/acme/acme.json

# --- 3. Certificat par défaut, côté configuration dynamique ------------------
cat > traefik/dynamic/tls.yml <<EOF
# Généré par install.sh — ne pas éditer à la main.
# Certificat servi par défaut. Traefik relit ce répertoire À CHAUD : remplacer
# traefik/certs/tls.crt et tls.key suffit à changer de certificat, sans
# redémarrer le moindre conteneur.
tls:
  stores:
    default:
      defaultCertificate:
        certFile: /certs/tls.crt
        keyFile: /certs/tls.key
EOF

# --- 4. Configuration statique Traefik selon le mode TLS ---------------------
{
  cat <<EOF
# Généré par install.sh (TLS_MODE=$TLS_MODE) — ne pas éditer à la main.
providers:
  docker:
    exposedByDefault: false
    network: foxplan-network
  file:
    directory: /etc/traefik/dynamic
    watch: true

entryPoints:
  web:
    address: ":80"
    http:
      redirections:
        entryPoint:
          to: websecure
          scheme: https
  websecure:
    address: ":443"
EOF

  case "$TLS_MODE" in
    acme)
      : "${ACME_EMAIL:?ACME_EMAIL doit être renseigné dans .env pour TLS_MODE=acme}"
      : "${ACME_CA_SERVER:?ACME_CA_SERVER doit être renseigné dans .env pour TLS_MODE=acme}"
      cat <<EOF
    http:
      tls:
        certResolver: fox

certificatesResolvers:
  fox:
    acme:
      email: "$ACME_EMAIL"
      storage: /acme/acme.json
      caServer: "$ACME_CA_SERVER"
      httpChallenge:
        entryPoint: web
EOF
      ;;
    selfsigned|static) : ;;
    *) die "TLS_MODE inconnu : '$TLS_MODE' (attendu : selfsigned, acme ou static)" ;;
  esac
} > traefik/traefik.yml

case "$TLS_MODE" in
  acme)
    say "Mode TLS : ACME — autorité $ACME_CA_SERVER"
    if [ -n "${LEGO_CA_CERTIFICATES:-}" ] && [ ! -f "traefik/ca/$(basename "$LEGO_CA_CERTIFICATES")" ]; then
      warn "LEGO_CA_CERTIFICATES pointe sur $LEGO_CA_CERTIFICATES, absent de traefik/ca/."
      warn "Déposez-y la chaîne de votre AC privée, sinon la négociation ACME échouera."
    fi
    say "En cas d'échec, le certificat par défaut reste servi : le site ne tombe pas."
    ;;
  static)
    say "Mode TLS : certificat statique — remplacez traefik/certs/tls.{crt,key} par les vôtres."
    warn "tls.crt doit contenir la chaîne COMPLÈTE : certificat serveur puis intermédiaires."
    ;;
  selfsigned)
    say "Mode TLS : auto-signé (évaluation). Passez à 'acme' ou 'static' pour la production."
    ;;
esac

say "Configuration prête. Étapes suivantes :"
echo "    docker login \"$FOXPLAN_REGISTRY\""
echo "    docker compose up -d"

if [ "${1:-}" = "--start" ]; then
  say "Démarrage de la pile"
  docker compose up -d
fi
